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(),
)
)
上面的一些重要注意事项:
- 查询集是惰性的,这意味着它们在被评估.
之前不会做任何事情
F()
表达式(和 ExpressionWrapper
)用于定义 由数据库 执行的表达式,而不是 Python 在内存中执行的表达式]. Django 创建一个表达式作为发送到数据库的查询的一部分;它永远不会被 Django 评估甚至返回给 Django。
- 当您对从
.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
)
我正在努力避免 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(),
)
)
上面的一些重要注意事项:
- 查询集是惰性的,这意味着它们在被评估. 之前不会做任何事情
F()
表达式(和ExpressionWrapper
)用于定义 由数据库 执行的表达式,而不是 Python 在内存中执行的表达式]. Django 创建一个表达式作为发送到数据库的查询的一部分;它永远不会被 Django 评估甚至返回给 Django。- 当您对从
.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
)