Поле Django не проходит через сериализатор
Используя Django REST Framework 2.2, я имею Person модель следующим образом в models.py::
class Person(models.Model):
id = models.CharField(max_length = 20, primary_key = True, blank = True)
name = Models.CharField(max_length = 1024, blank = True)
values = {}
Все данные хранятся в базе данных Firestore для сохранения и получения данных через REST API. Перед внесением новых записей в базу данных используется сериализатор для проверки входящих POST-данных.
Маршрут /person принимает данные POST-запроса и запускает их по команде PersonCreateSerializer в
views.py:
def create_person(request):
"""
Route: /person
Method: POST
"""
try:
print(request.data)
# Above print outputs:
# <QueryDict: {'name': ['John Doe'], 'values': ['{ "height": 180 }']}>
serializer = PersonCreateSerializer(data = request.data)
serializer.is_valid(raise_exception = True)
person = Person.create_person(request.data)
...
except APIException as exception:
return JsonResponse(exception.APIError, status = exception.status)
serializers.py:
class PersonCreateSerializer(CreateModelSerializer):
class Meta:
model = Person
fields = "__all__"
def validate(self, data):
print(data)
# Above print outputs:
# OrderedDict([('name', 'John Doe')])
# Notice missing 'values' field.
if not data.get("values"): # Ensure we have a values field within the data.
raise APIException("ERROR_MISSING_FIELD", "Missing required field 'values'.", 400)
return data
Проблема заключается в том, что любое значение, предоставленное для словаря values, отбрасывается, когда функция сериализатора validate() получает его.
POST Payload:

Мой вопрос заключается в том, почему словарь, полученный из POST-запроса, не попадает в сериализатор, чтобы его можно было разобрать? Это то, как вы используете словарные поля в Django?
Отправлено в сериализатор:
<QueryDict: {'name': ['John Doe'], 'values': ['{ "height": 180 }']}>
Получено сериализатором:
OrderedDict([('name', 'John Doe')])
Я рассмотрел альтернативные варианты, такие как HStoreField и JSONField, однако эти данные хранятся в базе данных Firestore, и необходимо сохранить ассоциацию ключ-значение, а не хранить их в виде простой строки JSON.
Я полагаю, что это потому, что values не является полем. Это просто переменная класса.
Сериализатор фильтрует данные по полям, на которые вы указали. Вы указали __all__, что означает все поля в модели.
Вы можете попробовать:
fields = ['name', 'values']
А если это не сработало, сделайте функцию и передайте ее "как поле":
# models.py
class Person(models.Model):
id = models.CharField(max_length = 20, primary_key = True, blank = True)
name = Models.CharField(max_length = 1024, blank = True)
values = {}
def get_values(self):
return self.values
# serializers.py
class PersonCreateSerializer(CreateModelSerializer):
class Meta:
model = Person
fields = ['name', 'get_values']
Решением, которое я нашел, было использование модуля django-dictionaryfield, который предоставляет тип поля Dictionary, который можно использовать для преобразования в и из всех типов массивов, таких как словари и списки.
Без поля, объявленного в model.py, сериализатор игнорирует его, поскольку оно не считается частью самой модели, поэтому использование пользовательской модели DictionaryField позволяет хранить его как поле модели Django.
Django DictionaryField Setup
Установите модуль в ваш проект:
$ pip install django-dictionaryfieldДобавьте
dictionaryfieldв вашINSTALLED_APPSконфигурационный файл Django:INSTALLED_APPS = ( ... "dictionaryfield", )
Модельный класс
Используйте DictionaryField для полей, которые должны быть массивами.
from django.db import models
from dictionaryfield import DictionaryField
class Person(models.Model):
id = models.CharField(max_length = 20, primary_key = True, blank = True)
name = Models.CharField(max_length = 1024, blank = True)
values = DictionaryField(default = {})
@staticmethod
def create_person(personData):
person = Person(
name = personData.get("name", "Unknown"),
values = personData.get("values", {}),
)
return person