在 ListView 中过滤具有外键值的查询集

Posted

技术标签:

【中文标题】在 ListView 中过滤具有外键值的查询集【英文标题】:Filtering a queryset with foreign key value in ListView 【发布时间】:2019-10-30 12:46:31 【问题描述】:

我试图通过将外键的值设置为 url slug 来过滤查询集。

models.py

class Parent(models.Model):

    parent_name = models.CharField(unique=True, max_length=40)

    parent_slug = models.SlugField(unique=True)


class Child(models.Model):

    child_name = models.CharField(unique=True, max_length=40, default=1)

    child_slug = models.SlugField(unique=True, default=1)

    parent_slug = models.ForeignKey(Parent, on_delete=models.CASCADE,default = 1)

urls.py

from .views import ChildListView

urlpatterns = [
    ...
    path('<parent_slug>/children/', ChildListView.as_view(), name='child_list'),
    ...
]

views.py

class ChildListView(ListView):

    template_name = 'child_list.html'

    context_object_name = 'child'

    def get_queryset(self):

        slug_param = self.kwargs['parent_slug']

        qs = Child.objects.filter(parent_slug = slug_param)

        return qs   

这是错误结果:

异常值: 无法将关键字“父”解析为字段。

【问题讨论】:

【参考方案1】:

您需要对Parent 对象(称为parent_slug)的parent_slug 进行过滤,因此您需要过滤:

class ChildListView(ListView):
    template_name = 'child_list.html'
    context_object_name = 'child'

    def get_queryset(self):
        return Child.objects.filter(parent_slug__parent_slug=self.kwargs['parent_slug'])

话虽如此,建模中的命名有点奇怪。通常,字段以模型名称为前缀,ForeignKey 指的是该字段所引用的模型对象,而不是它的 slug。此外,将default=1 设置为ForeignKey 可能没有多大意义,因为它稍后可能会引用与您所持有的对象不同的对象。最后将default=1 设置为SlugField 肯定没有多大意义。

定义模型的更好方法可能是:

class Parent(models.Model):
    name = models.CharField(unique=True, max_length=40)
    slug = models.SlugField(unique=True)

class Child(models.Model):
    name = models.CharField(unique=True, max_length=40)
    slug = models.SlugField(unique=True)
    parent = models.ForeignKey(Parent, on_delete=models.CASCADE)

我们甚至可以将nameslug 抽象为抽象基础模型(例如NameSlugModel),例如:

class NameSlugModel(models.Model):
    name = models.CharField(unique=True, max_length=40)
    slug = models.SlugField(unique=True)

    class Meta:
        abstract = True

class Parent(NameSlugModel):
    pass

class Child(NameSlugModel):
    parent = models.ForeignKey(Parent, on_delete=models.CASCADE)

在这种情况下,您可以使用:

class ChildListView(ListView):
    template_name = 'child_list.html'
    context_object_name = 'child'

    def get_queryset(self):
        return Child.objects.filter(parent__slug=self.kwargs['parent_slug'])

【讨论】:

谢谢,威廉!抽象出 NameSlugModel 的好点。我会实施的。查询过滤器的解释也很清楚。它为我提出了另外两个问题,我将单独发布。 Willem(或其他人),还有哪些好的标准抽象模型要包括在内?我可能也会包含一个日期时间戳抽象类。还有什么要考虑的吗? @DavidGoldman:通常,如果它是一组有意义的属性,则可能具有某些行为。见docs.djangoproject.com/en/2.2/topics/db/models/…有一些GitHub项目定义了一组基类,比如github.com/concentricsky/django-basic-models @marc_s:请不要更改代码块,&lt;b&gt; 是为了在代码块中显示粗体字,而不是在代码中显示&lt;b&gt;

以上是关于在 ListView 中过滤具有外键值的查询集的主要内容,如果未能解决你的问题,请参考以下文章

SSIS 数据流 - 具有所需外键值的顺序插入

JPA:查询以根据实体类中定义的外键值获取结果?

需要对查找多个外键值的 SQL 查询使用“VLOOKUP”类型的操作 - SOS

外键的过滤查询集[关闭]

Django反向过滤查询集外键示例不起作用

Django过滤与其他模型的外键相关的模型的查询集?