Проектирование АИС. С аратовский госуниверситет м еханико математический факультет проектирование информационных систем Составил
Скачать 3.17 Mb.
|
code — код сотрудника, это необходимо при одинаковых “ФИО” сотрудников или, например, при изменении фамилии сотрудника; family — фамилия; name — имя; patronym — отчество. Операции класса это: __init__ — конструктор класса, в данном случае он необходим поскольку его атрибуты нужно инициализировать; __hash__ — определение этой функции позволяет использовать объект класса в качестве элемента словарей и множеств; __eq__ — поскольку хэш представляет отображение элементов некоторого множества в конечное множество чисел, обычно это числа умещающиеся в машинное слово, то необходимо разрешать так называемые коллизии. В случае коллизии два разных объекта имеют одинаковое значение функции __hash__ и __eq__ позволяет различить эти объекты. Подразделения представлены классом Subdivision, который имеет следующие атрибуты: name — название подразделения; collaborators — множество его сотрудников; subdivisions — множество его собственных подразделений. Операции класса это также состоят из конструктора, операций __hash__ и __eq__ поскольку под- разделение может быть в качестве элемента множества subdivisions, а также других операций: __iter__ — итератор для просмотра всех сотрудников подразделения, включая и сотрудников его собственных подразделений; add — для добавления сотрудника к подразделению; addSubdivision — для добавления к подразделению другого подразделения в качестве его собствен- ного подразделения; iterSubdivision — итератор для просмотра его собственных подразделений. Оставшиеся элементы диаграммы классов могут быть описаны кратко. TelephoneType определяется своим названием. TelephoneTypes представляет собой множество из объектов класса TelephoneType. Класс Telephone состоит из номера и его типа. Телефоны содержаться в множестве задаваемым классом Telephones. Телефонный справочник содержит TelephoneRecord ссылающийся на телефоны и подразделения. Рассмотрим реализацию телефонного справочника . Для усвоения использованного ниже мате- риала необходимо усвоить 1-4 лекции курса “Учебный курс - Язык программирования Python” [ 10 ] Сузи Романа Арвиевича. 1 # -*- coding: utf-8 -*- 2 3 """ 4 Телефонная книга организации 5 """ 6 7 import itertools 8 9 class Collaborator: 10 """ 11 Сотрудник 12 """ 13 def __init__ (self, code, family, name, patronym): 14 self.code = code 15 self.family = family 16 self.name = name 17 self.patronym = patronym 18 19 def __str__ (self): 20 return "%s %.2s. %.2s." % (self.family, self.name, self.patronym) 21 22 def __hash__ (self): 23 return hash (self.code) 24 25 def __eq__ (self, other): 26 return self.code == other.code Строка 1 определяет используемую кодировку. Затем, нам строках 3-5, определяем документацию нашей программы. На 7 строке импортируем модуль itertools для организации итераторов для обхода подразделения по его сотрудникам и по его собственным подразделениям. Далее следует описание класса Collaborator. При вычисление хэш используется стандартная hash функция языка Python. 28 class Subdivision: 29 """ 30 Подразделение 31 """ 32 def __init__ (self, name): 33 self.name = name 34 self.collaborators = set () 35 self.subdivisions = set () 36 37 def __hash__ (self): 38 return hash (self.name) 39 40 def __eq__ (self, other): 41 return self.name == other.name 42 43 def __iter__ (self): 44 i = iter (self.collaborators) 45 for s in self.subdivisions: 46 i = itertools. chain (i, iter (s)) 47 return i 48 49 def add (self, collaborator): 50 assert collaborator not in self 51 self.collaborators. add (collaborator) 52 53 def addSubdivision (self, subdivision): 54 assert subdivision not in self.subdivisions 55 assert not set (self). intersection ( set (subdivision)) 56 self.subdivisions. add (subdivision) 57 58 def iterSubdivision (self): 59 i = iter (self.subdivisions) 60 for s in self.subdivisions: 61 i = itertools. chain (i, s. iterSubdivision ()) 62 return i В Subdivision для организации итераторов __iter__ и iterSubdivision используется так называемое за- цепление итераторов. Операция add на строчке 50 запрещает добавлять сотрудника к подразделению если он есть в нем или в его собственном подразделении. Это достигается за счет переопределе- ния стандартного метода __iter__ для контейнера языка Python. Строчка 54 запрещает добавлять подразделение если там оно уже есть, а строчка 55 если в нем есть хотя бы один сотрудник уже имеющиеся в нашем подразделении. 64 class TelephoneType: 65 """ 66 Тип телефона 67 """ 68 def __init__ (self, name): 69 self.name = name 70 71 def __hash__ (self): 72 return hash (self.name) 73 74 def __eq__ (self, other): 75 return self.name == other.name Тип телефона определяется его именем. 77 class TelephoneTypes ( set ): 78 """ 79 Типы телефонов 80 """ 81 def add (self, telephoneType): 82 assert telephoneType not in self 83 set add (self, telephoneType) На строке 82 стоит запрет на добавление к множеству типов телефонов элемента если он там уже есть. 85 class Telephone: 86 """ 87 Телефон 88 """ 89 def __init__ (self, telephone, telephoneType): 90 self.number = telephone 91 self. type = telephoneType 92 93 def __hash__ (self): 94 return hash (self.number) 95 96 def __eq__ (self, other): 97 return self.number == other.number Телефон определяется его типом и номером. 99 class Telephones ( set ): 100 """ 101 Телефоны 102 """ 103 def __init__ (self, telephoneTypes): 104 set __init__ (self) 105 self.telephoneTypes = telephoneTypes 106 107 def add (self, telephone): 108 assert telephone not in self 109 assert telephone. type in self.telephoneTypes 110 set add (self, telephone) На строке 108 стоит запрет на добавление к множеству телефонов элемента с уже существующим номером или и на строке 109 если его типа нет в telephoneTypes. 112 class TelephoneRecord: 113 """ 114 Запись в телефонном справочнике 115 """ 116 def __init__ (self, telephone, collaborator): 117 self.telephone = telephone 118 self.collaborator = collaborator 119 120 def __hash__ (self): 121 return hash ((self.telephone, self.collaborator)) 122 123 def __eq__ (self, other): 124 return self.telephone == other.telephone and \ 125 self.collaborator == other.collaborator Запись в телефонном справочнике должна ссылаться на телефон и сотрудника. 127 class TelephoneDir ( set ): 128 """ 129 Телефонный справочник 130 """ 131 def __init__ (self, telephones, subdivision): 132 set __init__ (self) 133 self.telephones = telephones 134 self.subdivision = subdivision 135 136 def add (self, telephoneRecord): 137 assert telephoneRecord.telephone in self.telephones 138 assert telephoneRecord.collaborator in self.subdivision 139 assert telephoneRecord not in self 140 set add (self, telephoneRecord) На строке 137 стоит запрет на добавление к множеству телефона, если его нет среди телефонов справочника. Аналогично, на строке 138, запрет для подразделений. Строка 139 запрещает добавлять записи в телефонный справочник, если они уже там есть. 142 if __name__ == ’__main__’ : 143 import tdcsv 144 145 telephoneDir = tdcsv. load () 146 147 for s in telephoneDir.subdivision. iterSubdivision (): 148 if s.name == ’помощник проректора’ : 149 for r in telephoneDir: 150 if r.collaborator in s and r.collaborator.family. find ( ’ск’ ) >= 0 : 151 print r.telephone.number, "%s %s. %s." % \ 152 (r.collaborator.family, r.collaborator.name[: 2 ], r.collaborator.patronym[: 2 ]) 153 break 154 155 for s in telephoneDir.subdivision. iterSubdivision (): 156 if s.name == ’зав. кафедрой’ : 157 for r in telephoneDir: 158 if r.collaborator in s and r.collaborator.family. find ( ’сс’ ) >= 0 : 159 print r.telephone.number, "%s %s. %s." % \ 160 (r.collaborator.family, r.collaborator.name[: 2 ], r.collaborator.patronym[: 2 ]) 161 break Каждый модуль языка Python может быть использован в качестве головного, в этом случае значение переменной __name__ будет иметь значение ’__main__’ (см. строку 142). На 143 строке подключаем модуль импорта данных из формата CSV, а на 145 осуществляется сам импорт. На строчках 147–153 осуществляется поиск в подразделении помощник проректора сотрудника, фамилия которого содержит ск. На строчках 155–161 осуществляется поиск, аналогичный предыдущему, в подразделении зав. кафедрой сотрудника, фамилия которого содержит сс. Результат работы программы представлен ниже. 51-57-39 Виноградский С. Г. 51-18-84 Лосатинская А. С. В результате первый запрос вернул два телефона, а второй не одного. CSV Для усвоения материала необходимо ознакомится с 7 курса “Учебный курс - Язык программирования Python” [ 10 ] Сузи Романа Арвиевича. Для представления информации используется два файла subdivision.csv и ssu.csv со струк- турой колонок представленных на рисунке ниже. subdivision подразделение головное подразделение ssu телефон код сотр. фамилия имя отчество подразделение тип тел. Для набора можно воспользоваться любым текстовым редактором поддерживающим кодировку UTF8 или экспортом из электронных таблиц. Сначала опишем функцию load из файла tdcsv.py для загрузки данных из формата CSV. 30 def load (): 31 subdivision = {} 32 for rec in csv. reader ( open (os.path. join (os.curdir, ’subdivision.csv’ ), ’rb’ ), delimiter= ’;’ ): 33 subdivision[rec[ 0 ]] = telephonedir. Subdivision (rec[ 0 ]) 34 if rec[ 1 ]: 35 subdivision[rec[ 1 ]]. addSubdivision (subdivision[rec[ 0 ]]) 36 else: 37 telephoneDir = telephonedir. TelephoneDir (telephonedir. Telephones (telephonedir. TelephoneTypes ()), subdivision[rec[ 0 ]]) 38 39 telephones, telephoneTypes, collaborators = {}, {}, {} 40 for rec in csv. reader ( open (os.path. join (os.curdir, ’ssu.csv’ ), ’rb’ ), delimiter= ’;’ ): 41 if rec[ 6 ] not in telephoneTypes: 42 telephoneTypes[rec[ 6 ]] = telephonedir. TelephoneType (rec[ 6 ]) 43 telephoneDir.telephones.telephoneTypes. add (telephoneTypes[rec[ 6 ]]) 44 if rec[ 0 ] not in telephones: 45 telephones[rec[ 0 ]] = telephonedir. Telephone (rec[ 0 ], telephoneTypes[rec[ 6 ]]) 46 telephoneDir.telephones. add (telephones[rec[ 0 ]]) 47 key = int (rec[ 1 ]) 48 if key not in collaborators: 49 collaborators[key] = telephonedir. Collaborator (key, rec[ 2 ], rec[ 3 ], rec[ 4 ]) 50 subdivision[rec[ 5 ]]. add (collaborators[key]) 51 telephoneDir. add (telephonedir. TelephoneRecord (telephones[rec[ 0 ]], collaborators[key])) 52 53 return telephoneDir Словарь subdivision на строке 31 будем использовать для хранения объектов – подразделений, читае- мых из файла ’subdivision.csv’ . Аналогично на строке 39 организовано чтение из файла ’ssu.csv’ Окончательно функция возвращает заполненный телефонный справочник. Функция save сохраняет данные в эти же файлы. База данных Структура базы данных представлена ниже Т елефоновТ ипы кодТелефонаТип название Подразделения кодПодразделения название кодГоловногоПодраз Т елефоны кодТелефона кодТелефонаТип номер Т елефонныйСправочник кодЗаписи кодТелефона кодСотрудника Сот рудники кодСотрудника кодПодразделения фамилия имя отчество Для создания таблиц используется следующий SQL код для базы данных Postgresql из файла telephonedir.sql 1 CREATE TABLE Подразделения ( 2 кодПодразделения SERIAL PRIMARY KEY, 3 название TEXT, 4 кодГоловногоПодраз INTEGER REFERENCES Подразделения(кодПодразделения) DEFAULT NULL, 5 UNIQUE(название, кодГоловногоПодраз) 6 ); 7 8 CREATE TABLE Сотрудники ( 9 кодСотрудника INTEGER PRIMARY KEY, 10 кодПодразделения INTEGER REFERENCES Подразделения(кодПодразделения) DEFAULT NULL, 11 фамилия TEXT, 12 имя TEXT, 13 отчество TEXT 14 ); 15 16 CREATE TABLE ТелефоновТипы ( 17 кодТелефонаТип SERIAL PRIMARY KEY, 18 название TEXT, 19 UNIQUE(название) 20 ); 21 22 CREATE TABLE Телефоны ( 23 кодТелефона SERIAL PRIMARY KEY , 24 кодТелефонаТип INTEGER REFERENCES ТелефоновТипы(кодТелефонаТип), 25 номер TEXT 26 ); 27 28 CREATE TABLE ТелефонныйСправочник ( 29 кодЗаписи SERIAL PRIMARY KEY, 30 кодТелефона INTEGER REFERENCES Телефоны(кодТелефона), 31 кодСотрудника INTEGER REFERENCES Сотрудники(кодСотрудника), 32 UNIQUE(кодТелефона, кодСотрудника) 33 ); С помощью скрипта create-db написанного на языке BASH создается база данных telephonedir1 со структурой таблиц задаваемых представленным выше SQL кодом. Набор данных можно осуществить с помощью knoda – графического интерфейса пользователя для доступа к базам данных. С помощью скриптов dump можно сохранить базу данных в файле dump.tar , а с помощью restore её восстановить. Для усвоения материала необходимо ознакомится с 10 лекцией “Учебный курс - Язык программи- рования Python” [ 10 ] Сузи Романа Арвиевича. Для работы с Postgresql на строке 3 файла tddb.py подключим модуль psycopg2. На строке 7 создается соединение с базой данных, а на строке 13 закрытие этого соединения. 1 # -*- coding: utf-8 -*- 2 3 import psycopg2 as db 4 5 import telephonedir 6 7 def createConn (): 8 conn = db. connect (host= ’localhost’ , database= "telephonedir1" , user= "postgres" ) 9 db.threadsafety= 2 10 curs = conn. cursor () 11 return (db, conn, curs) 12 13 def closeConn (db, conn, curs): 14 conn. close () На строке 87 выполняется запрос в базе данных. В цикле for на строке 88 выполняется его просмотр. Заметим, что модуль psycopg2 поддерживает спецификацию DBI-2.0 и поэтому кортеж rec содержит элементы преобразованные из базы данных согласно их типам. Так например целое из базы данных перейдет в целое языка Python, анологичное преобразование будет выполнено и для чисел с плавающей точкой, строк. Значение NULL будет представленно в Python значением None. 75 def load (): 76 db, conn, curs = createConn () 77 78 sql = """ 79 SELECT 80 кодПодразделения, 81 название, 82 кодГоловногоПодраз 83 FROM 84 Подразделения""" 85 subdivisions, subdivisionOwners = {}, {} 86 try: 87 curs. execute (sql) 88 for rec in curs. fetchall (): 89 s = telephonedir. Subdivision (rec[ 1 ]) 90 subdivisions[rec[ 0 ]] = s 91 subdivisionOwners[s] = rec[ 2 ] 92 except db.DatabaseError, x: 93 print x 94 conn. rollback () 95 else: 96 conn. commit () 97 for s, i in subdivisionOwners. iteritems (): 98 if i: 99 subdivisions[i].subdivisions. add (s) 100 else: 101 subdivision = s 102 103 sql = """ 104 SELECT 105 кодСотрудника, 106 кодПодразделения, 107 фамилия, 108 имя, 109 отчество 110 FROM 111 Сотрудники""" 112 collaborators = {} 113 try: 114 curs. execute (sql) 115 for rec in curs. fetchall (): 116 c = telephonedir. Collaborator (rec[ 0 ], rec[ 2 ], rec[ 3 ], rec[ 4 ]) 117 collaborators[rec[ 0 ]] = c 118 subdivisions[rec[ 1 ]]. add (c) 119 |