Django 多对多模型 DRF

Django many-to-many model DRF

我有以下模型结构:

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)

调用视图函数后,在数据库中创建了一个分类器。但在那之后,我收到以下错误:

TypeError: 'Account' object is not iterable

这一行抛出错误:

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

谁能帮我解决这个问题?

处理多重关系时需要设置many=True - m2m 或反向 FK:

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

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

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。

请检查...

你的model.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')

你的serializer.py

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']

最后你的view.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)

这里有两个问题:

  1. 显示 nested relationships M2M 字段:

If the field is used to represent a to-many relationship, you should add the many=True flag to the serializer field.

所以你需要将many=True添加到AccountSerializer:

author = AccountSerializer(read_only=True, required=False, many=True)
  1. 一个writable nested serializer:

By default nested serializers are read-only. If you want to support write-operations to a nested serializer field you'll need to create create() and/or update() methods in order to explicitly specify how the child relationships should be saved.

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