Django-仅在存在字段时删除重复项

Posted

技术标签:

【中文标题】Django-仅在存在字段时删除重复项【英文标题】:Django- Remove duplicates only if a field is present 【发布时间】:2016-10-06 00:34:27 【问题描述】:

我有两个模型:

class BookSeries(models.Model):
    title = models.CharField(max_length=200, null=False, blank=False, unique=True)
    #extra fields

class Book(models.Model):
    series = models.ForeignKey(BookSeries, blank=True, null=True, default=None)
    publisher = models.ForeignKey(Publisher, default=None, null=True, blank=True)
    title = models.CharField(max_length=200, null=False, blank=False, unique=True)
    #extra fields

现在我想查询所有不属于系列的书,并且只查询属于同一系列的任何一本书(系列可以为空)。

问题陈述:

我想查询所有单独的书籍和系列。 由于一个系列可以有多本书,而一本书可能不属于一个系列。一种解决方案是查询所有书籍对象(不属于系列)并查询所有系列对象,如here 所述。但这会将所有系列和书籍放在一起作为响应。我不希望它们被组合在一起(我也在使用分页)。

类似:Book.objects.filter( disctinct only if(series is not None))

我曾想过使用 distinct 和 exclude 但无法实现。

【问题讨论】:

您使用的是哪个数据库? 【参考方案1】:

如果 series 为 None,首先排除所有,然后调用 distinct() 返回一个列表。

Book.objects.exclude(series=None).distinct('series')

如果您需要排除空值和空字符串,首选方法是将条件链接在一起,如下所示: Book.objects.exclude(series__isnull=True).exclude(series__exact='')

您可以关注这个帖子以更好地理解Filtering for empty or NULL names in a queryset

【讨论】:

这只会提供不属于系列的书籍,我还想要系列中的一本书。正如 AKS 建议的那样【参考方案2】:

我建议以下方法:

    获取不属于series的所有书籍的id:

    ids_list1 = list(Book.objects.filter(series=None).values_list('id', flat=True))
    

    获取属于series的所有书籍的id,并且只使用distinct获取:

    ids_list2 = list(Book.objects
                         .exclude(series=None)   # exclude ones which are not in a series
                         .order_by('series')     # order by series
                         .distinct('series')     # keep the first book in each series
                         .values_list('id', flat=True))
    

现在,您可以组合这两个列表并进行另一个查询以仅返回具有这些 id 的书籍:

ids = id_list1 + id_list2
books = Book.objects.filter(id__in=ids)

【讨论】:

以上是关于Django-仅在存在字段时删除重复项的主要内容,如果未能解决你的问题,请参考以下文章

使用postgresql TEXT类型按字段排序时如何删除重复项?

用SQL语句,删除掉重复项只保留一条

如何删除这些重复项?

Spark - 在json数组字段中删除重复项[重复]

如何根据某个字段从数据库表中删除重复项

如果键存在则删除字典项[重复]