Как аннотировать поля без дубликатов полей Django - PullRequest
0 голосов
/ 24 мая 2018

Таким образом, у меня в основном есть эта простая модель:

class BaseLesson(models.Model):
    YOUTUBE_VIDEO = '0'
    MARKDOWN = '1'

    TYPE_CHOICES = (
        (YOUTUBE_VIDEO, 'youtube-video'),
        (MARKDOWN, 'markdown'),
    )

    type = models.CharField(
        max_length=10, choices=TYPE_CHOICES, default=MARKDOWN, verbose_name=_('type'))

    shown_users = models.ManyToManyField(
        User, related_name='lessons', verbose_name=_('shown users'), blank=True)

    objects = managers.BaseLessonManager()

Существует много-много отношений с моделью User в selected_users

И я хочу аннотировать статус is_shown на основетаблица «многие ко многим», поэтому я сделал это:

class BaseLessonManager(InheritanceManager, CachingManager):
    def get_lesson_with_is_shown(self, user):

        shown_user_case = django_models.Case(
            django_models.When(shown_users__id=user.id,
                               then=django_models.Value(True)),
            default=django_models.Value(False),
            output_field=django_models.BooleanField())

        return self.get_queryset().annotate(
            is_shown=shown_user_case)

Проблема в том, что если user1 и user2 видели один и тот же урок, он будет повторяться, например:

+-----------------+-----------+
|    lesson_id    |  user_id  |
+-----------------+-----------+
|        1        |     1     |
|        1        |     2     |
|        1        |     3     |
+-----------------+-----------+

В таком случае я получу следующие повторяющиеся уроки:

            {
                "id": 1
                "type": "0",
                "is_shown": true
            },
            {
                "id": 1
                "type": "0",
                "is_shown": false
            },
            {
                "id": 1
                "type": "0",
                "is_shown": false
            }

Итак, он проверяет каждое связанное поле урока в таблице SHOWN_USERS ... пример фотографии: https://imgur.com/GJCPWjk

Что я пробовал до сих пор:

1.Исключить:

Я добавил выражение исключения, чтобы избавиться от лишних уроков:

return self.get_queryset().annotate(
       is_shown=shown_user_case).exclude(
       django_models.Q(is_shown=False) & django_models.Q(shown_users__id=user.id))

И я думаю, что это очень уродливо, потому что у меня 1000 пользователей и 50 уроков, это означает, что я 'm, взяв все 50000 полей, затем отфильтруйте 50 из них: (*

Есть ли какой-нибудь более чистый способ сделать это?

2. Отличительный:

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

  • один раз (is_shown = True),
  • и другой раз (is_shown = False)

Вот репозиторий github, если вы хотите поэкспериментировать: https://github.com/coretabs-academy/website-v2

1 Ответ

0 голосов
/ 12 июля 2018

Мне удалось решить проблему, и если выяснилось, что мой способ запроса «многие ко многим» - это проблема, вместо shown_users__id == user.id я использовал id__in==user.lessons.values('id'), полный код:

class BaseLessonManager(InheritanceManager, CachingManager):
    def with_is_shown(self, user):

        user_shown_lessons = user.lessons.values('id')

        shown_user_case = django_models.Case(
            django_models.When(id__in=user_shown_lessons,
                           then=django_models.Value(True)),
            default=django_models.Value(False),
            output_field=django_models.BooleanField())

        return self.get_queryset().annotate(
            is_shown=shown_user_case)
...