【问题标题】:django get list of distinct 'children' of ForeignKey related model (and do this in template?)django 获取 ForeignKey 相关模型的不同“孩子”列表(并在模板中执行此操作?)
【发布时间】:2012-04-23 05:41:39
【问题描述】:

我正在制作已发行音乐专辑的数据库

models.py

class Image(models.Model):
    image = models.ImageField(....

class Album(models.Model):
    title = models.CharField(....

class Release(models.Model):
    album = models.ForeignKey(Album)
    cover_art = models.ForeignKey(Image, blank=True, null=True, on_delete=models.SET_NULL)

在我的模板中(目前我正在使用通用视图)我有:

{% for a in album_list %}
    {% for r in a.release_set.all %}
        {% if r.cover_art %}
        # display cover art image
        {% endif %}
    {% endfor %}
{% endfor %}

问题是,有时一张专辑已经发行了好几次,封面都是一样的,在这种情况下,我只想显示一次图片,并用一些文字列出它所属的发行版。

我试过了:

{% for i in a.release_set.cover_art %}
{% for i in a.release_set.cover_art_set %}
{% for i in a.release_set.all.cover_art %}
{% for i in a.release_set.all.cover_art_set %}

或者在更简单的情况下,如果有多个图像,我至少希望将图像显示得更小。

{% if a.release_set.count > 1 %} # works but displays duplicate images
{% if a.release_set.cover_art_set.count > 1 %} # doesn't work (see above)

是否可以通过反转此 ForeignKey 查找然后询问其孩子的集合来获得相关对象的列表?我能想到的唯一方法是在视图中组装一些元组/列表。

【问题讨论】:

    标签: django django-templates foreign-keys django-generic-views


    【解决方案1】:

    我在 Album 模型上使用了一种新方法来解决这个问题:

    class Album(models.Model):
        title = models.CharField(....
    
        def distinct_cover_images(self):
            "Returns the queryset of distinct images used for this album cover"
            pks = self.release_set.all().values_list('cover_art__pk', flat=True)
            distinct_cover_images = Images.objects.filter(pk__in=pks).distinct()
            return distinct_cover_images
    

    那么模板就简单多了:

    {% for i in a.distinct_cover_images %}
    

    感谢@danilobargen,感谢他对这段代码的贡献。

    【讨论】:

    • 啊,当然,这让我有点不知所措:) 很好的解决方案。
    • 很好的答案...好主意,但我的实施有问题。我的ForeginKey 关系与另一个应用程序中的不同模型有关。我认为这仍然有效,只需简单地导入该模型,但看起来它会在关系中涉及的两个应用程序上触发ImportError。有什么想法吗?
    • 听起来可能是循环导入,特别是如果在其他应用程序中定义了外键,因为该应用程序已经从该模块导入模型。在这里,您可以尝试将 import 语句 from other_app import model 移动到函数定义内部,即在 def distinct_cover_images(self) 下方的行上
    【解决方案2】:

    如果我理解正确:

    • 一张专辑可以有多个版本
    • 一个版本只有一个封面
    • 您想遍历专辑的所有封面

    在这种情况下,以下应该有效:

    {% for release in a.release_set.all %}
      {{ release.cover_art.image }}
    {% endfor %}
    

    如果您想防止列出相同的封面,您可以在循环中比较封面,或者在您的视图中准备一个具有不同封面的集合,以便您可以将其传递给模板。

    # Solution using a set
    context['distinct_coverimages'] = \
        set([r.cover_art.image for r in album.release_set.all()])
    
    # Solution using two queries, might perform better
    pks = album.release_set.values_list('cover_art__pk', flat=True)
    context['distinct_coverimages'] = models.Image.filter(pk__in=pks).distinct()
    

    第三种选择是为您的专辑创建一个自定义模板过滤器,以返回所有不同的发行封面。

    无论如何,我建议在你的 Django shell 中调试这些东西。您可以使用./manage.py shell 发出shell。如果你已经安装了django-extensions,你也可以使用./manage.py shell_plus来自动加载所有模型。所有不需要参数的对象属性和函数(例如,普通实例属性或没有参数的实例函数,如 'string'.isalnum())也可以在模板中以相同的方式使用(只是不带括号)。

    【讨论】:

    • 是的,抱歉,我应该更清楚一点:我已经有了一个带有 的工作 forloop。这是我要删除的重复项。
    • @nimasmi 查看我对示例的编辑以获取可能的解决方案。
    • @nimasmi 我刚刚用另一个解决方案编辑了我的答案,该解决方案阻止了使用列表推导和集合。
    • 谢谢。我不知道你的context['...'] 代码是做什么的。我在视图中尝试了它,在一个 forloop 中(我必须为Collection.objects.all() 这样做),并得到 NameError。我尝试了from django.template import Context 然后Context['...'] 并得到了 TypeError: 'type' object does not support item assignment。我保证我已经搜索过了,但是这条线在做什么?
    • 为了记录,比较循环中的封面的第一个建议不会因为它们不一定相邻而失败吗?例如使用{% ifchanged r.cover_art %}。如果我幸运的话可能会工作。
    猜你喜欢
    • 2021-04-15
    • 2020-04-10
    • 2011-08-10
    • 1970-01-01
    • 2018-05-25
    • 1970-01-01
    • 1970-01-01
    • 2015-01-26
    • 2013-08-25
    相关资源
    最近更新 更多