2

I'm new to django rest_framework and have and issue, i've extended the auth_user as per the django docs, but is giving me a hard time...

models.py

class UserProfile(models.Model):
    user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE)
    national_id = models.CharField(max_length=10, blank=True, null=True)
    mobile = models.CharField(max_length=10)
    pin = models.IntegerField()
    pattern = models.IntegerField(blank=True, null=True)
    fingerprint = models.CharField(max_length=45, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'user_profile'

serializers.py

class UserSerializer(serializers.ModelSerializer):
    national_id = serializers.CharField(source='userprofile.national_id', allow_null=True, required=False)
    mobile = serializers.CharField(source='userprofile.mobile')
    pin = serializers.IntegerField(source='userprofile.pin', write_only=True)
    pattern = serializers.IntegerField(source='userprofile.pattern', write_only=True)
    fingerprint = serializers.CharField(source='userprofile.fingerprint', write_only=True, allow_null=True, required=False)

    class Meta:
        model = User
        fields = ('id', 'username', 'password', 'first_name', 'last_name', 'email', 'national_id', 'mobile', 'pin', 'pattern', 'fingerprint')
        write_only_fields = ('password',)
        read_only_fields = ('last_login', 'is_superuser', 'is_staff', 'is_active', 'date_joined')

    def create(self, validated_data):
        user = User(
            username=validated_data['username'],
            first_name=validated_data['first_name'],
            last_name=validated_data['last_name'],
            email=validated_data['email'],
            )
        user.set_password(validated_data['password'])
        user.save()
        userprofile = UserProfile(
            user=user,
            national_id=validated_data['national_id'],
            mobile=validated_data['mobile'],
            pin=validated_data['pin'],
            pattern=validated_data['pattern'],
            fingerprint=validated_data['fingerprint'],
            )
        userprofile.save()
        return user

views.py

class UserView(viewsets.ModelViewSet):
    serializer_class = UserSerializer
    queryset = get_user_model().objects

urls.py

from django.conf.urls import include, url
from django.contrib import admin
from rest_framework.routers import DefaultRouter

from restful.views import *

router = DefaultRouter()

router.register(r'availability-notification', AvailabiltyNotificationView)
router.register(r'bank', BankView)
router.register(r'recipient', RecipientView)
router.register(r'user', UserView)

urlpatterns = [
    url(r'^', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^admin/', admin.site.urls),

but keeps giving me:

Environment:

Request Method: POST Request URL: http://localhost:8000/user/

Django Version: 1.10.2 Python Version: 3.5.2 Installed Applications: ['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'restful'] Installed Middleware: ['django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware']

Traceback:

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\core\handlers\exception.py" in inner 39. response = get_response(request)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\core\handlers\base.py" in _get_response 187. response = self.process_exception_by_middleware(e, request)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\core\handlers\base.py" in _get_response 185. response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\views\decorators\csrf.py" in wrapped_view 58. return view_func(*args, **kwargs)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\viewsets.py" in view 87. return self.dispatch(request, *args, **kwargs)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\views.py" in dispatch 474. response = self.handle_exception(exc)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\views.py" in handle_exception 434. self.raise_uncaught_exception(exc)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\views.py" in dispatch 471. response = handler(request, *args, **kwargs)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\mixins.py" in create 21. self.perform_create(serializer)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\mixins.py" in perform_create 26. serializer.save()

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\serializers.py" in save 192. self.instance = self.create(validated_data)

File "C:\Users\echavez\Source\ws\restful\serializers.py" in create 45. national_id=validated_data['national_id'],

Exception Type: KeyError at /user/ Exception Value: 'national_id'

I know this is a newbie question, but, i really need help!

Thanks in advance.

2 Answers2

2

You are getting profile data in wrong way. validated_data is a dictionary of user and profile data which you are going to save separately.

Get it like this.

profile_data = validated_data.pop('userprofile')

Note that we poped userprofile data so now you have left only user data in validated_data. So a complete flow will look like below

profile_data = validated_data.pop('userprofile')
user = User.objects.create(**validated_data)
UserProfile.objects.create(user=user, **profile_data)
return user

Take a look here

http://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations

Lal
  • 1,599
  • 15
  • 18
  • Hi LaL, thanks for your quick answer, you're right, but is throwing me this error: File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\base.py" in prepare_database_save 999. raise ValueError("Unsaved model instance %r cannot be used in an ORM query." % self) Exception Type: ValueError at /user/ Exception Value: Unsaved model instance cannot be used in an ORM query. – Eliezer Efraín Chávez Oct 09 '16 at 20:21
0

Thanks to LaL ZaDa who pointed me in the right direction, my code finally looks like this and works:

serializers.py

class UserSerializer(serializers.ModelSerializer):
    national_id = serializers.CharField(source='userprofile.national_id', allow_null=True, required=False)
    mobile = serializers.CharField(source='userprofile.mobile')
    pin = serializers.IntegerField(source='userprofile.pin', write_only=True)
    pattern = serializers.IntegerField(source='userprofile.pattern', write_only=True)
    fingerprint = serializers.CharField(source='userprofile.fingerprint', write_only=True, allow_null=True, required=False)

    bank_accounts = UserBankAccountSerializer(many=True)

    class Meta:
        model = User
        fields = ('id', 'username', 'password', 'first_name', 'last_name', 'email', 'national_id', 'mobile', 'pin', 'pattern', 'fingerprint', 'bank_accounts')
        write_only_fields = ('password',)
        read_only_fields = ('last_login', 'is_superuser', 'is_staff', 'is_active', 'date_joined')

    def create(self, validated_data):
        user = User(
            username=validated_data['username'],
            first_name=validated_data['first_name'],
            last_name=validated_data['last_name'],
            email=validated_data['email'],
            )
        user.set_password(validated_data['password'])
        user.save()
        profile_data = validated_data.pop('userprofile')
        userprofile = UserProfile(
            user=user,
            national_id=profile_data['national_id'],
            mobile=profile_data['mobile'],
            pin=profile_data['pin'],
            pattern=profile_data['pattern'],
            fingerprint=profile_data['fingerprint'],
            )
        userprofile.save()
        return user

Cause, this is not exactly a nested model (the bank_accounts, are nested), so when i do like this:

profile_data = validated_data.pop('userprofile')
user = User.objects.create(**validated_data)
UserProfile.objects.create(user=user, **userprofile)
return user

was throwing me...

Environment:

Request Method: POST Request URL: http://localhost:8000/user/

Django Version: 1.10.2 Python Version: 3.5.2 Installed Applications: ['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'restful'] Installed Middleware: ['django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware']

Traceback:

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\core\handlers\exception.py" in inner 39. response = get_response(request)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\core\handlers\base.py" in _get_response 187. response = self.process_exception_by_middleware(e, request)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\core\handlers\base.py" in _get_response 185. response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\views\decorators\csrf.py" in wrapped_view 58. return view_func(*args, **kwargs)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\viewsets.py" in view 87. return self.dispatch(request, *args, **kwargs)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\views.py" in dispatch 474. response = self.handle_exception(exc)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\views.py" in handle_exception 434. self.raise_uncaught_exception(exc)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\views.py" in dispatch 471. response = handler(request, *args, **kwargs)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\mixins.py" in create 21. self.perform_create(serializer)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\mixins.py" in perform_create 26. serializer.save()

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\rest_framework\serializers.py" in save 192. self.instance = self.create(validated_data)

File "C:\Users\echavez\Source\ws\restful\serializers.py" in create 49. user = User.objects.create(**validated_data)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\manager.py" in manager_method 85. return getattr(self.get_queryset(), name)(*args, **kwargs)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\query.py" in create 397. obj = self.model(**kwargs)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\contrib\auth\base_user.py" in init 68. super(AbstractBaseUser, self).init(*args, **kwargs)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\base.py" in init 550. setattr(self, prop, kwargs[prop])

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\fields\related_descriptors.py" in set 500. manager.set(value)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\fields\related_descriptors.py" in set 687. self.add(*objs, bulk=bulk)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\fields\related_descriptors.py" in add 597. self.field.name: self.instance,

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\query.py" in update 637. rows = query.get_compiler(self.db).execute_sql(CURSOR)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\sql\compiler.py" in execute_sql 1148. cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\sql\compiler.py" in execute_sql 824. sql, params = self.as_sql()

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\sql\compiler.py" in as_sql 1102. val.prepare_database_save(field),

File "C:\Users\echavez\Envs\YEiPii\lib\site-packages\django\db\models\base.py" in prepare_database_save 999. raise ValueError("Unsaved model instance %r cannot be used in an ORM query." % self)

Exception Type: ValueError at /user/ Exception Value: Unsaved model instance cannot be used in an ORM query.

Now i'll finish the create to include the nested one and the update and delete...

Thanks LaL