首页 > 解决方案 > 如何在没有重复字段的情况下注释字段 django

问题描述

所以我基本上有这个简单的模型:

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()

与shows_users中的User模型存在多对多关系

我想根据多对多表注释 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 个课程,这意味着我要获取所有 50000 个字段然后过滤其中的 50 个 :(

有没有更清洁的方法来做到这一点?

2.区别:

我之前尝试过 distinct 并没有解决问题,而不是显示三遍课程,它将显示:

标签: djangodjango-modelsdjango-orm

解决方案


我设法解决了这个问题,如果发现我的多对多查询方式是问题所在,而不是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)

推荐阅读