在 Django 多对多关系中添加属性

G. *_*ide 1 python django python-3.x django-rest-framework

我有以下 Django 模型:

class Lesson(models.Model):
    title = models.TextField()

class Course(models.Model):
    lessons = models.ManyToManyField(Lesson)

class User(AbstractUser):
    favorites = models.ManyToManyField(Lesson)
Run Code Online (Sandbox Code Playgroud)

我有一条路线 /courses/course_id 返回课程详细信息,包括一系列课程(使用 Django Rest Framework)

我如何根据我的用户收藏夹在课程对象中返回附加属性收藏夹。

我尝试了以下操作:

course = self.get_object(course_id)
favorites = request.user.favorites

for lesson in course.lessons.all():
    if lesson in favorites.all():
        lesson.favorite = True

serializer = CourseDetailSerializer(course, context=serializer_context)
return Response(serializer.data)
Run Code Online (Sandbox Code Playgroud)

但是返回时就不起作用了:

(django.core.exceptions.ImproperlyConfigured:字段名称favorite对于 model 无效Lesson

我的序列化器:

class CourseDetailSerializer(serializers.HyperlinkedModelSerializer):
    lessons = LessonListSerializer(many=True, read_only=True)

    class Meta:
        model = Course
        fields = ('id', 'lessons', 'name', 'title')


class LessonSerializer(serializers.ModelSerializer):
    class Meta:
        model = Lesson
        fields = ('id', 'title', 'duration', 'favorite')
Run Code Online (Sandbox Code Playgroud)

小智 5

如果未定义对象,则无法向对象添加属性,如下所示:

lesson.favorite = True
Run Code Online (Sandbox Code Playgroud)

当您创建 M2M 关系时:

favorites = models.ManyToManyField(Lesson)
Run Code Online (Sandbox Code Playgroud)

... django 创建虚拟模型,仅存储两个模型中的主键对。这种关系在数据库中可能如下所示:

  id  | user_id       | lesson_id 
------+---------------+----------
  151 |            11 |     3225
  741 |            21 |     4137
Run Code Online (Sandbox Code Playgroud)

我认为您想要实现的是添加有关此关系的额外信息。因此,您需要使用该额外字段创建中介模型,即:

class User(AbstractUser):
     favorites = models.ManyToManyField(Lesson, through='UserLessons')

class UserLessons(models.Model):
     user = models.ForeignKey(User)
     lesson =  models.ForeignKey(Lesson)
     favorite = models.BooleanField(default=False)
Run Code Online (Sandbox Code Playgroud)