19👍
So apparently I don’t have enough reputation to post a comment under an answer. But to elaborate on what Kevin Stone described, if you model is something like the following:
class AppUser(models.Model):
user = models.OneToOneField(User)
ban_status = models.BooleanField(default=False)
You can do something like this to create both the custom user and django user:
class AppUserSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
email = serializers.CharField(source='user.email')
password = serializers.CharField(source='user.password')
ban_status = serializers.Field(source='ban_status')
class Meta:
model = AppUser
fields = ('id', 'username', 'email', 'password', 'ban_status')
def restore_object(self, attrs, instance=None):
"""
Given a dictionary of deserialized field values, either update
an existing model instance, or create a new model instance.
"""
if instance is not None:
instance.user.email = attrs.get('user.email', instance.user.email)
instance.ban_status = attrs.get('ban_status', instance.ban_status)
instance.user.password = attrs.get('user.password', instance.user.password)
return instance
user = User.objects.create_user(username=attrs.get('user.username'), email= attrs.get('user.email'), password=attrs.get('user.password'))
return AppUser(user=user)
16👍
Okay, a couple of things. You want to create a OneToOneField
for your user model extension.
class MyUser(models.Model):
user = models.OneToOneField(User)
city = models.CharField(max_length=50, blank=True, default='')
Now, the power of Django Rest Framework, is you can build your serializer, to take data from both of these models when serializing.
class UserSerializer(serializers.ModelSerializer):
city = serializers.CharField(source='myuser.city')
class Meta:
model = User
fields = ('id', 'username', 'password', 'first_name', 'last_name', 'email', 'city')
Finally, where you’re creating the user, since you’re using custom fields, you need to implement your own restore_object()
that builds both models from the input data.
Also, creating Users in Django is a bit different, you need to call create_user()
and supply a password that is hashed, so its not as simple as storing fields from a serializer.
- [Django]-Django REST Serializer Method Writable Field
- [Django]-ValueError: Too many values to unpack Django
- [Django]-How to change validation error responses in DRF?
3👍
It would be nice if this use case was easier to find in the docs. As @jamod pointed out, in DRF 3, you can find it here:
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ('username', 'email', 'profile')
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(user=user, **profile_data)
return user
- [Django]-How does django know which migrations have been run?
- [Django]-How to save a model without sending a signal?
- [Django]-Django-debug-toolbar not showing up
2👍
When using Django Rest Framework you have to be careful. Any custom user model cannot utilize the built in token authentication. Until you can do that, I would suggest using a OneToOneField with user in your custom model. Your custom model will contain the extra fields you want to keep. One to One gives you access to the user from the custom user, and the custom user from the user.
- [Django]-South + Django 1.4 Database error
- [Django]-Filter Django database for field containing any value in an array
- [Django]-How to define default data for Django Models?
1👍
If you’re using django 1.5 or greater then use custom user model instead, this way user model will have it’s own dedicated table and serializer will then pick up the fields correctly.
- [Django]-Django — User.DoesNotExist does not exist?
- [Django]-Is Django admin difficult to customize?
- [Django]-Django RESTful API – django-piston vs. django-tastypie
1👍
I prefer to use the django signals module, which sends signals to the app when something happens, and among other things will let you call a function of your own before/after other functions. My answer is similar to Stuart’s answer but keeps all of the code relevant to your new extension class in one place (if you want to delete the profile later or change its name you don’t have to look anywhere else).
The following code lays out your extended class model, in this case a user profile, then creates an empty instance when a user model is created, then saves the instance with new information (that you must add yourself) by saving the parent user instance i.e. – user.save()
models.py
from django.db.models.signals import post_save
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model): #This extends the user class to add profile information
user = models.OneToOneField(User, on_delete=models.CASCADE)
#add your extra traits here: is_nice, is_shwifty, address, etc.
is_nice = models.BooleanField(default=True, blank=True)
# a user model was just created! This now creates your extended user (a profile):
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
# instance is the user model being saved.
Profile.objects.create(user=instance)
# a user model was just saved! This now saves your extended user (a profile):
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
If you don’t have a ProfileSerializer: serializers.py
#use hyperlinkedmodelserializer for easy api browsing + clicking
class ProfileSerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer()
class Meta:
model = Profile
fields = ('url', 'user', 'is_nice')
After you create your user and save your user, you’ll have an empty user.profile to add information to. For example, after running python manage.py shell
try:
from backend.models import User, Profile
#create your user
user=User(username="GravyBoat")
user.save()
#now update your user's profile
user.profile.is_nice=False
#that's one mean gravy boat
user.save()
user.profile.is_nice
#False
- [Django]-Should I be adding the Django migration files in the .gitignore file?
- [Django]-Django return file over HttpResponse – file is not served correctly
- [Django]-When to use Serializer's create() and ModelViewset's perform_create()