Django models DRF-在SlugRelatedField上使用包含字段查找的queryset筛选器

Django models DRF-在SlugRelatedField上使用包含字段查找的queryset筛选器,django-models,django-rest-framework,django-serializer,drf-queryset,Django Models,Django Rest Framework,Django Serializer,Drf Queryset,我正在努力弄清楚如何在SlugRelatedField上使用field__contains来运行queryset过滤器。 我有一个简单的图书模型和一个标签模型,如下所示: class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publica

我正在努力弄清楚如何在SlugRelatedField上使用field__contains来运行queryset过滤器。 我有一个简单的图书模型和一个标签模型,如下所示:

class Book(models.Model):
  title = models.CharField(max_length=100)
  authors = models.ManyToManyField(Author)
  publisher = models.ForeignKey(Publisher)
  publication_date = models.DateField()

class MetaTag(models.Model):
  book = models.ManyToManyField('Book', related_name='meta_tags',
  help_text='The book this meta tag belongs to')
  value = models.CharField(max_length=400, unique=True, help_text='Meta tag value')

class BookSerializer(serializers.HyperlinkedModelSerializer):
  class BookHyperlink(serializers.HyperlinkedIdentityField):
    """A Hyperlink field for book details"""

      def get_url(self, obj, view_name, request, format):
        url_kwargs = {
            'pk': obj.id,
        }
        return reverse(view_name, kwargs=url_kwargs, request=request, format=format)
  url = BookHyperlink(view_name='book-detail')
  meta_tags = CreatableSlugRelatedField(many=True, slug_field='value', queryset=MetaTag.objects.all())

  class Meta:
    model = Book
    fields = (
        'id',
        'title',
        'publisher',
        'publication_date',
        'meta_tags',
        'url'
    )

class MetaTagSerializer(serializers.ModelSerializer):

  class Meta:
    model = MetaTag
    fields = ('id', 'book', 'value',)

class CreatableSlugRelatedField(serializers.SlugRelatedField):

  def to_internal_value(self, data):
    try:
        return self.get_queryset().get_or_create(**{self.slug_field: data})[0]
    except ObjectDoesNotExist:
        self.fail('does_not_exist', slug_name=self.slug_field, value=smart_text(data))
    except (TypeError, ValueError):
        self.fail('invalid')

  class Meta:
    model = MetaTag
    fields = ('id', 'book', 'value', )
现在在我的BooksView中,我希望能够通过meta_标签值过滤queryset。我尝试了以下使用uu包含字段查找的方法:

class Books(viewsets.ModelViewSet):
  """Default view for Book."""

  queryset = Book.objects.all()
  serializer_class = BookSerializer
  permission_classes = (IsAuthenticated, )

  filter_backends = (DjangoFilterBackend,)
  filter_fields = tuple(f.name for f in Book._meta.get_fields())

  def get_queryset(self):

    search_pattern = self.request.query_params.get('search', None)
    if search_pattern is not None and search_pattern is not '':
        self.queryset = self.queryset.filter(meta_tags__contains = search_pattern)
    return self.queryset

def get_object(self):
    if self.kwargs.get('pk'):
        return Book.objects.get(pk=self.kwargs.get('pk'))
但我从django那里得到了以下错误:

文件~MyProject/venv/lib/python3.6/site-packages/django/db/models/sql/query.py,第1076行,在build\u查找中 raise FIELDEROR“相关字段得到无效的查找:{}”。formatlookup\u名称 django.core.exceptions.FieldError:相关字段的查找无效:包含

据我所知,这意味着由于meta_标记不是常规数组或文本字段,因此不能在该字段上应用contains字段查找


在这种情况下,过滤查询集以获取meta_标记值的最佳方法是什么?

我就这个问题咨询过的django专家建议,在这种情况下,尝试将slug_字段值附加到与外部模型一起使用时的u contains字段查找中

它在任何地方都没有文档记录,甚至在django的官方文档中也没有文档记录,因此我无法知道它是以这种方式工作的,但这个解决方案实际上是有效的:

queryset = queryset.filter(meta_tags__value__contains=search_pattern)
当您深入研究MetaTag模型时,它实际上是有意义的,因为值是meta_标记模型的内部字段:

class MetaTag(models.Model):

    book = models.ManyToManyField('Book', related_name='meta_tags',
                                 help_text='The book this meta tag belongs to')
    value = models.CharField(max_length=400, unique=True, help_text='Meta tag value')

    def __str__(self):
        return '%s > %s' % (self.channel, self.value)
首先附加_值不是很明显的原因是,使用SlugRelatedField序列化程序将对象的meta_标记数组展平,其中仅投影slug_字段,而忽略其余字段。 因此meta_标记数组的最终输出是平坦的:

meta_tags: ['tag1','tag2']
而不是:

meta_tags: [{book: 'a', value: 'tag1'},{book: 'a', value: 'tag2'}]
但由于django DRF上的序列化是在queryset完成后的后期进行的,因此应该考虑原始字段模式

希望有朝一日这能让人省去头痛