Django Rest Framework : Почему сложный вложенный сериализатор пытается создать вложенные поля в базе данных при вызове .is_valid()?

Контекст

У меня есть проект, в котором есть три сущности : Account, Community и JoinRequest.

JoinRequest связывает аккаунт (пользователя) с сообществом. И не должно быть более одного JoinRequest для любой пары (аккаунт, сообщество).

Проблема

Я создал соответствующие модели, сериализаторы и unittest, которые вы можете увидеть ниже. Но когда я запускаю свой тест, он терпит неудачу при возврате join_request_serializer.is_valid() = False

Что приводит к следующей ошибке :

join_request_serializer.errors
    {'user': {'email': [ErrorDetail(string='account with this email already exists.', code='unique')], 'username': [ErrorDetail(string='account with this username already exists.', code='unique')], 'password': [ErrorDetail(string='This field is required.', code='required')]}, 'community': {'name': [ErrorDetail(string='community with this name already exists.', code='unique')]}}

Похоже, что метод .is_valid() сериализатора JoinRequestSerializer пытается воссоздать Account и Community, данные которых ранее были переданы в качестве аргументов при создании экземпляра...

Есть идеи, почему появляется эта ошибка?

Unit Test

class JoinRequestSerializerTestCase(TestCase):
    def test_join_request_serializer_create_success(self):
        account = register()
        account_serializer = AccountSerializer(account)
        community_data = {
            'name': 'CommunityNameExample'
        }
        community = Community(community_data)
        community_serializer = CommunitySerializer(community)
        data = {'user':account_serializer.data, 'community':community_serializer}
        join_request_serializer = JoinRequestSerializer(data=data)
        self.assertEqual(join_request_serializer.is_valid(), True)
        join_request_serializer.save()
        self.assertEqual(JoinRequest.objects.count(), 1)

Account

class MyAccountManager(BaseUserManager):

    def create_user(self, email, username, password=None):
        if not email:
            raise ValueError('Users must have an email address')
        if not username:
            raise ValueError('Users must have an username')
        user = self.model(
            email=self.normalize_email(email),
            username=username,
            )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, username, password):
        # This method must be overridden to use MyAccountManager class
        user = self.create_user(
            email=self.normalize_email(email),
            username=username,
            password=password,
        )
        user.is_admin = True
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)
        return user


class Account(AbstractBaseUser):
    email = models.EmailField(verbose_name="email", max_length=60, unique=True)
    username = models.CharField(
                                max_length=30,
                                unique=True,
                                validators = [
                                                RegexValidator(
                                                            regex='^[a-zA-Z0-9]*$',
                                                            message='Username must be Alphanumeric.',
                                                            code='invalid_username'
                                                            )
                                            ]
                    )
    date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
    last_login = models.DateTimeField(verbose_name='last login', auto_now_add=True)
    is_admin = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)

    USERNAME_FIELD = 'username' # Generic (not explicit) keyword for the login field
    REQUIRED_FIELDS = ['email']

    objects = MyAccountManager() # What is the point of this line?


    def create(self, email, username, password, **kwargs):
        account = Account.objects.create_user(
                                                username = username,
                                                email = email,
                                                password = password
                                            )
        post_save(sender=Account, instance=account, created = True, raw=True)
        return account

Сообщество

class Community(models.Model):
    name = models.CharField(
        max_length=30,
        unique=True,
        validators = [
                        RegexValidator(
                                    regex='^[a-zA-Z0-9]*$',
                                    message='Community name must be Alphanumeric.',
                                    code='invalid_username'
                        )
                    ]
    )
    bio = models.CharField(max_length=150, blank=True, default='')
    slug = models.SlugField(max_length=30, blank=True, default=slugify(name))

    class Meta(object):
        verbose_name_plural = 'Communities'

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        self.slug = slugify(self.name)
        super(Community, self).save(*args, **kwargs)

JoinRequest

class JoinRequest(models.Model):
    community = models.ForeignKey(Community, on_delete=models.CASCADE)
    user = models.ForeignKey(Account, on_delete=models.CASCADE)
    creation_date = models.DateTimeField(auto_now_add=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['community', 'user'], name='unique_joinrequest')
        ]

AccountSerializer

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ['email', 'username', 'password']
        extra_kwargs = {'password':{'write_only':True}}

    def create(self):
        account = Account.objects.create_user(
            email = self.validated_data['email'],
            username = self.validated_data['username'],
            password = self.validated_data['password'],
        )
        return account

CommunitySerializer

class CommunitySerializer(serializers.ModelSerializer):

    class Meta:
        model = Community
        fields = ['name', 'bio']
        lookup_field = 'slug'
        extra_kwargs = {
            'url':{'lookup_field':'slug'}
        }

JoinRequestSerializer

class JoinRequestSerializer(serializers.ModelSerializer):
    user = AccountSerializer(
                                source='account_set',
                            )
    community=CommunitySerializer(
                                source='community_set',
                            )

    class Meta:
        model = JoinRequest
        fields = ['user', 'community']
        read_only_fields = ('user', 'community')
        validators = [
                        UniqueTogetherValidator(
                                queryset=JoinRequest.objects.all(),
                                fields=['user', 'community'],
                                message='A Join Request for this couple of User'\
                                     ' and Community already exists.'
                               )
                    ]
        extra_kwargs = {
            'user':{'read_only':True},
            'commnuity':{'read_only':True}
            }

    def create(self):
        join_request = JoinRequest(
                                    user = self.validated_data['user'],
                                    community = self.validated_data['community'],
                                )
        return join_request
Вернуться на верх