You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自定义DRF多对多字段查询参数过滤(用标签名而非ID)

问题

我正在使用DRF构建REST API,需要实现按标签(hashtag)过滤文章的功能,期望请求URL格式为article/list?hashtags=dobi,但目前只能通过ID(如article/list?hashtags=13)过滤。现有代码如下:

models.py

class Article(AbstractTimeStamp):
    user = models.ForeignKey('users.User', on_delete=models.CASCADE)
    title = models.CharField(max_length=300,blank=False)
    content = models.TextField(max_length=1000)
    hashtags = models.ManyToManyField('Hashtag', max_length=200, related_name='articles', blank=True)


class Hashtag(models.Model):
    hashtag = models.CharField(max_length=200, unique=True, blank=True)

serializers.py

class ListSerializer(serializers.ModelSerializer):
    hashtags = HashtagsSerializer(many=True)

    class Meta:
        model = Article
        fields = ['id','title','hashtags']

views.py

class ArticleListAPIView(generics.ListAPIView):
    queryset = Article.objects.all()
    serializer_class = ListSerializer
    filter_backends = [filters.SearchFilter,DjangoFilterBackend]

    search_fields = ['title']

    filterset_fields = ['hashtags']

尝试在ListAPIView中设置lookup_url_kwarg = ['hashtags']但无效,请问该如何修改实现需求?


解决方案

要实现通过标签文本而非ID过滤,需要自定义FilterSet,指定按Hashtag模型的hashtag字段匹配过滤:

  1. 定义自定义FilterSet
    在app目录下新建filters.py(或在现有文件中添加),编写如下代码:
import django_filters
from .models import Article, Hashtag

class ArticleFilter(django_filters.FilterSet):
    hashtags = django_filters.ModelChoiceFilter(
        field_name='hashtags__hashtag',
        to_field_name='hashtag',
        queryset=Hashtag.objects.all(),
        lookup_expr='exact'
    )

    class Meta:
        model = Article
        fields = ['hashtags']
  • field_name='hashtags__hashtag':指定关联的Hashtag模型的hashtag字段作为过滤依据
  • to_field_name='hashtag':指定从URL参数中接收的是hashtag字段的值,而非默认的ID
  • lookup_expr='exact':表示精确匹配标签文本,若需模糊匹配可改为icontains
  1. 更新View的过滤配置
    修改views.py,将原有的filterset_fields替换为自定义的filterset_class:
class ArticleListAPIView(generics.ListAPIView):
    queryset = Article.objects.all()
    serializer_class = ListSerializer
    filter_backends = [filters.SearchFilter,DjangoFilterBackend]

    search_fields = ['title']
    # 替换filterset_fields为自定义FilterSet
    filterset_class = ArticleFilter
  1. 支持多标签过滤(可选)
    如果需要同时过滤包含多个标签的文章(如article/list?hashtags=dobi&hashtags=python),将ModelChoiceFilter改为ModelMultipleChoiceFilter即可:
class ArticleFilter(django_filters.FilterSet):
    hashtags = django_filters.ModelMultipleChoiceFilter(
        field_name='hashtags__hashtag',
        to_field_name='hashtag',
        queryset=Hashtag.objects.all(),
        lookup_expr='exact'
    )

    class Meta:
        model = Article
        fields = ['hashtags']

完成以上修改后,即可通过article/list?hashtags=dobi的格式请求,获取包含指定标签的文章列表。

内容的提问来源于stack exchange,提问作者giwony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 20:57:21