Django - Обновление записи в базе данных, если она существует, или вставка новой записи, объединяющей две таблицы вместе (модели)

У меня есть приложение, которое объединяет два файла excel в один (данные учеников и данные оценок по их предметам). Таким образом, одна таблица для студентов и одна для оценок. Вот как выглядит мой models.py:


models.py

class Students(models.Model):
    study_program = models.CharField(max_length=40, blank=True, null=True)
    registration_number = models.IntegerField(blank=True, null=True)
    id_number_1 = models.FloatField(blank=True, null=True)
    name = models.CharField(max_length=100, null=True)
    surname = models.CharField(max_length=100)
    nationality = models.CharField(max_length=10)
    .
    .
    (many more columns here)
    .
    def __str__(self):
        return self.name + ' ' + self.surname


class StudentGrades(models.Model):
    student = models.ForeignKey(Students, default=None, on_delete=models.CASCADE)
    subject = models.CharField(max_length=40)  # Μάθημα (Subject)
    subject_code = models.CharField(max_length=20, )  # Κωδ. μαθ. (Subject Code)
    student_class = models.CharField(max_length=40, )  # Τμήμα Τάξης (Class)
    .
    .
    (many more columns here)
    .
    def __str__(self):
        return self.subject + ' ' + self.student.name + ' ' + self.student.surname

Первичным ключом, связывающим эти два ключа, является регистрационный номер студента. Каждый студент имеет уникальный регистрационный номер. В файле views.py я создал две функции (по одной для каждой таблицы), которые сохраняют содержимое файлов excel в базу данных. Вот views.py:

views.py

Эта функция сохраняет записи students в базу данных. Если в строке студента есть совпадающий регистрационный номер, она обновляет запись, в противном случае вставляет ее как новую.

def update_or_create_student(df):
    try:
        df = df[0]
    except:
        return redirect('/dashboard/upload/students')

    for i in range(len(df)):
        AM = df.iloc[i]['ΑΜ']
        if Students.objects.filter(registration_number=AM).exists():
            print('updated..')
            Students.objects.filter(registration_number=AM).update(
                study_program=df.iloc[i]['ΠΣ'],
                registration_number=df.iloc[i]['ΑΜ'],
                id_number_1=df.iloc[i]['Ακ. Ταυτότητα'],
                name=df.iloc[i]['Όνομα'],
                surname=df.iloc[i]['Επώνυμο'],
                .
                .
                .
            )
        else:
            print('created..')
            Students(
                study_program=df.iloc[i]['ΠΣ'],
                registration_number=df.iloc[i]['ΑΜ'],
                .
                .
                .
            ).save()

Теперь эта функция делает то же самое для оценок ученика.

def updated_or_create_grades(df):
    try:
        df = df[0]
    except:
        return redirect('/dashboard/upload/grades')

    student_id = None
    for i in range(len(df)):
        reg_no = df.iloc[i]["AM"]
        if Students.objects.filter(registration_number=reg_no).exists():
            student_id = Students.objects.get(registration_number=reg_no)

        if StudentGrades.objects.filter(registration_number=df.iloc[i]["AM"]).exists():
            print('updated..')
            StudentGrades.objects.filter(student=student_id).update(
                subject_code=df.iloc[i]['Κωδ. μαθ.'],
                subject_of_academic_year=df.iloc[i]['Μάθημα Ακ. Έτους'],
                student_class=df.iloc[i]['Τμήμα Τάξης'],
                .
                .
                .
        else:
            print('created..')
            StudentGrades(
                student=student_id,
                subject_code=df.iloc[i]['Κωδ. μαθ.'],
                subject_of_academic_year=df.iloc[i]['Μάθημα Ακ. Έτους'],
                student_class=df.iloc[i]['Τμήμα Τάξης'],
                .
                .
                .
            ).save()

Вот в чем проблема. Это работает, только если отношения 1:1 (у одного ученика один предмет/класс). И это была первоначальная функциональность приложения. Однако я хочу расширить его и включить много предметов/классов (поэтому 1:N, каждый ученик посещает несколько предметов). Нет необходимости создавать третью модель/таблицу, поскольку каждый новый excel-файл с оценками имеет точно такое же форматирование столбцов.

Я хочу модифицировать код, чтобы включить в него записи из всех оценок по всем предметам, которые посещал ученик. Каждый предмет имеет свой код, поэтому я думал фильтровать как по регистрационному номеру, так и по коду предмета, но не смог реализовать это в своей функции. Я не думаю, что нужно что-то менять в первой функции, только в функции updated_or_create_grades. Если это поможет, вот столбец в таблице для кода темы:

subject_code = models.CharField(max_length=20, )

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

Я думаю, что ваш код ограничивает df только первым элементом. Входной df может содержать всю информацию об оценках, но вы нарезаете и получаете только первый элемент?

df = df[0]
Вернуться на верх