2016-12-27 4 views
1

У меня есть эти модели:Serializer работает в оболочке Django, но не с точки зрения

class ServiceCategory(models.Model): 
    class Meta: 
     db_table = 'service_categories' 

    category = models.CharField(max_length=24) 

    def __str__(self): 
     return self.category 


class Service(models.Model): 
    class Meta: 
     db_table = 'services' 

    service = models.CharField(max_length=24) 
    category = models.ForeignKey('ServiceCategory') 

    def __str__(self): 
     return self.service 

И их сериализаторы:

class ServiceCategorySerializer(serializers.ModelSerializer): 
    class Meta: 
     model = ServiceCategory 
     fields = ('id', 'category') 

class ServiceSerializer(serializers.ModelSerializer): 
    category = ServiceCategorySerializer() 

    class Meta: 
     model = Service 
     fields = ('id', 'service', 'category') 

После установки, I quickly bumped into a problem создания нового Service через связанный с ним ServiceSerializer : Я должен также передать полный ServiceCategory со всеми его полями, хотя мне нужен только его id. ServiceCategory выше выглядит достаточно простым, но это вряд ли имеет место, так как я опущен много других его полей для краткости.

Так передавая полные атрибуты ServiceCategory в форму на переднем конце, казалось, очень неэффективно для меня, так что я попробовал другой подход:

class UpsertServiceSerializer(serializers.ModelSerializer): 
    category = serializers.IntegerField() # not ServiceCategorySerializer() 

    class Meta: 
     model = Service 
     fields = ('service', 'category') 

    def create(self, data): 
     c = ServiceCategory.objects.get(pk=data['category']) 
     return Service.objects.create(service=data['service'], category=c) 

Мое намерение состоит в том, чтобы использовать UpsertServiceSerializer для создает и обновления, с ServiceSerializer теперь используется для чтения. UpsertServiceSerializer работал без проблем в оболочке Django - мне все равно нужно передать только id из ServiceCategory, а не все его атрибуты, и новый объект Service действительно добавлен в базу данных - но когда я делаю запрос POST через Почтальон, я получаю эту ошибку:

TypeError at /services 
int() argument must be a string, a bytes-like object or a number, not 'ServiceCategory' 

Так что я попробовал новую версию UpsertServiceSerializer:

class UpsertServiceSerializer(serializers.Serializer): 
    service = serializers.CharField() 
    category = serializers.IntegerField() 

    def create(self, data): 
     c = ServiceCategory.objects.get(pk=data['category']) 
     return Service.objects.create(service=data['service'], category=c) 

Обратите внимание, что в новой версии, я подклассы serializers.Serializer вместо serializers.ModelSerializer, и внутри него нет class Meta. Эта версия ничем не отличается, она также проходит в оболочке Django, но не отображается в представлении с тем же TypeError.

Вот вид:

@api_view(['GET', 'POST']) 
def services(request): 
    if request.method == 'GET': 
     services = Service.objects.all() 
     serializer = ServiceSerializer(services, many=True) 
     return Response(serializer.data) 

    elif request.method == 'POST': 
     serializer = UpsertServiceSerializer(data=request.data) 
     if serializer.is_valid(): 
      serializer.save() 
      return Response(serializer.data, status=status.HTTP_201_CREATED) 
     return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 

Так что я делаю неправильно?

ответ

1

Это распространенная проблема с пониманием того, как связанные поля работают в сериализаторе. ForeignKey по умолчанию использует PrimaryKeyRelatedField, поэтому вам не нужен IntegerField, хотя вам не нужно переопределять метод create.

class UpsertServiceSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = Service 
     fields = ('service', 'category') 

Передача pk для категории будет работать. В случае, когда вам нужен специальный макет для модели category не простой pk, вы можете написать свой собственный метод to_representation.

class UpsertServiceSerializer(serializers.ModelSerializer): 
    ... 
    def to_representation(self, instance): 
     representation = super(UpsertServiceSerializer, self).to_representation(instance) 
     representation['category'] = ServiceCategorySerializer(instance.category).data 
     return representation 
+0

Спасибо. Очень ценная информация. Принимается и поддерживается. – Duos

+0

@ Примите ваше приветствие –

Смежные вопросы