I have the following model structure:
class Project(models.Model):
author = models.ManyToManyField(Account)
name = models.CharField(max_length=40, default=\'
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)
There are two problems here:
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)
By default nested serializers are
read-only
. If you want to support write-operations to a nested serializer field you'll need to createcreate()
and/orupdate()
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.
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.
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.
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)