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]