如何自定义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字段匹配过滤:
- 定义自定义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字段的值,而非默认的IDlookup_expr='exact':表示精确匹配标签文本,若需模糊匹配可改为icontains
- 更新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
- 支持多标签过滤(可选)
如果需要同时过滤包含多个标签的文章(如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
相关产品推荐
相关产品推荐

