为什么 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)

据我所知,getfilter 之间的主要区别在于,当有多个对象具有我正在寻找的功能时,我无法使用 get。但除此之外,他们的工作方式相似。 get 用于单个对象,filter 用于多个对象。

但是,在这种情况下,当我 运行 getfilter.

时,我得到了不同的结果

如果我使用 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) 至少有一个元素符合过滤条件。所以输出总是一个模型实例,而不是NoneQuerySet

.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