Django many-to-many model DRF

前端 未结 5 1507
执念已碎
执念已碎 2021-01-26 04:37

I have the following model structure:

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


        
相关标签:
5条回答
  • 2021-01-26 05:10

    Please check...

    your 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')
    

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

    and finally your view.py is

    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)
    
    0 讨论(0)
  • 2021-01-26 05:17

    There are two problems here:

    1. Showing nested relationships for M2M field:

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

    So you need to add many=True to AccountSerializer:

    author = AccountSerializer(read_only=True, required=False, many=True)
    
    1. A 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.

    So if you look at the example and the documentation it seems that you need to implement create or update method.

    0 讨论(0)
  • 2021-01-26 05:23

    Since your Author field is many to many, you will need to override the create method on your serializer.

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

    You will also probably need to set the update method on the serializer, the behavior here can be tricky so make sure you test and make sure the behavior is what you expect.

    0 讨论(0)
  • 2021-01-26 05:23

    Ok, my previous answer, though could be an issue, isn't the root cause of the actual crash.

    When calling the serializer, you set:

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

    However, author is a ManyToManyField which means you should call the serializer as:

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

    NB: you still require the many=True on the serializer's author field.

    0 讨论(0)
  • 2021-01-26 05:32

    You need to set many=True when dealing with multiple relation - either a m2m or a reversed FK:

    author = AccountSerializer(read_only=True, required=False, many=True)
    
    0 讨论(0)
提交回复
热议问题