Django-filter 按相关字段过滤

Sni*_*r03 6 django django-models django-filter django-rest-framework

我有两张桌子。

class Writer(models.Model)
    name = model.CharField()
    ...

class Article(models.Model)
    name = model.CharField()
    writer = model.ForeignKey('Writer', related_name="relationship") 
    ...
Run Code Online (Sandbox Code Playgroud)

我想构建一些获取作者列表的 API 端点,但这应该可以通过文章 ID 进行过滤。我正在使用 django 过滤器。所以:

class WriterViewSet(viewsets.ReadOnlyModelViewSet):
   filter_backend = [filters.djangoFilterBackend],
   filter_class = WriterFilter


class WriteFilter(django_filters.rest_framework.FilterSet):
....
Run Code Online (Sandbox Code Playgroud)

所以我担心的是,我如何定义 WriteFilter 以通过文章过滤 Writer?

JPG*_*JPG 9

class WriteFilter(django_filters.rest_framework.FilterSet):
    article = django_filters.CharFilter(name='relationship__name', lookup_expr='contains')

    class Meta:
        model = WriterFilter
        fields = ['article']
Run Code Online (Sandbox Code Playgroud)


你的网址会是这样的,
/api/wtiter/list/?article=somearticlename


更新-1

因为django-filter 2.0name论点变为field_name

因此过滤器类将是,

class WriteFilter(django_filters.rest_framework.FilterSet):
    article = django_filters.CharFilter(field_name='relationship__name', lookup_expr='contains')

    class Meta:
        model = WriterFilter
        fields = ['article']
Run Code Online (Sandbox Code Playgroud)


fre*_*nzy 5

JPG 答案是正确的,但如果你有很多字段和关系,这将是一项乏味的工作。但你实际上可以在元中声明关系field

class ArticleFilter(django_filters.rest_framework.FilterSet):
    class Meta:
        model = Article
        fields = ['article', 'writer__name']
Run Code Online (Sandbox Code Playgroud)

或者使用查找表达式:

class ArticleFilter(django_filters.rest_framework.FilterSet):
    class Meta:
        model = Article
        fields = {
            'article': ('exact', ),
            'relationship__name': ('exact', 'contains')
            }
Run Code Online (Sandbox Code Playgroud)

还有更多优化:

def prefix_dict_keys(prefix: str, d: dict):
    return {prefix + k: v for k, v in d.items()}

class ArticleFilter(django_filters.rest_framework.FilterSet):
    class Meta:
        model = Article
        fields = {
            'article': ('exact', ),
            ...
            **prefix_dict_keys('writer__'
                {
                   'name': ('exact', 'contains')),
                   ...
                }),
            ...
            }
Run Code Online (Sandbox Code Playgroud)