Python Django多对多模型DRF

Python Django多对多模型DRF,python,django,django-models,django-rest-framework,django-orm,Python,Django,Django Models,Django Rest Framework,Django Orm,我有以下模型结构: class Project(models.Model): author = models.ManyToManyField(Account) name = models.CharField(max_length=40, default='NewBook') class Account(AbstractBaseUser): email = models.EmailField(unique=True) username = models.CharField(max

我有以下模型结构:

class Project(models.Model):
  author = models.ManyToManyField(Account)
  name = models.CharField(max_length=40, default='NewBook')

class Account(AbstractBaseUser):
  email = models.EmailField(unique=True)
  username = models.CharField(max_length=40, unique=True)
  first_name = models.CharField(max_length=40, blank=True)
  last_name = models.CharField(max_length=40, blank=True)
  tagline = models.CharField(max_length=140, blank=True)
  is_admin = models.BooleanField(default=False)
  created_at = models.DateTimeField(auto_now_add=True)
  updated_at = models.DateTimeField(auto_now=True)
  objects = AccountManager()
  USERNAME_FIELD = 'email'
  REQUIRED_FIELDS = ['username']
我的观点是这样的:

class ProjectViewSet(viewsets.ModelViewSet):
  queryset = Project.objects.order_by('-name')
  serializer_class = ProjectSerializer

  def perform_create(self, serializer):
    instance = serializer.save(author=self.request.user)
    return super(ProjectViewSet, self).perform_create(serializer)
调用view函数后,将在数据库中创建一个分类器。但在那之后,我得到了以下错误:

TypeError:“帐户”对象不可编辑

在此行中引发错误:

instance = serializer.save(author=self.request.user)

有谁能帮我解决这个问题吗?

在处理多个关系(m2m或反向FK)时,您需要设置
many=True

author = AccountSerializer(read_only=True, required=False, many=True)

由于Author字段是多对多字段,因此需要重写序列化程序上的create方法

def create(self, validated_data):
     author = validated_data.pop(author, None)
     project = Project.objects.save(validated_data)
     if author:
         project.author.add(author)

您可能还需要在序列化程序上设置更新方法,此处的行为可能比较棘手,因此请确保您进行了测试,并确保该行为符合您的预期。

好的,我之前的回答可能是一个问题,但不是实际崩溃的根本原因

调用序列化程序时,可以设置:

instance = serializer.save(author=self.request.user)
但是,作者是
ManyToManyField
,这意味着您应该将序列化程序称为:

instance = serializer.save(author=[self.request.user])
注意:您仍然需要序列化程序的作者字段中的many=True。

请检查

您的型号.py

class Account(AbstractBaseUser):
  email = models.EmailField(unique=True)
  username = models.CharField(max_length=40, unique=True)
  first_name = models.CharField(max_length=40, blank=True)
  last_name = models.CharField(max_length=40, blank=True)
  tagline = models.CharField(max_length=140, blank=True)
  is_admin = models.BooleanField(default=False)
  created_at = models.DateTimeField(auto_now_add=True)
  updated_at = models.DateTimeField(auto_now=True)
  objects = AccountManager()
  USERNAME_FIELD = 'email'
  REQUIRED_FIELDS = ['username']


class Project(models.Model):
      author = models.ManyToManyField(Account)
      name = models.CharField(max_length=40, default='NewBook')
class ProjectSerializer(serializers.ModelSerializer):
    author = AccountSerializer(read_only=True, required=False)

    class Meta:
        model = Project
        fields = ('id', 'author', 'name')
        read_only_fields = ('id')

    def get_validation_exclusions(self, *args, **kwargs):
        exclusions = super(ProjectSerializer, self).get_validation_exclusions()
        return exclusions + ['author']
您的序列化程序.py

class Account(AbstractBaseUser):
  email = models.EmailField(unique=True)
  username = models.CharField(max_length=40, unique=True)
  first_name = models.CharField(max_length=40, blank=True)
  last_name = models.CharField(max_length=40, blank=True)
  tagline = models.CharField(max_length=140, blank=True)
  is_admin = models.BooleanField(default=False)
  created_at = models.DateTimeField(auto_now_add=True)
  updated_at = models.DateTimeField(auto_now=True)
  objects = AccountManager()
  USERNAME_FIELD = 'email'
  REQUIRED_FIELDS = ['username']


class Project(models.Model):
      author = models.ManyToManyField(Account)
      name = models.CharField(max_length=40, default='NewBook')
class ProjectSerializer(serializers.ModelSerializer):
    author = AccountSerializer(read_only=True, required=False)

    class Meta:
        model = Project
        fields = ('id', 'author', 'name')
        read_only_fields = ('id')

    def get_validation_exclusions(self, *args, **kwargs):
        exclusions = super(ProjectSerializer, self).get_validation_exclusions()
        return exclusions + ['author']
最后,您的视图.py

class ProjectViewSet(viewsets.ModelViewSet):
  queryset = Project.objects.order_by('-name')
  serializer_class = ProjectSerializer

  def perform_create(self, serializer):
    instance = serializer.save(author=self.request.user)
    return super(ProjectViewSet, self).perform_create(serializer)

这里有两个问题:

  • 显示M2M字段:
  • 如果该字段用于表示多对多关系,则应将
    many=True
    标志添加到序列化器字段

    因此,您需要将
    many=True
    添加到
    AccountSerializer

    author = AccountSerializer(read_only=True, required=False, many=True)
    
  • A:
  • 默认情况下,嵌套序列化程序是只读的。如果要支持对嵌套序列化程序字段的写入操作,则需要创建
    create()
    和/或
    update()
    方法,以明确指定应如何保存子关系


    因此,如果您查看示例和文档,似乎需要实现
    create
    update
    方法。

    您需要向我们展示完整的stacktrace,我们无法判断错误是如何发生的。这是完整的stacktrace@ShangWang,您的序列化程序是什么样子的?这是我的序列化程序@Linovia,谢谢,现在正在创建项目。另一个问题:如何向项目中添加作者?我必须在前端调用.PUT(..)吗?你可以在前端调用
    PATCH
    方法,然后在序列化程序中编写
    update()
    方法来处理这个问题。