Django REST: TypeError: Объект типа 'Language' не JSON сериализуемый - PullRequest
0 голосов
/ 07 марта 2020

При попытке добавить значение языка python3 возвращает ошибку, что этот объект не JSON сериализуемый.

модели:

from django.db import models
from django.contrib.auth.models import AbstractUser, AbstractBaseUser

class Admin(AbstractUser):

    class Meta(AbstractUser.Meta):
        pass

class HahaUser(AbstractBaseUser):
    is_admin = models.BooleanField(default=False, verbose_name='is administrator?')
    born = models.PositiveSmallIntegerField(verbose_name='born year')
    rating = models.PositiveIntegerField(default=0, verbose_name='user rating')
    email = models.EmailField(verbose_name='email')
    nickname = models.CharField(max_length=32, verbose_name='useraname')
    password = models.CharField(max_length=100, verbose_name='password') # on forms add widget=forms.PasswordInput
    language = models.ForeignKey('Language', on_delete=models.PROTECT)
    country = models.ForeignKey('Country', on_delete=models.PROTECT)

    def __str__(self):
        return self.nickname

    class Meta:
        verbose_name = 'User'
        verbose_name_plural = 'Users'
        ordering = ['nickname']

class Language(models.Model):
    name = models.CharField(max_length=20, verbose_name='language name')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 'Language'
        verbose_name_plural = 'Languages'


class Country(models.Model):
    name_ua = models.CharField(max_length=20, verbose_name='country name in Ukranian')
    name_en = models.CharField(max_length=20, verbose_name='country name in English')
    name_ru = models.CharField(max_length=20, verbose_name='country name in Russian')

    def __str__(self):
        return self.name_en

    class Meta:
        verbose_name = 'Country'
        verbose_name_plural = 'Countries'

Сериализаторы:

from rest_framework import serializers

from main import models

class RegistrationSerializer(serializers.ModelSerializer):

    password2 = serializers.CharField(style={'input_type': 'password'},
        write_only=True, required=True)

    class Meta:
        model = models.HahaUser
        fields = ['nickname', 'password', 'password2', 'language', 'country',
            'email', 'born']
        extra_kwargs = {
            'password': {'write_only': True}
        }

    def save(self):
        account = models.HahaUser.objects.create(
            email=self.validated_data['email'],
            nickname=self.validated_data['nickname'],
            language=self.validated_data['language'],
            born=self.validated_data['born'],
            country=self.validated_data['country']
        )

        password = self.validated_data['password']
        password2 = self.validated_data['password2']
        if password != password2:
            raise serializers.ValidationError({'password': 'Passwords must match.'})

        account.set_password(password)
        account.save()

        return account

просмотров:

from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view

from .serializers import RegistrationSerializer

@api_view(['POST',])
def registration_view(request):
    if request.method == 'POST':
        serializer = RegistrationSerializer(data=request.data)
        data = {}
        if serializer.is_valid():
            account = serializer.save()
            data['response'] = 'Successfully registrated a new user.'
            data['email'] = account.email
            data['nickname'] = account.nickname
            data['language'] = account.language
            data['born'] = account.born
            data['country'] = account.country
        else:
            data = serializer.errors

        return Response(data)

Полный текст ошибки:

Internal Server Error: /api/account/register/
Traceback (most recent call last):
  File "/home/dima/Стільниця/hahachat/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/dima/Стільниця/hahachat/lib/python3.6/site-packages/django/core/handlers/base.py", line 145, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/dima/Стільниця/hahachat/lib/python3.6/site-packages/django/core/handlers/base.py", line 143, in _get_response
    response = response.render()
  File "/home/dima/Стільниця/hahachat/lib/python3.6/site-packages/django/template/response.py", line 105, in render
    self.content = self.rendered_content
  File "/home/dima/Стільниця/hahachat/lib/python3.6/site-packages/rest_framework/response.py", line 70, in rendered_content
    ret = renderer.render(self.data, accepted_media_type, context)
  File "/home/dima/Стільниця/hahachat/lib/python3.6/site-packages/rest_framework/renderers.py", line 103, in render
    allow_nan=not self.strict, separators=separators
  File "/home/dima/Стільниця/hahachat/lib/python3.6/site-packages/rest_framework/utils/json.py", line 25, in dumps
    return json.dumps(*args, **kwargs)
  File "/usr/lib/python3.6/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/usr/lib/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/home/dima/Стільниця/hahachat/lib/python3.6/site-packages/rest_framework/utils/encoders.py", line 67, in default
    return super().default(obj)
  File "/usr/lib/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'Language' is not JSON serializable

Я много чего пробовал: - добавить json метод к языку модель - отправить данные в поле language_id - создать LanguageSerializer и работать с ним, но ничего не работает

Надеюсь на вашу помощь))

Ответы [ 3 ]

1 голос
/ 07 марта 2020

Результат account.language является экземпляром. Итак, в вашем registration_view данные ['language'] получили экземпляр, а не строку или число. Вот почему язык данных не JSON сериализуемый.

Исходя из ваших требований, вы можете изменить его на

data['language'] = account.language.name

1 голос
/ 07 марта 2020

Как говорит исключение, language является объектом Language модели и не является примитивным типом. Таким образом, вы должны использовать некоторые атрибуты модели языка, такие как language_id или language_name вместо объекта языка.

from rest_framework import serializers

from main import models

class RegistrationSerializer(serializers.ModelSerializer):

    password2 = serializers.CharField(style={'input_type': 'password'},
        write_only=True, required=True)
    language_name = serializers.CharField(source='language.name')

    class Meta:
        model = models.HahaUser
        fields = ['nickname', 'password', 'password2', 'language_name', 'country',
            'email', 'born']
        extra_kwargs = {
            'password': {'write_only': True}
        }

    def save(self):
        account = models.HahaUser.objects.create(
            email=self.validated_data['email'],
            nickname=self.validated_data['nickname'],
            language=self.validated_data['language_name'],
            born=self.validated_data['born'],
            country=self.validated_data['country']
        )

        password = self.validated_data['password']
        password2 = self.validated_data['password2']
        if password != password2:
            raise serializers.ValidationError({'password': 'Passwords must match.'})

        account.set_password(password)
        account.save()

        return account

ПРИМЕЧАНИЕ: Если вы исправите ошибку сериализуемого языка, вы получите еще одно исключение для Country тоже.

0 голосов
/ 11 марта 2020

Спасибо за помощь, но я решил бы ее сам.

Я просто добавляю str () к внешним ключам в моем представлении, где я генерирую JSON ответ.

    from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view

from .serializers import RegistrationSerializer

@api_view(['POST',])
def registration_view(request):
    if request.method == 'POST':
        serializer = RegistrationSerializer(data=request.data)
        data = {}
        if serializer.is_valid():
            account = serializer.save()
            data['response'] = 'Successfully registrated a new user.'
            data['email'] = account.email
            data['nickname'] = account.nickname
            data['language'] = str(account.language)
            data['born'] = account.born
            data['country'] = str(account.country)
        else:
            data = serializer.errors

        return Response(data)
...