【问题标题】:Objects filtered by ManyToManyField_in do not contain the rest of ManyToMany field values, how to get them?ManyToManyField_in过滤的对象不包含剩余的ManyToMany字段值,如何获取?
【发布时间】:2015-11-18 07:44:18
【问题描述】:

一段时间以来,我一直在努力寻找问题的答案,但找不到我真正需要的答案。

我最近开始搞乱 Django(我已经搜索了文档),直到现在一切都很好。我正在制作一个简单的画廊应用程序,想法很简单,每张图片都有一堆标签。我想建立一个标签列表(那里没问题),然后选择一个标签 - 获取所有图像的相关标签列表 - 我有一个问题,看看我的视图代码:

def getTagList(request):
    images = Image.objects.all()
    imgsWithTag = images.filter(tags__name__in=["space"]).only('tags')
    allTags = imgsWithTag.values_list('tags__name', flat=True)

在这里 - 我希望 allTags 是所有图像标签的列表(包括示例中的“空格”) - 相反我得到:

[u'space', u'space']

对于我在数据库中的两个图像。每张图片都包含两个标签(“空格”是常见的标签),但据我所知,只有“匹配”标签被返回。

这里到底发生了什么以及如何避免它?有没有更好的方法来做我想做的事?

我的模型如下:

class Tag(models.Model):
    name = models.CharField(max_length=60, primary_key=True)
    def __unicode__(self):
        return self.name

class Image(models.Model):
    title = models.CharField(max_length=60)
    image = models.ImageField(upload_to="images/")
    tags = models.ManyToManyField(Tag, blank=True)
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    def thumbnail(self):
        return '<img src="%s" height="40" />' % (self.image.url)
    thumbnail.short_description = 'Image'
    thumbnail.allow_tags = True

    def get_tags(self):
        return ", ".join([x.name for x in self.tags.all()])

    def url(self):
        return self.image.url

    def __unicode__(self):
        return self.title

谢谢。

【问题讨论】:

    标签: django filter models manytomanyfield


    【解决方案1】:

    这是正常行为,因为 django 在后台使用 JOIN 进行 SQL 查询。

    要获取所有相关标签,您可以使用它(假设:您的标签模型命名为Tag,ManyToMany 的相关名称与标签连接图像为images:

    def getTagList(request):
        images = Image.objects.all()
        imgsWithTag = images.filter(tags__name__in=["space"])
        allTags = Tag.objects.filter(images__in=imgsWithTag).values_list('tags__name', flat=True)
    

    起初看起来 django 会执行 2 次查询:第一次获取所有图像,然后第二次获取与该图像关联的所有标签,但事实并非如此。

    Django 足够聪明,可以将这些查询连接在一起,因此您将在WHERE 上获得一个带有嵌套选择的查询。所以你只会打数据库一次。如果您希望它被调用两次(有时更好),您可以这样做:

    def getTagList(request):
        images = Image.objects.all()
        imgsWithTag = images.filter(tags__name__in=["space"]).values_list('id', flat=True)
        allTags = Tag.objects.filter(images__id__in=imgsWithTag).values_list('tags__name', flat=True)
    

    【讨论】:

    • 感谢您的回答。但是,我没有将每个标签与图像列表相关联的字段——这个想法对我来说并不正确。在这种情况下,Id 方法也不起作用。
    • 是的,除非您在将图像与标签链接的多对多字段中指定了 related_name='+',否则您有。看docs
    猜你喜欢
    • 2021-12-02
    • 2021-09-29
    • 1970-01-01
    • 1970-01-01
    • 2012-04-19
    • 1970-01-01
    • 1970-01-01
    • 2021-12-27
    • 2022-01-11
    相关资源
    最近更新 更多