Django - 更新数据库条目(如果存在)或插入将两个表组合在一起的新条目(模型)

Django - Update database entry if it exists or insert new entry combining two tables together (models)

提问人:Σταύρος Καρακέπελης 提问时间:11/14/2023 更新时间:11/14/2023 访问量:38

问:

我有一个应用程序,可以将两个 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

此功能将学生记录保存到数据库中。如果学生所在行的注册号匹配,则会更新记录,否则会将其作为新记录插入。

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 个,数据库将只保留最新的科目记录并丢弃其余的。

python django django-models django-views sqlite3-python

评论


答:

0赞 Rajkumar Hajgude 11/14/2023 #1

我认为您的代码仅限制了第一个元素的 df。输入 df 可能包含所有等级信息,但您只切片和获取第一个元素?

df = df[0]