Django Rest Framework как создать сериализатор из нескольких моделей - PullRequest
0 голосов
/ 31 августа 2018

Мне нужно было расширить пользовательскую модель, чтобы добавить такие вещи, как адрес, счет, другие user_types и т. Д. Есть 2 возможных способа добиться этого, расширить пользовательскую модель или создать новую модель, которая будет связана с целевым пользователем с помощью OneToOneField. Я решил пойти с новой моделью, потому что она казалась проще и рекомендуется в этом вопросе переполнения стека. Но теперь я не могу создать Serializer без вложенного поля профиля, которое, кроме того, недокументировано, потому что генератор документации 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

EDIT: Вот соответствующая часть моего 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()

EDIT:

Ответы Мохаммеда Али решают это для GET, но я также хотел бы использовать методы POST, UPDATE и PATCH. Я обнаружил, что должен использовать параметр source, но это относительно сериализатора. Я не знаю, как ссылаться на профиль без поля профиля.

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

Полегче, Вы можете создать профиль объекта только в функции создания.

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

Это просто краткая реализация вашего сценария. Вы можете заполнить историю.

0 голосов
/ 31 августа 2018

Прочитайте документацию для сериализаторов: Django REST FRAMEWORK - пользователь related_name

user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="user_profile") # models

class ProfileSerializer(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), required=False)

     class Meta:
        model = Profile
        fields = '__all__'


class UserSerializer(serializers.ModelSerializer):
    user_profile = ProfileSerializer(required=True)

    class Meta:
        model = User
        fields = '__all__'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...