вложенные поля Django Rest framework с несколькими моделями

это Django и Django Rest framework. У меня есть 2 модели: пользователь и телефон.

1-я проблема:

Я хочу иметь возможность обновлять данные пользователя (электронная почта) вместе с телефоном данные (номера телефонов) в 1 одном ответе на обновление api. Номер телефона быть 0 или много. Ну, как partial=True на самом деле. Если пользователь просто хочет обновляйте номера телефонов, не обновляйте электронную почту и наоборот.


дополнительная информация: во время Регистрация, телефон не входит. Просто базовая информация о пользователе (фамилия, имя, адрес электронной почты, пароль). Телефон может обновляться только в форме профиля пользователя после завершения регистрации. Форма профиля пользователя фактически связывается с несколькими моделями, которая является пользователем и телефоном

вторая проблема:

как сериализовать несколько phone_numbers и сохранить в db?

class User(AbstractBaseUser):
    email = models.EmailField(unique=True, default='')
    USERNAME_FIELD = 'email'


class Phone(models.Model):
    phone_number = models.CharField(max_length=10)
    owner = models.ForeignKey(User)

--------------------------------------
class UserSerializer(serializers.ModelSerializer):
    phone_number = PhoneSerializer(required=False, many=True)

    class Meta:
        model = User
        fields = ('email, 'phone_number')


class PhoneSerializer(serializers.ModelSerializer):

     class Meta:
          Model = Phone
          fields = ('phone_number')

HTML-форма будет иметь знак "плюс" в поле Номер телефона укажите, что можно добавить новый номер телефона. пример здесь

email : admin@admin.com
phone number: 23423432423
(add more)
phone number: 3423423423
(add more)
...

ожидаемый json

{
'email': 'email@email.com',
'phone_number': '32432433223234'
}

или если добавлено много телефонных номеров

{
'email': 'email@email.com',
'phone_number': '32432433223234',
'phone_number': '324342322342323'
}

или, может быть,

{
'email': 'email@email.com',
'phone_number': ['32432433223234','324342322342323']
}

или, может быть,

{
'email': 'email@email.com',
'Phone': [{'id': 1, 'phone_number': '32432433223234'}, {'id': 2, 'phone_number': '324342322342323'}]
}

это json можно сделать? как сериализатор и modelviewset могут это сделать? извините, я совершенно новичок в drf

1 ответов


  1. версия по умолчанию для вложенных объектов.

вам нужно добавить сериализатор create и update методы:

class UserSerializer(serializers.ModelSerializer):
    phones = PhoneSerializer(required=False, many=True)

    class Meta:
        model = User
        fields = ('email', 'phone_number')

    def create(self, validated_data):
        phones_data = validated_data.pop('phones', [])
        user = super(UserSerializer, self).create(validated_data)
        for phone_data in phones_data:
            user.phone_set.create(phone_number=phone_data['phone_number'])
        return user

    def update(self, instance, validated_data):
        phones_data = validated_data.pop('phones', [])
        user = super(UserSerializer, self).update(instance, validated_data)
        # delete old
        user.phone_set.exclude(phone__in=[p['phone_number'] for p in phones_data]).delete()
        # create new
        for phone_data in phones_data:
            user.phone_set.get_or_create(phone_number=phone_data['phone_number'])
        return user

заявка на создание:

{"email": "test@example.com" "phones": [{"phone_number": 12}, {"phone_number": 123}]}

запрос на обновление:

{"phones": [{"phone_number": 22}]}
  1. оптимизация текущей структуры:
    • не храните телефон как поле int-лучше строка.
    • принимаем телефоны как список строк, используйте ListField (http://www.django-rest-framework.org/api-guide/fields/#listfield), создание и обновление дескриптора в методах сериализатора.

обновление

  1. phones_data = validated_data.pop('phones') ->phones_data = validated_data.pop('phones', []), обрабатывать случай если никакие телефоны в запросе.

  2. следует ли обновлять и создавать телефоны в modelviewset?

    нет, сериализатор отвечает трансформация native data -> internal objects. Поэтому, если он получает данные телефонов - он должен создать PhoneNumber объекты.