Django F() 和 ExpressionWrapper

Django F() and ExpressionWrapper

我正在努力避免 DB 命中我的 views.py。如果我使用 F() 和 ExpressionWrapper,我是否正在对数据库进行查询。我正在尝试优化我的代码,但在阅读文档时有点困惑。我还包括了 Models.py 以供参考。我正在对我正在工作的 Web 应用程序进行优化。

Views.py

from django.shortcuts import render
from django.db.models import F, Q, Count, Sum, ExpressionWrapper, IntegerField
from .models import Student, Subject, Enrollment


def home(request):
    student = Student.objects.all()
    subject = Subject.objects.all()
    sem_score = Enrollment.objects.all().update(sem_score=ExpressionWrapper((F("prelim_score") + F("midterm_score") + F("final_score"))/3, output_field=IntegerField()))
    enrollment = Enrollment.objects.all()
    num_student = Enrollment.objects.all().count()
    context = {"student":student, "subject":subject, "enrollment":enrollment, "num_student":num_student}
    return render(request, 'core/home.html', context)

Models.py

class Professor(models.Model):
    name = models.CharField(max_length=50)
    
    def __str__(self):
        return self.name
    
class Student(models.Model):
    name = models.CharField(max_length=50)
    
    def __str__(self):
        return self.name
    
class Course(models.Model):
    name = models.CharField(max_length=50)
    
    def __str__(self):
        return self.name
    
class Subject(models.Model):
    name = models.CharField(max_length=50)
    course = models.ManyToManyField(Course)
    enroll = models.ManyToManyField(Student, through='Enrollment')

    def __str__(self):
        return self.name
    
    
    
class Enrollment(models.Model):
    GRADE_STATUS = (
        ("A","A"),
        ("B", "B"),
        ("C", "C"),
    )
    student = models.ForeignKey(Student, on_delete=models.CASCADE)
    subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
    professor = models.ForeignKey(Professor, on_delete=models.CASCADE, null=True, blank=True)
    date = models.DateTimeField(auto_now_add=True)
    prelim_score = models.IntegerField(null=True, blank=True, default=0)
    midterm_score = models.IntegerField(null=True, blank=True,  default=0)
    final_score = models.IntegerField(null=True, blank=True,  default=0)
    sem_score = models.IntegerField(null=True, blank=True,  default=0)
    sem_status = models.CharField(choices=GRADE_STATUS , max_length=50, null=True, blank=True,  default=0)
    
    
    def __str__(self):
        return f"{self.student} enrolled in {self.subject}"
    

I used the F() and ExpressionWrapper, Am I doing a query on the database

sem_score = Enrollment.objects.all().update(
    sem_score=ExpressionWrapper(
        (F("prelim_score") + F("midterm_score") + F("final_score")) / 3,
        output_field=IntegerField(),
    )
)

上面的一些重要注意事项:

  1. 查询集是惰性的,这意味着它们在被评估.
  2. 之前不会做任何事情
  3. F() 表达式(和 ExpressionWrapper)用于定义 由数据库 执行的表达式,而不是 Python 在内存中执行的表达式]. Django 创建一个表达式作为发送到数据库的查询的一部分;它永远不会被 Django 评估甚至返回给 Django。
  4. 当您对从 .all() 返回的查询集调用 .update 时,它将立即评估查询集并执行更新。那是将查询(连同您的表达式)发送到数据库并且数据库在数据库服务器上计算表达式的时间。

所以,直接回答你的问题:不,单独调用F()ExpressionWrapper(),不会查询数据库。一旦 django 确实 与数据库对话,它就会发送您的表达式以供数据库评估。表达式求值严格发生在数据库中,而不是在 Python.

此外,因为在 F() 表达式中引用的模型字段都是同一类型,所以您不需要 ExpressionWrapper:

sem_score = Enrollment.objects.all().update(
    sem_score=(F("prelim_score") + F("midterm_score") + F("final_score")) / 3
)