rest serializer for nested class - django

i am very new to django , and started writing serializers and come with this issue
i have extended my user class from user_profile class
now i want to write the user_profile serializer to save data in user Profile and user
this is my user serializer
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email','password','is_staff')
it working fine
this is my user_profile class
class User_Profile(models.Model):
class Meta:
db_table = 'user_profile'
user = models.OneToOneField(User, on_delete=models.CASCADE)
phoneNumber = models.CharField(max_length=10)
now i write this serializer for user profile
class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
email = serializers.CharField(source='user.email')
username = serializers.CharField(source='user.username')
class Meta:
model = User_Profile
fields = ('url', 'phoneNumber','email','username')
but it does save the user and user profile data , and it gives error like this
Cannot assign "{u'username': u'test12', u'email': u'test#12.cm'}": "User_Profile.user" must be a "User" instance.
Please help!

Related

Django Create Extended User with Serializer

I'm working on extending the Basic User model to additional fields. I had created a Profile Model that should have a OneToOneRelation. I'm working with serializers. Now when I try to post a dummy user, I get this error:
**TypeError: User() got an unexpected keyword argument 'street'**
If I send only the user it works well. I know that the 'street' argument is not part of the User, but part of the Profile that should store later.
I tried to solve this with 'request.POST.pop' for every value and parsed to dict but then no data will be transmitted. Additionally, I had no success with Signals.
Does anyone have an idea how I can make this work, as the user and profile will be created at the same time? The user must save first and pass the id its generating to the Profile that is referenced to it.
Models.py:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=CASCADE, null=True)
street = models.CharField(name="street", max_length=100)
number = models.CharField(name="number", max_length=10)
plz = models.CharField(name="plz", max_length=10)
city = models.CharField(name="city", max_length=100)
phone = models.CharField(name="phone", max_length=20)
locked = models.BooleanField(name="locked", default=False)
Serializer.py:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ['street', 'number', 'plz', 'city', 'phone']
Views.py:
#api_view(['POST'])
def userCreate(request):
userSerializer = UserSerializer(data=request.data)
if userSerializer.is_valid():
user = userSerializer.create(validated_data=request.data)
profileSerializer = ProfileSerializer(instance=user ,data=request.data)
if profileSerializer.is_valid():
profileSerializer.create()
return Response(status=status.HTTP_200_OK)
return Response(status=status.HTTP_400_BAD_REQUEST)
You can rewrite the serializer to include profile. And then override the create method.
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = '__all__'
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(**profile_data, user=user)
return user
Then your view becomes:
#api_view(['POST'])
def userCreate(request):
userSerializer = UserSerializer(data=request.data)
if userSerializer.is_valid():
user = userSerializer.save()
return Response(status=status.HTTP_200_OK)
return Response(status=status.HTTP_400_BAD_REQUEST)
The request to server should then be modified as:
{
profile: {
... // profile specific attributes like street, number, city
},
... // user specific attibutes
}
PS: To update the instance, you should override the update method of serializer.

Django Rest Framework Serializer - return related field

I have a model with a one-to-one relationship with a main model:
class User(models.Model):
id = models.BigIntegerField(primary_key=True)
username = models.CharField(max_length=100, blank=True)
class AggregatedStats(models.Model):
user_id = models.ForeignKey('User', on_delete=models.DO_NOTHING, unique=True)
followers_30d = models.BigIntegerField(blank=True)
I have written the following serializers:
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'followers']
class AggregatedStatsSerializer(serializers.HyperlinkedModelSerializer):
username = UserSerializer(source='user.username')
class Meta:
model = AggregatedStats
fields = ['followers_30d', 'username']
I am trying to return the username from the User model, but whatever I try to get it, the best I can do is get the hyperlinked related field from user, but not the actual "username" attribute. How would you return this?
You can simply create a field and return it:
class AggregatedStatsSerializer(serializers.HyperlinkedModelSerializer):
username = SerializerMethodField()
class Meta:
model = AggregatedStats
fields = ['followers_30d', 'username']
def get_username(self, obj):
return obj.user_id.username

How to retrieve all models data by User id in Django Serializer?

I have following serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id']
class PersonSerializer(serializers.ModelSerializer):
user = UserSerializer()
comments = CommentSerializer(source='comment_set', many=True)
class Meta:
model = Person
fields = '__all__'
And related views
class PersonRetrieveView(generics.RetrieveAPIView):
queryset = Person.objects.all()
serializer_class = PersonSerializer
class UserRetrieveView(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (permissions.IsAuthenticated, )
The models are standard, Person related to User by Foreign key.
So my url path('persons/<int:pk>/', PersonRetrieveView.as_view()), returns Person object with user field with user id. I want to make kinda reverse logic. By user id I want to query all users with field person with all persons related to this user by user id.
I can't just make
class UserSerializer(serializers.ModelSerializer):
person = PersonSerializer()
class Meta:
model = User
fields = ['id']
because Person serializer defined below the User serializer. Is there any way to do it simple with generics?
Your models.py should look like this:
class Person(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
related_name='persons', # This is important
on_delete=models.CASCADE
)
# Other fields...
Then serializers.py:
class PersonSerializer(serializers.ModelSerializer):
persons=serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Person
For more info or other relation types you can look at the DRF doc:
https://www.django-rest-framework.org/api-guide/relations/

Django - Creating an instance via the serializer with a foreign key reference

I have a agencies and users. I want to create User instances via the UserSerializer which have an agency_id. However the serializer's validated_data does not have the agency_id after calling is_valid().
class Agency(models.Model):
name = models.CharField(max_length=60)
class User(modes.Model):
username = models.CharField(max_length=60)
agency = models.ForeignKey(Agency, blank=True, null=True)
class UserSerializer(serializers.ModelSerializer):
class Meta:
User = get_user_model()
model = User
fields = ( 'id', 'username', 'agency_id' )
read_only_fields = ['id']
Try to create a user via the serializer which belongs to the Acme Agency:
agency = Agency.objects.create(name="Acme Agency")
serializer = UserSerializer(data={ 'username':'wiley', 'agency_id': agency.id} )
serializer.is_valid() # True
serializer.validated_data.get('agency_id') # None
Creating a user via the UserManager using the agency id works just fine:
user = User.objects.create(username='wiley', agency_id=1)
user.agency.id # 1
use agency instead of agency_id in UserSerializer as
class UserSerializer(serializers.ModelSerializer):
class Meta:
User = get_user_model()
model = User
fields = ('id', 'username', 'agency')
read_only_fields = ['id']
and use the serailizer as,
serializer = UserSerializer(data={ 'username':'wiley', 'agency': agency.id} )

How to use Primary Key In a Serializer in Django

My Model is
class UserInfo(models.Model):
user = models.OneToOneField(User, unique=True)
mobile_no = models.CharField(max_length=10, blank=True)
and serialzer is :
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = UserInfo
fields = ('mobile_no','user')
but whenever I tried to use this
serializer = UserInfoSerializer(data=data)
if serializer.is_valid():
serializer.save()
It is not saving the data and giving errors.
Is there any method to use other then this to for using Primary key.
You should use PrimaryKeyRelatedField
add this to your serializer
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
Your UserInfoSerializer should look like:
class UserInfoSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = UserInfo
fields = ('mobile_no','user')
Update
If you want to update existing object in database then you have to pass model instance as an argument to UserInfoSerializer constructor.
user_info = self.get_object()
serializer = UserInfoSerializer(user_info, data=data)