在ListView中使用外键值过滤查询集

时间:2019-06-16 20:56:53

标签: django foreign-keys django-queryset

我正在尝试通过将外键的值设置为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 个答案:

答案 0 :(得分:1)

您需要过滤parent_slug对象(简称为Parent)的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'])

话虽这么说,建模中的术语有点 odd 。通常,字段 not 都以模型名称为前缀,并且ForeignKey是指该字段所引用的模型对象,而不是其子对象。此外,为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'])