首页 > 解决方案 > Django Rest Framework 如何从多个模型创建序列化程序

问题描述

我需要扩展 User 模型以添加诸如地址、分数、更多 user_types 等内容。有两种可能的方法来实现这一点,扩展 User 模型或创建一个将与目标 User 连接的新模型OneToOneField。我决定使用新模型,因为它看起来更容易,并且在这个堆栈溢出问题中推荐。但是现在我无法在没有嵌套配置文件字段的情况下创建序列化程序,而且没有记录,因为默认的 rest_framwork 文档生成器无法为嵌套序列化程序生成文档。

我的UserSerializer样子是这样的:

class UserSerializer(serializers.ModelSerializer):
    # This creates a nested profile field
    profile = ProfileSerializer(required=True)

    def create(self, validated_data):
        profile_data = validated_data.pop('profile')
        user = User.objects.create_user(**validate_data)
        profile, created = Profile.objects.upodate_or_creeate(user=user, defaults=profile_data)
        return user

    class Meta:
        model = User
        fields = ('id', 'username', 'email', 'password', 'buckelists', 'profile')
        read_only_fields = ('id',)
        extra_kwargs = {'password':{'write_only': True}}

此序列化程序采用以下 JSON 格式:

{
    'name': ...,
    'email': ...,
    'password': ...,
    'profile': {
        'address': ...,
        'score': ...,
        'user_type': ...,
        'achievements': ...,
        'country': ...,
        'trusted': ...,
    }

这看起来很奇怪,并且生成的文档rest_framework.documentation.include_docs_urls显示如下:

{
    'username': ...,
    'email': ...,
    'password': ...,
    'field': ...,
}

所以不清楚应该在配置文件字段中包含什么。我想创建可以接受以下格式的序列化程序:

{
    'name': ...,
    'email': ...,
    'password': ...,
    'address': ...,
    'score': ...,
    'user_type': ...,
    'achievements': ...,
    'country': ...,
    'trusted': ...,
}

是否可以不从头开始创建自定义序列化程序?或者至少可以为嵌套序列化程序生成文档。

PS:我使用python3.6和Django 2.1

编辑:这是我的models.py的相关部分:

class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)

trusted = models.BooleanField(default=False)
address = models.CharField(max_length=100, default="")

COUNTRIES = (
    ('CZ', 'Czech Republic'),
    ('EN', 'England'),
)
country = models.CharField(max_length=2, choices=COUNTRIES, default="CZ")

score = models.BigIntegerField(default=0)

achievements = models.ManyToManyField(Achievement, blank=True)

USER_TYPES = (
    ('N', 'Normal'),
    ('C', 'Contributor'),
    ('A', 'Admin'),
)
user_type = models.CharField(max_length=1, choices=USER_TYPES, default='N')


@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
    Token.objects.create(user=instance)


@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created=False, **kwargs):
if created:
    profile, created = Profile.objects.get_or_create(user=instance)
profile.save()

编辑:

Mohammad Ali 的答案为 GET 解决了这个问题,但我也想使用 POST、UPDATE 和 PATCH 方法。我发现我必须使用source参数,但这与序列化程序有关,我不知道如何在没有配置文件字段的情况下引用配置文件。

标签: pythondjangorestdjango-modelsdjango-rest-framework

解决方案


放轻松,您可以在 create 函数中创建 Profile obj。

class UserSerializer(serializers.ModelSerializer):

    trusted = serializers.BooleanField()
    address = serializers.CharField()

    class Meta:
        model = User
        fields = ('username', 'email', 'password', 'trusted', 'address',)

    def create(self, validated_data):
        user = User.objects.create(username=validated_data['username'], email=validated_data['email'])
        user.set_password(validated_data['password'])
        user.save()

        profile = Profile(user=user, trusted=validated_data['trusted'], address=validated_data['address']
        profile.save()
        return validated_data

这只是您的场景的简要实现。你可以填满故事。


推荐阅读