Skip to main content
 首页 » 编程设计

python之Django,只从相关对象中获取唯一值

2024年09月07日38JeffreyZhao

我希望我可以在我的网站列表中呈现最常用的标签,我确实这样做了。问题是,显示的标签经常重复,我相信如果只显示唯一的标签会好得多。

在我的模型中,我编写了方法 unique_tags

class ArticleTag(models.Model): 
    article = models.ForeignKey('ep.Article', on_delete=models.CASCADE, related_name='tags') 
    tag = models.ForeignKey('ep.Tag', on_delete=models.CASCADE) 
 
    def unique_tags(self): 
        return self.objects.values_list('tag').distinct() 

当我在 python shell 中测试它时它工作正常。但它不呈现任何标记。我的模板如下所示:

            <div class="widget-tags"> 
          <ul> 
            {% for prev_article in object.articles.all %} 
            {% for article_tag in prev_article.article.tags.all.unique_tags %} 
            <li><a href="#">{{article_tag.tag.verbose_name}}</a></li> 
            {% endfor %} 
            {% endfor %} 
          </ul> 
        </div> 

对象来自与 Article 表和 Field 表建立关系的模型,所以使用 object.articles.all 我得到了与特定领域相关的文章的所有实例。我使用 detail在我看来。

那么,我的第一个问题是,这种方法有效吗?我的意思是,在模型类中添加新方法,或者也许我应该在 View 中添加它?而且我仍然对 django 模板语言不满意,所以可能存在问题。而且我知道模板中有这个过滤器,如 {{ some_object | function}} 但我读到,在模板中尽可能少地保留逻辑是一种很好的做法。

请您参考如下方法:

如果您想这样做,我会在 Article 级别添加逻辑::

class Article(models.Model): 
 
    def unique_tags(self): 
        return Tag.objects.filter(articletag__article=self).distinct()

然后查询:

{% for article_tag in <b>prev_article.unique_tags</b> %} 
    <li><a href="#">{{article_tag.tag.verbose_name}}</a></li> 
{% endfor %}

通过使用 .values_list,您将获得主键的值,因此通常是 int(或给定的其他原始类型你自己定义了一个主键)。

话虽如此,我认为最好通过添加 unique_together [Django-doc] 来确保这永远不会发生。模型中的约束:

class ArticleTag(models.Model): 
    article = models.ForeignKey( 
        'ep.Article', 
        on_delete=models.CASCADE, 
        related_name='tags' 
    ) 
    tag = models.ForeignKey('ep.Tag', on_delete=models.CASCADE) 
 
    class Meta: 
        <b>unique_together = ('article', 'tag')</b>

因此,现在您可以简单地不为同一篇文章标记两次相同的标签。因此,一旦强制执行,您可以简单地使用:

<!-- given unique_together is enforced --> 
 
{% for article_tag in <b>prev_article.tags.all</b> %} 
    <li><a href="#">{{article_tag.tag.verbose_name}}</a></li> 
{% endfor %}

然后您可以使用 .prefetch_related(..) 加载所有具有恒定数量查询的相关对象。