Snipper03
Snipper03

Reputation: 1524

Django-filter filter by related fields

I have two tables.

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

class Article(models.Model)
    name = model.CharField()
    writer = model.ForeignKey('Writer', related_name="relationship") 
    ...

I wanted to build some API endpoints getting the writer list, but this should be filterable by Article id. I am using django-filter. So:

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


class WriteFilter(django_filters.rest_framework.FilterSet):
....

So my concern is, how can I define WriteFilter to filter Writer by the article?

Upvotes: 7

Views: 13485

Answers (3)

frenzy
frenzy

Reputation: 1650

JPG answer is right, but if you got lots of fields and relations it will be tedious work. But you can actually declare relations in field meta:

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

Or with lookup expressions:

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

And even more optimization:

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')),
                   ...
                }),
            ...
            }

Upvotes: 5

JPG
JPG

Reputation: 88539

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

    class Meta:
        model = WriterFilter
        fields = ['article']


Your url will be like this,
/api/wtiter/list/?article=somearticlename


UPDATE-1

since django-filter 2.0, the name argument changed to field_name.

Hence the filter class will be,

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

    class Meta:
        model = WriterFilter
        fields = ['article']

Upvotes: 12

Ngoc Pham
Ngoc Pham

Reputation: 1458

You can try like this. My class custom your filter with new param. Your api must have extra param . In this case is ?article_name='example'

class WriteFilter(django_filters.rest_framework.FilterSet):
    class Meta:
        model = WriterFilter
        fields = ['article_name']
    article_name = ArticleFilter(name="article_name")

class ArticleFilter(django_filters.Filter):
    def filter(self, qs, value):
        return qs.article_set.filter(name=value)

If you run queryset, it will get all Writer with article name is 'example'.

Hoop this help

Upvotes: 2

Related Questions