我正在开发一个应用程序,学生可以评估他们的老师。我有几个模型,但这个问题的重点是:
class Professor(models.Model):
name = models.CharField(max_length=50,null=True)
categories = models.ManyToManyField(Category, related_name='professors')
def __str__(self):
return self.name
class Student(models.Model):
name = models.CharField(max_length=50,null=True)
professors = models.ManyToManyField(Professor, related_name='students',through='Studentprofesor' )
def __str__(self):
return self.name
class Studentprofesor(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
professor = models.ForeignKey(Professor, on_delete=models.CASCADE)
tested = models.BooleanField(default=False)
据我所知,get
和filter
之间的主要区别在于,当有多个具有我正在寻找的功能的对象时,我无法使用get
。但除此之外,他们以类似的方式工作。对于单个对象get
,对于多个对象filter
。
但是,在这种情况下,当我运行get
和filter
时,我会得到不同的结果。
如果我使用get
:
Student.objects.get(name="Mike").professors.all()
我获得:
<QuerySet [<Professor: Tom>, <Professor: Jenn>]>
但如果我使用filter
:
Student.objects.filter(name="Mike").professors.all()
我获得:
AttributeError: 'QuerySet' object has no attribute 'professors'
就好像过滤器无法跟踪对象之间的多种关系。
为什么会这样?
答案 0 :(得分:2)
Bacause filter()
返回queryset(多个学生)。但professors
是单个学生实例的属性。您可以first()
与filter()
一起使用以获取单个对象:
Student.objects.filter(name="Mike").first().professors.all()
答案 1 :(得分:2)
.get(..)
和.filter(..)
之间存在巨大差异。简而言之:.get(..)
获取满足给定条件的单个模型实例,而.filter(..)
过滤查询集并生成概念上包含满足以下条件的模型实例 s (!)的查询集给定的条件。
.get(..)
.get
表示您的目标是检索一个实例。所以这意味着如果你写:
Model.objects.get(..)
结果是Model
实例(假设有这样的实例)。因此,我们可以从该单个实体获得属性(如.professors
等)。如果调用成功,我们保证:(1)没有过滤条件所持有的多个对象; (2)过滤标准至少有一个元素。因此输出总是模型实例,而不是None
或QuerySet
。
{em>热切地评估.get(..)
函数:我们立即对数据库执行查询。如果数据库未返回任何条目,或两个或更多条目,则Model.DoesNotExist
和MultipleObjectsReturned
例外将分别上升。
注意:由于
.get(..)
急切地行动,在.get(..)
右侧添加过滤器等没有用处(除非您定义filter
功能在那个例子上,但这也不是一个好主意。但是,您可以使用左侧的.values()
,values_list
,prefetch_related
等函数来更改输出类型(以及预取某些部分)。例如:Student.objects.values().get(name='Mike')
将生成一个包含该实例值的字典。
.filter(..)
另一方面过滤过滤器一个查询集。这意味着在我们过滤后,查询集可能不再包含任何实例(如果过滤器限制太多)或两个以上(如果过滤器太弱而无法固定到单个条目)。
Django 不非常评估此类.filter(..)
。这意味着默认情况下,Django将不对数据库进行查询以检索条目。只有在结果查询集上调用示例len(..)
或者对其进行迭代时,Django才会首先执行数据库查询,然后处理相应的结果。
由于.filter(..)
的结果是另一个QuerySet
,我们可以将操作链接在一起。例如,我们可以拨打额外的.filter(..)
或.exclude(..)
,values_list(..)
或QuerySet
支持的任何其他功能。
由于结果不是模型实例,因此我们无法调用模型实例的属性。如果没有学生符合标准,Student.objects.filter(..).name
的结果应该是什么?或者,如果有多个Student
匹配给定约束,该怎么办?
然而,我们可以获取Professor
个列表,其中包含一个或多个名为Student
'Mike'
的{{1}}个:
# professors with a student called Mike
Professors.objects.filter(students__name="Mike")
过滤器永远不会引发Model.DoesNotExist
或MultipleObjectsReturned
例外,因为完全允许使用包含多个项目的空QuerySet
或QuerySet
s。