Дубликаты экземпляров не удаляются из набора запросов
Я столкнулся с проблемой, связанной с набором запросов, возвращаемых в методе get_tag_posts
внутри модели Profile
. При использовании запроса в том виде, в котором он написан, он не удаляет дубликаты, даже если вызывается метод .distinct()
.
Краткая иллюстрация проблемы:
- Вопрос 1 - тег A
- Вопрос 2 - Метка A
- Вопрос 3 - тег A, тег B
Когда вызывается get_tag_posts
, он включает следующий набор запросов:
<QuerySet [<Tag: A>, <Tag: A>, <Tag: A>, <Tag: B>]>
Однако я ожидаю, что набор запросов будет возвращен в виде: <QuerySet [<Tag: A>, <Tag: B>]>
После этого каждый экземпляр аннотируется, чтобы подсчитать, сколько раз данный тег был размещен пользователем. Почему в этом случае не удаляются дубликаты одного экземпляра?
class Profile(Model):
user = OneToOneField(settings.AUTH_USER_MODEL, on_delete=CASCADE)
def get_tag_posts(self, order_by=None):
if not order_by:
order_by = "-question__date"
elif order_by == "name":
pass
else:
order_by = "-score"
questions_with_tag = Subquery(self.questions.filter(
tags__name=OuterRef("name")).only('id'))
tags = Tag.objects.filter(
question__profile=self
).distinct().order_by(order_by)
return {
'records': tags.annotate(times_posted=Count(questions_with_tag)),
'title': f"{tags.count()} Tags"
}
class Tag(Model):
name = CharField(unique=True, max_length=25)
class Post(Model):
body = TextField()
date = DateTimeField(default=timezone.now)
comment = ForeignKey('Comment', on_delete=CASCADE, null=True)
profile = ForeignKey(
'authors.Profile', on_delete=SET_NULL, null=True,
related_name='%(class)ss',
related_query_name="%(class)s"
)
vote = GenericRelation(
'Vote', related_query_name="%(class)s"
)
score = IntegerField(default=0)
class Question(Post):
title = CharField(
max_length=80, unique_for_date="date",
help_text="Concisely state the problem you're having",
error_messages={
"max_length": "The title of your question is too long"
}
)
tags = ManyToManyField(
'Tag', related_name="questions", related_query_name="question"
)
views = IntegerField(default=0)
visible = BooleanField(default=True)
objects = Manager()
postings = QuestionSearchManager()
searches = QueryStringSearchManager()
Отношения "многие ко многим" на самом деле включают 3 таблицы. В вашем примере: Вопросы, Теги, Question_Tag_Relations
Question_Tag_Relations
PK | Question_PK | Tag_PK |
---|---|---|
1 | 1 | 1 |
2 | 2 | 1 |
3 | 3 | 1 |
4 | 3 | 2 |
Когда вы захватываете distinct()
, вы захватываете Distinct PKs в этой таблице отношений, а не сами теги.
Поэтому вам нужно получить tag_pk (не знаю конкретного названия столбца)
.
Некоторые БД поддерживают разделение по столбцам, например: ~.distinct('tag_pk')
Но если ваша БД этого не поддерживает, то вам, возможно, придется сделать так: ~.values_list('tags').distinct()
... Я считаю, что это дополнительный запрос
Это было бы моим предположением: Tags.objects.filter(pk__in=self.questions.values_list('tags').distinct())