Создание пользовательского сериализатора в django
Я столкнулся с проблемой, потому что мне нужно создать пользовательский сериализатор, чтобы удовлетворить свои потребности.
Вот мои модели:
class PublicID(models.Model):
TYPE_FIELDS = (
('M', 'monkey'),
('A', 'alien'),
('P', 'person'),
)
public_id = models.CharField(unique=True, max_length=48, editable=False)
obj_type = models.CharField(choices=TYPE_FIELDS, max_length=1)
class Request(models.Model):
source = models.ForeignKey(PublicID, related_name='source_request_set',
on_delete=models.CASCADE)
dest = models.ForeignKey(PublicID, related_name='dest_request_set',
on_delete=models.CASCADE)
class Monkey(models.Model):
nickname = models.CharField(max_length=255)
public_id = models.OneToOneField(PublicID, related_name='monkey',
blank=True, on_delete=models.CASCADE)
class Alien(models.Model):
alias = models.CharField(max_length=255)
public_id = models.OneToOneField(PublicID, related_name='alien',
blank=True, on_delete=models.CASCADE)
class Person(models.Model):
first_name = models.CharField(max_length=255)
public_id = models.OneToOneField(PublicID, related_name='person',
blank=True, on_delete=models.CASCADE)
Обратите внимание, что все типы obj_type
могут посылать Request
каждому типу obj_type
. Например, у нас может быть Monkey
, который посылает запрос Alien
через их уникальные PublicID
Мой сериализатор выглядит следующим образом:
class RequestSerializer(serializers.ModelSerializer):
class Meta:
model = Request
exclude = ['id']
def validate_source(self, value):
obj_type = value.get('obj_type')
if obj_type is None:
raise serializers.ValidationError('`obj_type` field is required.')
# other checks
return value
def validate_dest(self, value):
obj_type = value.get('obj_type')
if obj_type is None:
raise serializers.ValidationError('`obj_type` field is required.')
# other checks
return value
def run_validation(self, attrs):
source = attrs.get('source')
dest = attrs.get('dest')
if source is None or dest is None:
raise serializers.ValidationError('`source` and `dest` fields are '
'required.')
self.validate_source(source)
self.validate_dest(dest)
return attrs
def to_representation(self, instance):
source_type = instance.source.obj_type
dest_type = instance.dest.obj_type
print(source_type, dest_type)
representation = {}
if source_type == 'monkey':
representation['source'] = {
'nickname': instance.source.monkey.nickname,
'obj_type': 'monkey',
}
elif source_type == 'alien':
representation['source'] = {
'alias': instance.source.alien.alias,
'obj_type': 'alien',
}
elif source_type == 'person':
representation['source'] = {
'username': instance.source.person.username,
'obj_type': 'person',
}
if dest_type == 'monkey':
representation['dest'] = {
'nickname': instance.dest.monkey.nickname,
'obj_type': 'monkey',
}
elif dest_type == 'alien':
representation['dest'] = {
'alias': instance.dest.alien.alias,
'obj_type': 'alien',
}
elif dest_type == 'person':
representation['dest'] = {
'username': instance.dest.person.username,
'obj_type': 'person',
}
return representation
Ожидаемое поведение:
Мой сериализатор должен быть способен:
- Получив
Request
, он должен уметь сериализовать его в:
{
'source': {'nickname': 'john', 'obj_type': 'monkey'},
'dest': {'alias': 'jim', 'obj_type': 'alien'}
}
Это успешно завершено благодаря модификации метода to_representation
.
- Учитывая сериализованные данные (предположим, что это данные, полученные выше в пункте (1)), он должен быть в состоянии проверить их, чтобы использовать их в методах
create
илиupdate
. Поскольку я переопределилrun_validation
и создал методыvalidate_<field>
, он успешно валидирует данные.
Мой вопрос в том, где правильное место для десериализации данных:
{
'source': {'nickname': 'john', 'obj_type': 'monkey'},
'dest': {'alias': 'jim', 'obj_type': 'alien'}
}
в объект Request
, который имеет source
и dest
, которые являются объектами PublicID
?
В ходе моих исследований я нашел лучший способ - переопределить метод to_internal_value()
, чтобы получить объект, если он существует, или вызвать исключение, если его нет. Если он не существует, я буду ловить исключение и использовать .save(create=True)
вместо него.
- Является ли это наиболее питоническим способом и лучшей практикой django для этого?
Другое дело, что если я проверю данные и сохраню возвращаемое значение сериализатора в переменной s
, я не смогу получить доступ к s.data
.
in to_representation
source_type = instance.source.obj_type
AttributeError: объект 'ReturnDict' не имеет атрибута 'source'
Однако, я могу получить доступ к s.validated_data
и значения правильные.
почему вызывается метод
to_representation()
, когда я пытаюсь получить доступ кs.data
? Я предполагал, что поскольку экземпляр сериализатора был создан из сериализованных данных, процесс сериализации не будет происходить снова.Является ли проблемой то, что я не могу получить доступ к
s.data
? Моя реализация неверна?