@PashaLynx
Страшный дилетант

Проблема в архитектуре бд sqlite, что не так?

Всем салют. Делаю приложение на tkinter для учета студентов. Есть проблема в бд, подскажите, что не так.

Код создания бд:
class DB:
    def __init__(self):
        self.conn = sqlite3.connect('students.db')
        self.c = self.conn.cursor()

        self.c.execute(
            '''PRAGMA foreign_keys=on''')
        self.conn.commit()

        self.c.execute(
            '''CREATE TABLE IF NOT EXISTS gender(
            gender text)''')
        self.conn.commit()

        self.c.execute(
            '''INSERT OR IGNORE INTO gender (gender)
            VALUES ('М'), 
            ('Ж')''')
        self.conn.commit()

        self.c.execute(
            '''CREATE TABLE IF NOT EXISTS groupp(
            groupp text)''')
        self.conn.commit()

        self.c.execute(
            '''CREATE TABLE IF NOT EXISTS teacher(
            teacher text)''')

        self.c.execute(
            '''CREATE TABLE IF NOT EXISTS students(
            id integer primary key, 
            namme text, 
            groupp text,
            teacher text,
            nummber text,
            birth text,
            address text,
            gender text,
            FOREIGN KEY (groupp) REFERENCES groupp(groupp),
            FOREIGN KEY (teacher) REFERENCES teacher(teacher),
            FOREIGN KEY (gender) REFERENCES gender(gender))''')
        self.conn.commit()

    def insert_teacher(self, teacher):
        self.c.execute(
            '''INSERT INTO teacher(teacher)
            VALUES (?)''',
            (teacher, ))
        self.conn.commit()

    def insert_group(self, groupp):
        self.c.execute(
            '''INSERT INTO groupp(groupp)
            VALUES (?)''',
            (groupp, ))
        self.conn.commit()


    def insert_data(self, namme, groupp, teacher, nummber, birth, address, gender):
        self.c.execute(
            '''INSERT INTO students(namme, groupp, teacher, nummber, birth, address, gender)
            VALUES (?, ?, ?, ?, ?, ?, ?)''',
            (namme, groupp, teacher, nummber, birth, address, gender))
        self.conn.commit()

То есть, чтобы добавить в систему студента, должны быть уже созданы его группа и куратор. В чем заключается проблема - когда заносишь в бд студента, вылетает вот такая ошибка:
Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 1705, in __call__
    return self.func(*args)
  File "/home/overlord/PycharmProjects/student_registration/visual1.py", line 226, in <lambda>
    self.gender.get))
  File "/home/overlord/PycharmProjects/student_registration/visual1.py", line 77, in records
    self.db.insert_data(namme, groupp, teacher, nummber, birth, address, gender)
  File "/home/overlord/PycharmProjects/student_registration/visual1.py", line 349, in insert_data
    (namme, groupp, teacher, nummber, birth, address, gender))
sqlite3.OperationalError: foreign key mismatch - "students" referencing "gender"


Вот код самого окна добавления студента, не может ли это быть как-то связаным с тем, что именно пол у меня идет через Combobox?
class Child(tk.Toplevel):
    def __init__(self):
        super().__init__(root)
        self.init_child()
        self.view = app

    def init_child(self):
        self.title('Добавить студента.')
        self.geometry('400x420+400+300')
        self.resizable(False, False)

        label_namme = tk.Label(self, text='ФИО:')
        label_namme.place(x=50, y=50)
        label_groupp = tk.Label(self, text='Группа:')
        label_groupp.place(x=50, y=80)
        label_teacherr = tk.Label(self, text='Куратор:')
        label_teacherr.place(x=50, y=110)
        label_number = tk.Label(self, text='Номер телефона:')
        label_number.place(x=50, y=140)
        label_birth = tk.Label(self, text='Дата рождения:')
        label_birth.place(x=50, y=170)
        label_address = tk.Label(self, text='Адрес проживания:')
        label_address.place(x=50, y=200)
        label_genderr = tk.Label(self, text='Пол:')
        label_genderr.place(x=50, y=230)

        self.entry_namme = ttk.Entry(self)
        self.entry_namme.place(x=200, y=50)

        self.entry_groupp = ttk.Entry(self)
        self.entry_groupp.place(x=200, y=80)

        self.entry_teacherr = ttk.Entry(self)
        self.entry_teacherr.place(x=200, y=110)

        self.entry_numberr = ttk.Entry(self)
        self.entry_numberr.place(x=200, y=140)

        self.entry_birth = ttk.Entry(self)
        self.entry_birth.place(x=200, y=170)

        self.entry_address = ttk.Entry(self)
        self.entry_address.place(x=200, y=200)

        self.gender = ttk.Combobox(self, values=[u'М', u'Ж'])
        self.gender.current(0)
        self.gender.place(x=200, y=230)

        btn_cancel = ttk.Button(self, text='Закрыть', command=self.destroy)
        btn_cancel.place(x=300, y=270)

        self.btn_ok = ttk.Button(self, text='Добавить')
        self.btn_ok.place(x=220, y=270)
        self.btn_ok.bind('<Button-1>', lambda event: self.view.records(self.entry_namme.get(),
                                                                       self.entry_groupp.get(),
                                                                       self.entry_teacherr.get(),
                                                                       self.entry_numberr.get(),
                                                                       self.entry_birth.get(),
                                                                       self.entry_address.get(),
                                                                       self.gender.get()))

        self.grab_set()
        self.focus_set()


Заодно прикрепляю код добавления студента в бд:

def records(self, namme, groupp, teacher, nummber, birth, address, gender):
        self.db.insert_data(namme, groupp, teacher, nummber, birth, address, gender)
        self.view_records()


    def insert_data(self, namme, groupp, teacher, nummber, birth, address, gender):
        self.c.execute(
            '''INSERT INTO students(namme, groupp, teacher, nummber, birth, address, gender)
            VALUES (?, ?, ?, ?, ?, ?, ?)''',
            (namme, groupp, teacher, nummber, birth, address, gender))
        self.conn.commit()
  • Вопрос задан
  • 564 просмотра
Решения вопроса 1
@o5a
Ошибку выдает потому, что запрос на вставку gender ('insert or ignore') пытается использовать ключи, а в таблице они не заданы.
Например, так

CREATE TABLE IF NOT EXISTS gender(gender text primary key)


В остальном по структуре. Если все же делаете реляционную модель, то в таблице студентов должны храниться id из этих справочных таблиц (groupp, teacher и т.д.), а не сами значения. Тогда это позволит поддерживать уникальность значений, позволять использовать выбор значений из справочников (которыми и будут эти таблицы gender, teacher и т.д.).

Пример, для учителя не просто таблица с teacher text, а таблица с ключевым полем, которое и используется для связки с таблицей студентов и остальными редактируемыми полями.

CREATE TABLE IF NOT EXISTS teacher(
            teacher integer primary key,
            teacher_name text)


Тогда по учителю можно будет добавлять и другие поля, характеризующие его, менять само имя(название/фамилию), при этом не нарушая связь по ключу с таблицей студентов. Выбор каждого поля для таблицы студентов будет выбором из текущих значений соответствующей справочной таблицы, а не ввод вручную.

Если же полноценная реляционная модель не нужна, то нет и смысла делать отдельную таблицу под каждую сущность (они по факту не будут использоваться), можно все хранить напрямую в таблице студентов.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы