Django: QuerySet с группой одинаковых записей - PullRequest
0 голосов
/ 15 октября 2019

Моя цель - показать для конкретного опроса 10 лучших «сущностей» в каждом вопросе, упорядоченных по значимости. У опроса есть несколько вопросов. И на каждый вопрос есть несколько ответов. Каждый ответ может иметь несколько сущностей (иногда одинаковые name (CharField), иногда разные name с). Сущности сгруппированы по полю name для каждого вопроса.

Я думал, что следующий конечный результат имеет смысл:

[
    5:  # question.pk
    [
        {
            'name': 'Leonardo Di Caprio',
            'count': 4,  # E.g. answer__pk = 1, answer__pk = 1, answer__pk = 2, answer__pk = 3. Leonardo Di Caprio was mentioned twice in answer_pk 1 and therefore has entries.
            'salience': 3.434  # Sum of all 4 entities
        },
        {
            'name': 'titanic',
            'count': 5,
            'salience': 1.12
        },
        {
            'name': 'music',
            'count': 3,
            'salience': 1.12
        }
    ],
    3:  # question.pk
    [
        {
            'name': 'Leonardo Di Caprio',
            'count': 5,
            'salience': 1.5
        },
        {
            'name': 'titanic',
            'count': 4,
            'salience': 1.12
        },
        {
            'name': 'music',
            'count': 2,
            'salience': 1.12
        }
    ],
]

Теперь я пытаюсь написать правильный QuerySet для моего желаемого результата. Кто-нибудь здесь, кто может помочь мне с этим? Я пришел к выводу, что мне, вероятно, придется использовать .values() и .annotate(). Но мои результаты весьма далеки от моей цели.

Здесь мои models.py:

class Entity(TimeStampedModel):
    name = models.CharField()
    type = models.CharField()
    salience = models.FloatField()
    sentiment_magnitude = models.FloatField()
    sentiment_score = models.FloatField()
    language = models.CharField()
    answer = models.ForeignKey(
        Answer, on_delete=models.CASCADE, related_name="entities"
    )

class Answer(TimeStampedModel):
    question = models.ForeignKey(
        "surveys.Question", on_delete=models.CASCADE, related_name="answers"
    )
    response = models.ForeignKey()
    answer = models.TextField()

class Question(TimeStampedModel):
    survey = models.ForeignKey(
        "surveys.Survey", on_delete=models.CASCADE, related_name="questions"
    )
    title = models.CharField(max_length=100, verbose_name=_("Title"))
    focus = models.CharField()

class Response(TimeStampedModel):
    survey = models.ForeignKey(
        "surveys.Survey", on_delete=models.CASCADE, related_name="responses"
    )
    order = models.ForeignKey()
    attendee = models.ForeignKey()
    total_time = models.PositiveIntegerField()
    ip_address = models.GenericIPAddressField()
    language = models.CharField()

class Survey(TimeStampedModel):
    id = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4)
    event = models.ForeignKey()
    template = models.CharField()

Вот что я пытался до сих пор. Но это, похоже, далеко от моей цели:

questions = self.request.event.surveys.get_results(
    settings.SURVEY_PRE_EVENT
)

for question in questions:
    print("------")
    print(question.pk)

    answers = question.answers.all()
    for answer in answers:
        print(
            answer.entities.values("name")
            .annotate(count=Count("name"))
            .annotate(salience=Sum("salience"))
        )

Вот вывод:

------
33
<QuerySet [{'name': 'people', 'count': 1, 'salience': 1.0}]>
<QuerySet [{'name': 'income', 'count': 1, 'salience': 1.0}]>
<QuerySet [{'name': 'incomes', 'count': 2, 'salience': 1.26287645101547}]>

Ответы [ 2 ]

1 голос
/ 15 октября 2019

Я не совсем уверен, правильно ли я понял вашу проблему, но вы, возможно, ищете что-то вроде

Question.objects.values("answers__entities__name").annotate(
    salience=Sum("answers__entities__salience"),
    count=Count("answers"),
)

Отказ от ответственности: я не проверял это, и я могу ошибаться, но этос чем бы я начал играть.

Также вы можете найти это полезным: https://simpleisbetterthancomplex.com/tutorial/2016/12/06/how-to-create-group-by-queries.html

0 голосов
/ 15 октября 2019

Вы можете перебирать вопросы, чтобы создать список для каждого вопроса:

Entity.objects.filter(answer__question=question).values('name').annotate(count=Count('pk')).annotate(total_salience=Sum('salience'))

Или, если вы хотите, чтобы все были в одном наборе запросов, сгруппируйте сначала по вопросу (pk):

Entity.objects.values('answer__question__pk', 'name').annotate(count=Count('pk')).annotate(total_salience=Sum('salience'))

Это создаст список, а не вложенный список по вопросу, но вы можете позже перегруппировать его в python, чтобы вложить сущности для каждого вопроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...