在 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)
我们甚至可以将name
和slug
抽象为抽象基础模型(例如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:请不要更改代码块,<b>
是为了在代码块中显示粗体字,而不是在代码中显示<b>
。以上是关于在 ListView 中过滤具有外键值的查询集的主要内容,如果未能解决你的问题,请参考以下文章