我正在努力弄清楚如何使用" field__contains"来运行queryset过滤器。在SlugRelatedField上。 我有一个简单的Book模型和Tag模型,如下所示:
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_tags值过滤查询集。我已经尝试了以下内容" __包含"字段查找:
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_lookup中 引发FieldError('相关字段无效查找:{}' .format(lookup_name)) django.core.exceptions.FieldError:相关字段无效查找:包含
据我所知,这意味着,因为" meta_tags"不是常规数组或文本字段,包含字段查找不能应用于该字段。
对于meta_tags值,在这种情况下过滤查询集的最佳方法是什么?
答案 0 :(得分:0)
一位django专家我已经就这个问题进行了咨询,建议尝试追加" slug_field" (" __值"在这种情况下)到" __包含"与外部模型一起使用时的字段查找。
它没有在任何地方记录,甚至没有在https://docs.djangoproject.com/en/2.0/ref/contrib/postgres/fields/#contains的django官方文档中记录,所以我无法知道它的工作原理,但这个解决方案确实有效:
queryset = queryset.filter(meta_tags__value__contains=search_pattern)
当你深入研究MetaTag模型时,它实际上是有道理的,因为"价值"是meta_tags模型的内部字段:
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)
首先附加__value并不是那么明显的原因是因为meta_tags数组(对象数组)使用SlugRelatedField序列化器展平,其中只投影slug_field而其余字段被省略。 所以meta_tags数组的最终输出是平的:
meta_tags: ['tag1','tag2']
而不是:
meta_tags: [{book: 'a', value: 'tag1'},{book: 'a', value: 'tag2'}]
但是由于django DRF上的序列化是在后期(在查询集完成之后)进行的,因此应该考虑原始字段模式。
希望有一天这会让人感到头疼。