为什么 Get 和 Filter 给出不同的结果? (姜戈)
Why do Get and Filter give different results? (Django)
我正在开发一个应用程序,学生可以在其中评价他们的老师。我有几个模型,但这个问题的重要模型是:
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'
好像过滤器无法遵循对象之间的多对多关系。
为什么会这样?
因为 filter()
returns 查询集(多个学生)。但是 professors
是单个学生实例的属性。您可以使用 first()
和 filter()
来获取单个对象:
Student.objects.filter(name="Mike").first().professors.all()
.get(..)
and .filter(..)
之间存在巨大差异。简而言之:.get(..)
获得满足给定条件的单个模型实例,而 .filter(..)
过滤查询集并生成概念上包含模型实例的查询集 s (!)满足给定条件。
Django 的 .get(..)
.get
意味着您的目标是检索 恰好一个 实例。所以这意味着如果你写:
Model.objects.get(..)
结果是一个 Model
实例(假设有这样的实例)。因此,我们可以从该单个实体获得属性(如 .professors
等)。如果调用成功,我们可以保证: (1) 没有多个对象符合过滤条件; (2) 至少有一个元素符合过滤条件。所以输出总是一个模型实例,而不是None
或QuerySet
。
.get(..)
函数被评估急切:我们立即对数据库执行查询。如果数据库 returns 没有条目,或者两个或更多条目,则分别引发 Model.DoesNotExist
and MultipleObjectsReturned
异常。
Note: since .get(..)
acts eagerly, adding filters, etc. at the right of .get(..)
has no use (well unless you define a filter
function on that instance, but that is not a good idea either). You can however use functions like .values()
, values_list
, prefetch_related
, etc. on the left side to change the type of output (and prefetch certain parts). For example:
Student.objects<b>.values()</b>.get(name='Mike')
will result in a dictionary containing the values of that instance.
Django 的 .filter(..)
另一方面过滤过滤一个查询集。这意味着在我们过滤之后,查询集可能不再包含任何实例(如果过滤器过于严格)或两个或更多(如果过滤器太弱而无法固定到单个条目)。
Django 不 评估这样.filter(..)
急切。这意味着默认情况下 Django 将 不会 查询数据库以检索条目。仅当您对结果查询集调用 len(..)
或对其进行迭代时,Django 才会首先执行数据库查询,然后处理相应的结果。
由于 .filter(..)
的结果是另一个 QuerySet
,我们可以将操作链接在一起。例如,我们可以调用额外的 .filter(..)
或 .exclude(..)
、values_list(..)
或 QuerySet
.
支持的任何其他函数
由于结果不是模型实例,我们不能调用模型实例的属性。如果没有学生符合条件,Student.objects.filter(..).name
的结果应该是什么?或者如果有多个 Student
匹配给定的约束怎么办?
然而,我们可以获得 Professor
的列表,这些 Professor
教一个或多个 Student
名称为 'Mike'
的 'Mike'
具有:
# professors with a student called Mike
Professors.objects.filter(students__name="Mike")
过滤器永远不会引发 Model.DoesNotExist
or a MultipleObjectsReturned
异常,因为完全允许它处理空 QuerySet
或包含多个项目的 QuerySet
。
我正在开发一个应用程序,学生可以在其中评价他们的老师。我有几个模型,但这个问题的重要模型是:
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'
好像过滤器无法遵循对象之间的多对多关系。
为什么会这样?
因为 filter()
returns 查询集(多个学生)。但是 professors
是单个学生实例的属性。您可以使用 first()
和 filter()
来获取单个对象:
Student.objects.filter(name="Mike").first().professors.all()
.get(..)
and .filter(..)
之间存在巨大差异。简而言之:.get(..)
获得满足给定条件的单个模型实例,而 .filter(..)
过滤查询集并生成概念上包含模型实例的查询集 s (!)满足给定条件。
Django 的 .get(..)
.get
意味着您的目标是检索 恰好一个 实例。所以这意味着如果你写:
Model.objects.get(..)
结果是一个 Model
实例(假设有这样的实例)。因此,我们可以从该单个实体获得属性(如 .professors
等)。如果调用成功,我们可以保证: (1) 没有多个对象符合过滤条件; (2) 至少有一个元素符合过滤条件。所以输出总是一个模型实例,而不是None
或QuerySet
。
.get(..)
函数被评估急切:我们立即对数据库执行查询。如果数据库 returns 没有条目,或者两个或更多条目,则分别引发 Model.DoesNotExist
and MultipleObjectsReturned
异常。
Note: since
.get(..)
acts eagerly, adding filters, etc. at the right of.get(..)
has no use (well unless you define afilter
function on that instance, but that is not a good idea either). You can however use functions like.values()
,values_list
,prefetch_related
, etc. on the left side to change the type of output (and prefetch certain parts). For example:Student.objects<b>.values()</b>.get(name='Mike')
will result in a dictionary containing the values of that instance.
Django 的 .filter(..)
另一方面过滤过滤一个查询集。这意味着在我们过滤之后,查询集可能不再包含任何实例(如果过滤器过于严格)或两个或更多(如果过滤器太弱而无法固定到单个条目)。
Django 不 评估这样.filter(..)
急切。这意味着默认情况下 Django 将 不会 查询数据库以检索条目。仅当您对结果查询集调用 len(..)
或对其进行迭代时,Django 才会首先执行数据库查询,然后处理相应的结果。
由于 .filter(..)
的结果是另一个 QuerySet
,我们可以将操作链接在一起。例如,我们可以调用额外的 .filter(..)
或 .exclude(..)
、values_list(..)
或 QuerySet
.
由于结果不是模型实例,我们不能调用模型实例的属性。如果没有学生符合条件,Student.objects.filter(..).name
的结果应该是什么?或者如果有多个 Student
匹配给定的约束怎么办?
然而,我们可以获得 Professor
的列表,这些 Professor
教一个或多个 Student
名称为 'Mike'
的 'Mike'
具有:
# professors with a student called Mike
Professors.objects.filter(students__name="Mike")
过滤器永远不会引发 Model.DoesNotExist
or a MultipleObjectsReturned
异常,因为完全允许它处理空 QuerySet
或包含多个项目的 QuerySet
。