diff --git a/0.6_test/__pycache__/dbtable.cpython-311.pyc b/0.6_test/__pycache__/dbtable.cpython-311.pyc index 1d2d43e..5344175 100644 Binary files a/0.6_test/__pycache__/dbtable.cpython-311.pyc and b/0.6_test/__pycache__/dbtable.cpython-311.pyc differ diff --git a/0.6_test/__pycache__/texts.cpython-311.pyc b/0.6_test/__pycache__/texts.cpython-311.pyc index 4a4f964..74baffb 100644 Binary files a/0.6_test/__pycache__/texts.cpython-311.pyc and b/0.6_test/__pycache__/texts.cpython-311.pyc differ diff --git a/0.6_test/main.py b/0.6_test/main.py index 7207ec2..a6aee03 100644 --- a/0.6_test/main.py +++ b/0.6_test/main.py @@ -1,5 +1,6 @@ import sys import texts +# import time sys.path.append('tables') from project_config import * @@ -13,7 +14,8 @@ TODO: 1) Реализовать ввод порядкового номера - done 2) Удалить проверки на "русскоязычный ввод" - done 3) Устранить SQLi с помощью санации атрибутов - done -4) UPDATE для отдельный таблиц/общий? - indev +4) UPDATE для отдельных таблиц - indev +5) Красивый вывод - done FIXME: ''' @@ -111,8 +113,18 @@ class Main: else: DishTable().delete(self.dish_arr[x-1][0]) next_step = "5" + elif next_step == "5": next_step = self.show_dish_in_cath() + + elif next_step == "8": + x = int(input(texts.text_choice_update)) + if(x==1): + self.cath_update() + elif(x==2): + self.dish_update() + return "1" + elif next_step != "0" and next_step != "9" and next_step != "3": print("Выбрано неверное число! Повторите ввод!") return "1" @@ -160,16 +172,28 @@ class Main: print("Выбрана категория: " + self.cath_obj) print("Блюда:") - print("№\tНазвание\tВремя приготовления\tКраткая инструкция\ - \n-------------------------------------------------------------------------------------") + lst = DishTable().all_by_cath_id(self.cath_id) - + self.max_len_name = 0 + self.max_index = len(lst) for i in lst: self.dish_arr.append([i[2], str(i[1]), str(i[4])]) - + self.max_len_name = max(self.max_len_name, len(i[2])) + print("№" + " "*(self.max_index + 1)+ "Название" + " "*(self.max_len_name - 4)\ + +"Время приготовления Краткая инструкция\ + \n-------------------------------------------------------------------------------------------") + # print('Катя хорошая и Дима тоже') for i in range(len(self.dish_arr)): - print(str(i+1) + "\t" + self.dish_arr[i][0] + "\t\t" + self.dish_arr[i][1] + "\t\t\t" + self.dish_arr[i][2]) - + txt = str(i+1) + " "*(2+self.max_index-len(str(i))) + txt += self.dish_arr[i][0] + " "*(4+self.max_len_name - len(self.dish_arr[i][0])) + txt += self.dish_arr[i][1] + " "*(5+19-len(self.dish_arr[i][1])) + txt += self.dish_arr[i][2] + # txt += self.dish_arr[i][0] + + # print(f"""{str(i+1):<8}{self.dish_arr[i][0]:<18}\ + # {self.dish_arr[i][1]:<15}{self.dish_arr[i][2]}""") +# print(f"""{str(i+1)}{" "*(self.max_index+2)}\ +# {self.dish_arr[i][0]}{" "*(self.max_len_name+2)}{self.dish_arr[i][1]}{" "*19}{self.dish_arr[i][2]}""") + print(txt) menu = texts.show_dish_in_cath_txt print(menu) return self.read_next_step() @@ -199,10 +223,6 @@ class Main: self.add_cath() current_menu = "1" - elif current_menu == "8": - self.update_cath() - current_menu = "1" - print("До свидания!") return diff --git a/0.6_test/tables/__pycache__/cath_table.cpython-311.pyc b/0.6_test/tables/__pycache__/cath_table.cpython-311.pyc index 377335f..273c17d 100644 Binary files a/0.6_test/tables/__pycache__/cath_table.cpython-311.pyc and b/0.6_test/tables/__pycache__/cath_table.cpython-311.pyc differ diff --git a/0.6_test/tables/__pycache__/dish_table.cpython-311.pyc b/0.6_test/tables/__pycache__/dish_table.cpython-311.pyc index 1ee25bb..5833efa 100644 Binary files a/0.6_test/tables/__pycache__/dish_table.cpython-311.pyc and b/0.6_test/tables/__pycache__/dish_table.cpython-311.pyc differ diff --git a/0.6_test/tables/cath_table.py b/0.6_test/tables/cath_table.py index 9545e22..654b94a 100644 --- a/0.6_test/tables/cath_table.py +++ b/0.6_test/tables/cath_table.py @@ -14,9 +14,6 @@ class CathTable(DbTable): return ['CONSTRAINT "Name" UNIQUE (cath_name)'] def delete(self, val): - # sql = "DELETE FROM " + self.table_name() - # sql += " WHERE cath_name" - # sql += "=" + "'" + "".join(val) + "';" param_sql = "DELETE FROM cath WHERE cath_name = %s;" cur = self.dbconn.conn.cursor() value = "".join(val) @@ -42,4 +39,21 @@ class CathTable(DbTable): self.insert_one(["Завтрак"]) self.insert_one(["Обед"]) self.insert_one(["Ужин"]) + self.insert_one(["Перекус"]) + self.insert_one(["Десерт"]) + self.insert_one(["Напиток"]) + self.insert_one(["Закуска"]) + self.insert_one(["Салат"]) + self.insert_one(["Гарнир"]) + self.insert_one(["Выпечка"]) + self.insert_one(["Супы"]) + self.insert_one(["Соусы"]) + self.insert_one(["Паста"]) + self.insert_one(["Мясные блюда"]) + self.insert_one(["Рыбные блюда"]) + self.insert_one(["Веганские блюда"]) + self.insert_one(["Блюда из птицы"]) + self.insert_one(["Морепродукты"]) + self.insert_one(["Национальная кухня"]) + self.insert_one(["Быстрые блюда"]) return \ No newline at end of file diff --git a/0.6_test/tables/dish_table.py b/0.6_test/tables/dish_table.py index f01817c..3110995 100644 --- a/0.6_test/tables/dish_table.py +++ b/0.6_test/tables/dish_table.py @@ -88,7 +88,8 @@ class DishTable(DbTable): return "1" insert = [cath_id, ins_time, ins_name, ins_manual] - DishTable().insert_one(insert) + + self.insert_one(insert) def example_insert(self): @@ -96,4 +97,35 @@ class DishTable(DbTable): self.insert_one([1, "20 minutes", "Блины", "Замесить тесто, да пожарить. ©️ Никита Сергеич"]) self.insert_one([2, "2 hours", "Хлэб", "Почти, как блины, но не совсем."]) self.insert_one([3, "40 minutes", "Паста", "Почувствуй себя итальянцем"]) + self.insert_one([1, "1 hour", "Пицца", "Раскатать тесто, добавить начинку и запечь в духовке."]) + self.insert_one([2, "30 minutes", "Салат Цезарь", "Нарезать салат, приготовить соус и обжарить куриную грудку."]) + self.insert_one([3, "45 minutes", "Лазанья", "Слои теста с соусом и начинкой, запеченные в духовке."]) + self.insert_one([4, "1 hour 15 minutes", "Жаркое", "Обжарить мясо и овощи, затем потушить в духовке."]) + self.insert_one([5, "20 minutes", "Смузи", "Смешать фрукты, ягоды, йогурт и лед в блендере."]) + self.insert_one([6, "2 hours 30 minutes", "Бефстроганов", "Обжарить говядину, приготовить соус и подать с гарниром."]) + self.insert_one([7, "1 hour", "Чили кон карне", "Обжарить мясо, добавить фасоль, помидоры и специи."]) + self.insert_one([8, "45 minutes", "Фахитас", "Обжарить мясо и овощи, подать с лепешками и соусом."]) + self.insert_one([9, "2 hours", "Пельмени", "Приготовить тесто, начинку и слепить пельмени."]) + self.insert_one([10, "1 hour 30 minutes", "Ризотто", "Обжарить рис, добавить бульон и готовить, постоянно помешивая."]) + self.insert_one([11, "50 minutes", "Тако", "Обжарить начинку, подать с лепешками и соусами."]) + self.insert_one([12, "3 hours", "Бараньи ребрышки", "Замариновать ребрышки и запечь в духовке."]) + self.insert_one([13, "1 hour 15 minutes", "Карри", "Обжарить специи, добавить овощи и курицу, потушить."]) + self.insert_one([14, "30 minutes", "Бургер", "Обжарить котлету, собрать бургер с соусами и овощами."]) + self.insert_one([15, "2 hours 45 minutes", "Утка по-пекински", "Замариновать утку, запечь и подать с лепешками и соусом."]) + self.insert_one([16, "1 hour 30 minutes", "Паэлья", "Обжарить рис с овощами, добавить бульон и морепродукты."]) + self.insert_one([17, "45 minutes", "Рататуй", "Обжарить овощи и запечь в духовке."]) + self.insert_one([18, "2 hours", "Борщ", "Обжарить овощи, добавить бульон и тушить."]) + self.insert_one([19, "1 hour 15 minutes", "Куриные наггетсы", "Замариновать куриное филе, обвалять в панировке и обжарить."]) + self.insert_one([20, "3 hours", "Индейка с начинкой", "Приготовить начинку, фаршировать индейку и запекать в духовке."]) + self.insert_one([1, "50 minutes", "Фрикадельки", "Приготовить фарш, сформировать фрикадельки и обжарить."]) + self.insert_one([2, "2 hours 15 minutes", "Лазанья с мясным соусом", "Приготовить мясной соус, слои теста и запечь в духовке."]) + self.insert_one([3, "1 hour 30 minutes", "Чили", "Обжарить мясо, добавить фасоль, помидоры и специи, потушить."]) + self.insert_one([4, "40 minutes", "Хумус", "Приготовить нутовую пасту, добавить специи и подать с питой."]) + self.insert_one([5, "2 hours 30 minutes", "Утиная ножка по-французски", "Замариновать утиные ножки, обжарить и потушить."]) + self.insert_one([6, "1 hour 45 minutes", "Лапша по-сингапурски", "Обжарить лапшу с овощами, добавить соус и морепродукты."]) + self.insert_one([7, "55 minutes", "Фалафель", "Приготовить фалафельную смесь, сформировать шарики и обжарить."]) + self.insert_one([8, "2 hours 45 minutes", "Жаркое из телятины", "Обжарить мясо, добавить овощи и потушить в духовке."]) + self.insert_one([9, "1 hour 20 minutes", "Том ям", "Приготовить бульон, добавить морепродукты и специи."]) + self.insert_one([10, "3 hours 15 minutes", "Баранина по-гречески", "Замариновать баранину, запечь и подать с рисом."]) + self.insert_one([11, "50 minutes", "Картофельные оладьи", "Приготовить картофельное пюре, сформировать оладьи и обжарить."]) return \ No newline at end of file diff --git a/0.6_test/test.py b/0.6_test/test.py new file mode 100644 index 0000000..0a318aa --- /dev/null +++ b/0.6_test/test.py @@ -0,0 +1 @@ +print(len("\t")) \ No newline at end of file diff --git a/0.6_test/texts.py b/0.6_test/texts.py index cc81b7a..71e8cc3 100644 --- a/0.6_test/texts.py +++ b/0.6_test/texts.py @@ -3,20 +3,27 @@ show_main_menu_txt = """Привутствуем в меню, выберите 2 - сброс и инициализация БД; 9 - выход;""" show_cath_1txt = """Просмотр списка категорий! -№\tНазвание\n-------------------------------------------------------------------------------------""" +№\tНазвание\n-------------------------------------------------------------------------------------------""" -show_cath_2txt = """-------------------------------------------------------------------------------------\nДальнейшие операции: +show_cath_2txt = """-------------------------------------------------------------------------------------------\nДальнейшие операции: 0 - возврат в главное меню; 3 - добавление новой категории; 4 - удаление категории; 5 - просмотр блюд в категории; - 8 - обновить название категории; + 8 - обновить категорию/блюдо; 9 - выход.""" -show_dish_in_cath_txt = """-------------------------------------------------------------------------------------\nДальнейшие операции: +show_dish_in_cath_txt = """-------------------------------------------------------------------------------------------\nДальнейшие операции: 0 - возврат в главное меню; 1 - возврат в просмотр категорий; 6 - добавление нового блюда; 7 - удаление блюда; - 8 - обновить блюдо в выбранной категории; - 9 - выход.""" \ No newline at end of file + 8 - обновить категорию/блюдо; + 9 - выход.""" + +text_choice_update = """-------------------------------------------------------------------------------------------\n +Что вы хотите обновить? +1 - Категорию +2 - Блюдо +Введите необходимую цифру для выбора: +""" \ No newline at end of file diff --git a/other/Renata/__pycache__/dbconnection.cpython-311.pyc b/other/Renata/__pycache__/dbconnection.cpython-311.pyc new file mode 100644 index 0000000..63c054b Binary files /dev/null and b/other/Renata/__pycache__/dbconnection.cpython-311.pyc differ diff --git a/other/Renata/__pycache__/dbtable.cpython-311.pyc b/other/Renata/__pycache__/dbtable.cpython-311.pyc new file mode 100644 index 0000000..23a26dd Binary files /dev/null and b/other/Renata/__pycache__/dbtable.cpython-311.pyc differ diff --git a/other/Renata/__pycache__/extra_functions.cpython-311.pyc b/other/Renata/__pycache__/extra_functions.cpython-311.pyc new file mode 100644 index 0000000..a96045f Binary files /dev/null and b/other/Renata/__pycache__/extra_functions.cpython-311.pyc differ diff --git a/other/Renata/__pycache__/project_config.cpython-311.pyc b/other/Renata/__pycache__/project_config.cpython-311.pyc new file mode 100644 index 0000000..f5d2836 Binary files /dev/null and b/other/Renata/__pycache__/project_config.cpython-311.pyc differ diff --git a/other/Renata/config.yaml b/other/Renata/config.yaml new file mode 100644 index 0000000..be6cac8 --- /dev/null +++ b/other/Renata/config.yaml @@ -0,0 +1,6 @@ +# Базовые параметры настройки конфигурации проекта +dbname: Test # В классе менять не надо +user: postgres # Замените на свой логин от БД в классе +password: Qwerty # Замените на свой пароль от БД в классе +host: localhost # Замените на 192.168.0.48 в классе +dbtableprefix: "public." # Замените на свой логин от БД \ No newline at end of file diff --git a/other/Renata/dbconnection.py b/other/Renata/dbconnection.py new file mode 100644 index 0000000..6fac33c --- /dev/null +++ b/other/Renata/dbconnection.py @@ -0,0 +1,34 @@ +# Установка соединения с базой данных +# (параметры передаются через класс конфиг). +import psycopg2 + +class DbConnection: + + def __init__(self, config): + self.dbname = config.dbname + self.user = config.user + self.password = config.password + self.host = config.host + self.prefix = config.dbtableprefix + self.conn = psycopg2.connect(dbname = self.dbname, + user = self.user, + password = self.password, + host = self.host) + + def __del__(self): + if self.conn: + self.conn.close() + + def test(self): + cur = self.conn.cursor() + cur.execute("DROP TABLE IF EXISTS test CASCADE") + cur.execute("CREATE TABLE test(test integer)") + cur.execute("INSERT INTO test(test) VALUES(1)") + self.conn.commit() + cur.execute("SELECT * FROM test") + result = cur.fetchall() + cur.execute("DROP TABLE test") + self.conn.commit() + return (result[0][0] == 1) + + diff --git a/other/Renata/dbtable.py b/other/Renata/dbtable.py new file mode 100644 index 0000000..5fcf977 --- /dev/null +++ b/other/Renata/dbtable.py @@ -0,0 +1,92 @@ +# Базовые действия с таблицами + +from dbconnection import * + +class DbTable: + dbconn = None + + def __init__(self): + return + + def table_name(self): + return self.dbconn.prefix + "table" + + def columns(self): + return {"test": ["integer", "PRIMARY KEY"]} + + def column_names(self): + return sorted(self.columns().keys(), key = lambda x: x) + + def primary_key(self): + return ['id'] + + def column_names_without_id(self): + res = sorted(self.columns().keys(), key = lambda x: x) + if 'id' in res: + res.remove('id') + return res + + def table_constraints(self): + return [] + + def create(self): + sql = "CREATE TABLE " + self.table_name() + "(" + arr = [k + " " + " ".join(v) for k, v in sorted(self.columns().items(), key = lambda x: x[0])] + sql += ", ".join(arr + self.table_constraints()) + sql += ")" + cur = self.dbconn.conn.cursor() + cur.execute(sql) + self.dbconn.conn.commit() + return + + def drop(self): + sql = f"DROP TABLE IF EXISTS {self.table_name()} CASCADE" + cur = self.dbconn.conn.cursor() + cur.execute(sql) + self.dbconn.conn.commit() + return + + def insert_one(self, vals): + for i in range(0, len(vals)): + if type(vals[i]) == str: + vals[i] = "'" + vals[i] + "'" + else: + vals[i] = str(vals[i]) + sql = "INSERT INTO " + self.table_name() + "(" + sql += ", ".join(self.column_names_without_id()) + ") VALUES(" + sql += ", ".join(vals) + ")" + cur = self.dbconn.conn.cursor() + cur.execute(sql) + self.dbconn.conn.commit() + return + + def first(self): + sql = "SELECT * FROM " + self.table_name() + sql += " ORDER BY " + sql += ", ".join(self.primary_key()) + cur = self.dbconn.conn.cursor() + cur.execute(sql) + return cur.fetchone() + + def last(self): + sql = "SELECT * FROM " + self.table_name() + sql += " ORDER BY " + sql += ", ".join([x + " DESC" for x in self.primary_key()]) + cur = self.dbconn.conn.cursor() + cur.execute(sql) + return cur.fetchone() + + def all(self): + sql = "SELECT * FROM " + self.table_name() + sql += " ORDER BY " + sql += ", ".join(self.primary_key()) + cur = self.dbconn.conn.cursor() + cur.execute(sql) + return cur.fetchall() + + def insert_one(self, vals): + sql = f"INSERT INTO {self.table_name()}("+", ".join(self.column_names_without_id())+") VALUES(" + "%s" + ", %s"*(len(vals)-1) + ")" + cur = self.dbconn.conn.cursor() + cur.execute(sql, vals) + self.dbconn.conn.commit() + return \ No newline at end of file diff --git a/other/Renata/extra_functions.py b/other/Renata/extra_functions.py new file mode 100644 index 0000000..e4a8c1b --- /dev/null +++ b/other/Renata/extra_functions.py @@ -0,0 +1,17 @@ +from datetime import datetime + +def max_len(vals, index): + tmp = -1 + for i in vals: + tmp = max(tmp, len(i[index])) + if index == 2: + return max(tmp, 3) + return max(tmp, 7) +def check_format(val): + format = "%Y-%m-%d" + res = True + try: + res = bool(datetime.strptime(val, format)) + except ValueError: + res = False + return not(res) diff --git a/other/Renata/main.py b/other/Renata/main.py new file mode 100644 index 0000000..c3b4e57 --- /dev/null +++ b/other/Renata/main.py @@ -0,0 +1,284 @@ +import sys +sys.path.append('tables') + +from project_config import * +from dbconnection import * +from tables.countries_table import * +from tables.racers_table import * +from extra_functions import * +class Main: + + config = ProjectConfig() + connection = DbConnection(config) + + def __init__(self): + DbTable.dbconn = self.connection + return + + def db_init(self): + ct = CountriesTable() + rt = RacersTable() + ct.create() + rt.create() + return + + def db_insert_somethings(self): + ct = CountriesTable() + rt = RacersTable() + ct.insert_one(["Germany"]) + ct.insert_one(["United Kingdom"]) + ct.insert_one(["Netherlands"]) + ct.insert_one(["Finland"]) + ct.insert_one(["Mexico"]) + ct.insert_one(["Switzerland"]) + rt.insert_one(['1985-01-07', 1,'Lewis', 'Hamilton', 100]) + rt.insert_one(['1997-09-30', 3,'Max', 'Verstappen', 50]) + rt.insert_one(['1989-08-28', 4,'Valtteri', 'Bottas', 30]) + rt.insert_one(['1989-07-01', 1,'Daniel', 'Ricciardo', 15]) + rt.insert_one(['1990-01-26', 5,'Sergio', 'Perez', 10]) + + def db_drop(self): + ct = CountriesTable() + rt = RacersTable() + rt.drop() + ct.drop() + return + + def show_main_menu(self): + menu = """Добро пожаловать! +Основное меню (выберите цифру в соответствии с необходимым действием): + 1 - просмотр стран; + 2 - сброс и инициализация таблиц; + 9 - выход.""" + print(menu) + return + + def read_next_step(self): + return input("=> ").strip() + + def after_main_menu(self, next_step): + if next_step == "2": + self.db_drop() + self.db_init() + self.db_insert_somethings() + print("Таблицы созданы заново!") + return "0" + elif next_step != "1" and next_step != "9": + print("Выбрано неверное число! Повторите ввод!") + return "0" + else: + return next_step + + def show_countries(self): + self.country_id = -1 + menu = """Просмотр списка стран! +№\tНазвание страны""" + print(menu) + lst = CountriesTable().allbyname() + for index, i in enumerate(lst): + print(str(index+1) + "\t" + i[1]) + menu = """Дальнейшие операции: + 0 - возврат в главное меню; + 3 - добавление новой страны; + 4 - удаление страны; + 5 - просмотр гонщиков, родившихся в этой стране; + 9 - выход.""" + print(menu) + return + + def after_show_countries(self, next_step): + while True: + if next_step == "4": + self.delete_country() + return "1" + elif next_step == "5": + next_step = self.after_show_racers(self.show_racers_by_countries()) + elif next_step != "0" and next_step != "9" and next_step != "3": + print("Выбрано неверное число! Повторите ввод!") + return "1" + else: + return next_step + def after_show_racers(self, next_step): + while True: + if next_step == "3": + self.insert_new_racer() + elif next_step == "4": + self.delete_racer() + elif next_step == "0" or next_step == "9" or next_step == "1": + return next_step + else: + print('Ввели неверное число') + return "5" + + def delete_country(self): + num = input("Введите номер строки, в которой находится страна, которую вы хотите удалить (0 - отмена): ").strip() + if num == "0": + return + while len(num) == 0 or not(num.isdigit()) or not(CountriesTable().find_by_position(int(num))): + if len(num) == 0: + text = "Номер строки не пустое значение!" + elif not(num.isdigit()): + text = "Номер строки это положительное ЧИСЛО!" + else: + text = "Номер строки вне диапазона!" + num = input(text + " Введите номер строки снова (0 - отмена): ").strip() + if num == "0": + return + self.country_id = int(CountriesTable().find_by_position(int(num))[0]) + RacersTable().delete_by_cid(self.country_id) + CountriesTable().delete_by_cid(self.country_id) + def show_add_country(self): + data = input("Введите название страны (-1 - отмена): ").strip() + if data == "-1": + return + while len(data) == 0 or len(data) > 64 or CountriesTable().findbyname(data): + if len(data) == 0: + text = "Название страны не пустое!" + elif len(data) > 64: + text = "Название страны не превышает 64 значения!" + else: + text = "Такая страна уже есть в таблице!" + data = input(text + " Введите название страны снова (-1 - отмена): ").strip() + if data == "-1": + return + CountriesTable().insert_one([data]) + + def show_racers_by_countries(self): + if self.country_id == -1: + num = input("Укажите номер строки, в которой записана интересующая Вас персона (0 - отмена): ").strip() + while len(num) == 0 or not(num.isdigit()) or not(CountriesTable().find_by_position(int(num))): + if len(num) == 0: + text = "Номер строки не пустое значение!" + elif not(num.isdigit()): + text = "Номер строки это положительное ЧИСЛО!" + else: + text = "Номер строки вне диапазона!" + num = input(text + " Введите номер строки снова (0 - отмена): ").strip() + if num == "0": + return + country = CountriesTable().find_by_position(int(num)) + self.country_id = int(country[0]) + self.country_name = country[1] + print("Выбрана страна: " + self.country_name) + print("Гонщики:") + lst = RacersTable().all_by_country_id(self.country_id) + self.rac_max_len = len(str(len(lst))) + self.max_sur_len = max_len(lst, 4) + self.max_name_len = max_len(lst, 2) + menu = "№" + " "*(self.rac_max_len + 1)+ "Фамилия" + " "*(self.max_sur_len - 5) +"Имя" + " "*(self.max_name_len - 1) +"День рождения Количество побед" + print(menu) + for index, i in enumerate(lst): + text = str(index+1) + " "*(self.rac_max_len-len(str(index+1))+2)+i[4]+ \ + " "*(self.max_sur_len-len(i[4])+2)+i[2]+ " "*(self.max_name_len-len(i[2])+2) + text += str(i[0]) + " "*5+str(i[5]) + print(text) + menu = """Дальнейшие операции: + 0 - возврат в главное меню; + 1 - возврат в просмотр стран; + 3 - добавление нового гонщика; + 4 - удаление гонщика; + 9 - выход.""" + print(menu) + return self.read_next_step() + + def insert_new_racer(self): + while True: + data = [] + data.append(input("Введите имя гонщика (-1 - отмена): ").strip()) + if data[0] == "-1": + return + while len(data[0]) == 0 or len(data[0]) > 64: + if len(data[0]) == 0: + text = 'Имя не может быть пустым!' + else: + text = 'Имя превышает 64 символа!' + data[0] = input(text + " Введите имя заново (-1 - отмена): ").strip() + if data[0] == "-1": + return + data.append(input("Введите фамилию гонщика (-1 - отмена): ").strip()) + if data[1] == "-1": + return + while len(data[1]) == 0 or len(data[1]) > 64: + if len(data[1]) == 0: + text = 'Фамилия не может быть пустым!' + else: + text = 'Фамилия не превышает 64 символа!' + data[1] = input(text + " Введите фамилию заново (-1 - отмена): ").strip() + if data[1] == "-1": + return + data.append(input("Введите день рождения гонщика в формате (ГГГГ-ММ-ДД)(1976-04-03 - 3 апреля 1976 года), причем гонщику должно быть меньше 60 лет (-1 - отмена): ").strip()) + if data[2] == "-1": + return + while len(data[2]) == 0 or check_format(data[2]) or RacersTable().checkbirthday(data[2])[0]: + if len(data[2]) == 0: + text = 'День рождения не может быть пустым!' + elif check_format(data[2]): + text = 'Строка не соответствует формату дня рождения!' + else: + text = 'Гонщику больше 60 лет!' + data[2] = input(text + " Введите день рождения гонщика заново (ГГГГ-ММ-ДД) (-1 - отмена): ").strip() + if data[2] == "-1": + return + self.racer = RacersTable().select_by_s_n_b(data) + if not(self.racer): + break + print('Такой гонщик уже есть!', end = ' ') + data.append(self.country_id) + data[2], data[0], data[1], data[3] = data[0], data[2], data[3], data[1] + data.append(input("Введите количество побед гонщика (пробелы - значение по умолчанию: 0)(-1 - отмена): ").strip()) + if data[4] == "-1": + return + if len(data[4]) == 0: + RacersTable().insertbydef(data[:-1]) + return + while not(data[4].isdigit()): + text = "Количество побед это Положительное ЧИСЛО!" + data[4] = input(text + " Введите количество побед снова (-1 - отмена): ").strip() + if data[4]== "-1": + return + RacersTable().insert_one(data) + + def delete_racer(self): + num = input("Введите номер строки, в которой находится гонщик, которого вы хотите удалить (0 - отмена): ").strip() + if num == "0": + return + while len(num) == 0 or not(num.isdigit()) or not(RacersTable().find_by_position(self.country_id, int(num))): + if len(num) == 0: + text = "Номер строки не пустое значение!" + elif not(num.isdigit()): + text = "Номер строки это положительное ЧИСЛО!" + else: + text = "Номер строки вне диапазона!" + num = input(text + " Введите номер строки снова (0 - отмена): ").strip() + if num == "0": + return + RacersTable().delete_by_rid(int(RacersTable().find_by_position(self.country_id, int(num))[3])) + def main_cycle(self): + current_menu = "0" + next_step = None + while(current_menu != "9"): + if current_menu == "0": + self.show_main_menu() + next_step = self.read_next_step() + current_menu = self.after_main_menu(next_step) + elif current_menu == "1": + self.show_countries() + next_step = self.read_next_step() + current_menu = self.after_show_countries(next_step) + elif current_menu == "2": + self.show_main_menu() + elif current_menu == "3": + self.show_add_country() + current_menu = "1" + print("До свидания!") + return + + def test(self): + DbTable.dbconn.test() + +m = Main() +# Откоментируйте эту строку и закоментируйте следующую для теста +# соединения с БД +# m.test() +m.main_cycle() + diff --git a/other/Renata/project_config.py b/other/Renata/project_config.py new file mode 100644 index 0000000..2b451e5 --- /dev/null +++ b/other/Renata/project_config.py @@ -0,0 +1,21 @@ +# Загрузка настроек проекта (в данном случае только настроек соединения с БД) +# из файла config.yaml. +import yaml + +class ProjectConfig: + """Класс считывает базовые настройки из файла config.yaml""" + + def __init__(self): + with open('config.yaml') as f: + config = yaml.safe_load(f) + self.dbname = config['dbname'] + self.user = config['user'] + self.password = config['password'] + self.host = config['host'] + self.dbtableprefix = config['dbtableprefix'] + +# Этот метод запускается только, если запускать +# данный файл, а не подключать его. +if __name__ == "__main__": + x = ProjectConfig() + print(x.dbfilepath) diff --git a/other/Renata/tables/__pycache__/countries_table.cpython-311.pyc b/other/Renata/tables/__pycache__/countries_table.cpython-311.pyc new file mode 100644 index 0000000..0cc42ab Binary files /dev/null and b/other/Renata/tables/__pycache__/countries_table.cpython-311.pyc differ diff --git a/other/Renata/tables/__pycache__/racers_table.cpython-311.pyc b/other/Renata/tables/__pycache__/racers_table.cpython-311.pyc new file mode 100644 index 0000000..1d78c45 Binary files /dev/null and b/other/Renata/tables/__pycache__/racers_table.cpython-311.pyc differ diff --git a/other/Renata/tables/countries_table.py b/other/Renata/tables/countries_table.py new file mode 100644 index 0000000..17b1bce --- /dev/null +++ b/other/Renata/tables/countries_table.py @@ -0,0 +1,37 @@ +from dbtable import * + +class CountriesTable(DbTable): + def table_name(self): + return self.dbconn.prefix + '"Сountries"' + + def columns(self): + return {"country_id": ["serial", "PRIMARY KEY"], + "name": ["varchar(64)", "NOT NULL", "UNIQUE"] + } + def primary_key(self): + return ["country_id"] + def column_names_without_id(self): + res = sorted(self.columns().keys(), key = lambda x: x) + res.remove('country_id') + return res + def find_by_position(self, num): + sql = f"SELECT * FROM {self.table_name()} ORDER BY name LIMIT 1 OFFSET " + "%(offset)s" + cur = self.dbconn.conn.cursor() + cur.execute(sql, {"offset": num - 1}) + return cur.fetchone() + def allbyname(self): + sql = f"SELECT * FROM {self.table_name()} ORDER BY name" + cur = self.dbconn.conn.cursor() + cur.execute(sql) + return cur.fetchall() + def findbyname(self, data): + sql = f"SELECT country_id FROM {self.table_name()} WHERE name = "+ "%s" + cur = self.dbconn.conn.cursor() + cur.execute(sql, (data,)) + return cur.fetchall() + def delete_by_cid(self, cid): + sql = f"DELETE FROM {self.table_name()} WHERE country_id = " +"%s" + cur = self.dbconn.conn.cursor() + cur.execute(sql, (cid,)) + self.dbconn.conn.commit() + return \ No newline at end of file diff --git a/other/Renata/tables/racers_table.py b/other/Renata/tables/racers_table.py new file mode 100644 index 0000000..8045138 --- /dev/null +++ b/other/Renata/tables/racers_table.py @@ -0,0 +1,62 @@ +# Таблица Телефоны и особые действия с ней. + +from dbtable import * + +class RacersTable(DbTable): + def table_name(self): + return self.dbconn.prefix + '"Racers"' + + def columns(self): + return {"racer_id": ["serial", "PRIMARY KEY"], + "surname": ["varchar(64)", "NOT NULL"], + "name": ["varchar(64)", "NOT NULL"], + "birthday": ["date", "NOT NULL", "CHECK (extract(year from age(current_date, birthday)) < 60)"], + "country_id": ["integer", "NOT NULL", 'REFERENCES public."Сountries"(country_id) ON DELETE CASCADE'], + "wins": ["integer", "NOT NULL", "DEFAULT 0"]} + def table_constraints(self): + return ["UNIQUE (surname, name, birthday)"] + def primary_key(self): + return ["racer_id"] + def column_names_without_id(self): + res = sorted(self.columns().keys(), key = lambda x: x) + res.remove('racer_id') + return res + def all_by_country_id(self, cid): + sql = f"SELECT * FROM {self.table_name()} WHERE country_id = " + "%s ORDER BY surname, name, birthday" + cur = self.dbconn.conn.cursor() + cur.execute(sql, (cid,)) + return cur.fetchall() + def delete_by_cid(self, cid): + sql = f"DELETE FROM {self.table_name()} WHERE country_id = " +"%s" + cur = self.dbconn.conn.cursor() + cur.execute(sql, (cid,)) + self.dbconn.conn.commit() + return + def find_by_position(self, cid, num): + sql = f"SELECT * FROM {self.table_name()} WHERE "+ "country_id = %(cid)s ORDER BY surname, name, birthday LIMIT 1 OFFSET %(offset)s" + cur = self.dbconn.conn.cursor() + cur.execute(sql, {"cid": cid, "offset": num - 1}) + return cur.fetchone() + def delete_by_rid(self, rid): + sql = f"DELETE FROM {self.table_name()} WHERE racer_id = " +"%s" + cur = self.dbconn.conn.cursor() + cur.execute(sql, (rid,)) + self.dbconn.conn.commit() + return + def checkbirthday(self, val): + sql = "SELECT extract(year from age(current_date, %s)) >= 60" + cur = self.dbconn.conn.cursor() + cur.execute(sql, (val,)) + return cur.fetchone() + def select_by_s_n_b(self, vals): + sql = f"SELECT racer_id FROM {self.table_name()} WHERE name = " + "%s AND surname = %s AND birthday = %s" + cur = self.dbconn.conn.cursor() + cur.execute(sql, vals) + return cur.fetchone() + def insertbydef(self, vals): + sql = f"INSERT INTO {self.table_name()}(birthday, country_id, name, surname) VALUES "+"(%s,%s,%s,%s)" + cur = self.dbconn.conn.cursor() + print(vals) + cur.execute(sql, vals) + self.dbconn.conn.commit() + return \ No newline at end of file diff --git a/other/test.py b/other/test.py index 159aed8..287d012 100644 --- a/other/test.py +++ b/other/test.py @@ -9,3 +9,7 @@ # from tables.cath_table import * # cath = CathTable().find_by_name('За') +st = '2' +print('!\t!') +for i in range(30): + print('_', end="")