I'm using Django-piston and I'd like to get user objects that include user profile data.
I'm trying :
class UserHandler(BaseHandler):
model = User
fields = ('id', 'username', 'favorite_color')
...
favorite_color is defined in UserProfile
The result is only printing id and username and nothing for favorite color.
If your UserProfile is linked to the User via a OneToOneField, you should be able to do it by walking the relation, using the nested-tuple syntax. (The following is untested)
class UserHandler(BaseHandler):
model = User
fields = ('id', 'username', ('userprofile', ('favorite_color',))
...
See the docs here
check if you already use model=User in other handler
and look at this
https://bitbucket.org/jespern/django-piston/wiki/FAQ
Related
-Solved-
This request was never going to work as some servers and browsers don't process body params from a GET request however Postman simply processes the request as expected and this was the reason why I got very confused and not sure what to look for. Instead use query params if you wish to filter data in a REST
-updated for more clarification-
I have 2 models CustomUser and Category, added User FK to Categories
updated my serializers to account for that ( not sure this part is correct tho )
on a Ajax GET request I pass the user id so I can grab only the categories that have the specified FK
in my Views request.get.data('user_id') brings back None
if I run the same request via Postman then I get the desired results
Any clues on why this would happen?
Apologies if my initial post was vague.
class CategorySerializer(TaggitSerializer, serializers.ModelSerializer):
author = serializers.PrimaryKeyRelatedField(queryset=CustomUser.objects.all())
posts = PostSerializer(many=True, read_only=True)
tags = TagListSerializerField()
class Meta:
model = Category
fields = ('id', 'name', 'description', 'created_at', 'updated_at', 'posts', 'tags', 'author')
# User Serializer
class CustomUserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('id', 'email')
I didn't get clear, do you have trouble reading the id in the response or writing it to the database?
So, I have a foreign key to my User model in many of my models. Now, the serializers for these models are nested, in that they include the entire user object rather than just the id. I have done so as shown bellow:
class BadgeSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Badge
fields = '__all__'
It works as expected. However, I seldom find myself in a situation where I want just the id. I was wondering what is the best way to conditionally nest my BadgeSerializer...
Now, the best solution I can think of is to have a non-nested BadgeSerializer, which includes only the user id. And then have a NestedBadgeSerializer (extending BadgeSerializer) which does nest the User model and include the entire user object.
class BadgeSerializer(serializers.ModelSerializer):
class Meta:
model = Badge
fields = '__all__'
class NestedBadgeSerializer(BadgeSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Badge
fields = '__all__'
I am NOT sure if that's the proper way though.
Question is about using standard Django backward related manager name in DRF.
I have following serializer
class ExtraUserSerializer(serializers.ModelSerializer):
boatmodel_set = serializers.PrimaryKeyRelatedField(many=True,
queryset=BoatModel.objects.all())
class Meta:
model = get_user_model()
fields = ("id", "username", 'boatmodel_set', )
This serializer represents primary model ExtraUser and boat_model set represents backward relationship to secondary model BoatModel. Related name “boatmodel_set” chosen simply because main core Django site uses this standard “secondarymodel_set” conventional backward related manager name so that in DRF part I had to use related_name = “ boatmodel_set” as well in order to not change code in the main part.
Question is - is it possible to keep related_name = “ boatmodel_set” but represent it in rendered json as , for example “boats”??
Thank you
Yes, you can just specify the source= parameter [drf-doc], and name the field differently, like:
class ExtraUserSerializer(serializers.ModelSerializer):
boats = serializers.PrimaryKeyRelatedField(
many=True,
queryset=BoatModel.objects.all(),
source='boatmodel_set'
)
class Meta:
model = get_user_model()
fields = ('id', 'username', 'boats')
Here the JSON-side will contain "boats": ..., whereas the model side will still use myuser.boatmodel_set.all().
So I am just getting familiar with django and django-rest-framework.
I have a model of Jobs that have an owner, and I want to add the list of jobs a user owns to the user endpoint.
I tried to do it like this, as the tutorial of the django rest framework says:
class UserSerializer(serializers.ModelSerializer):
jobs = serializers.PrimaryKeyRelatedField(many = True, queryset = Job.objects.all())
class Meta:
model = User
fields = ('id', 'username', 'jobs')
But for some reason, when I want to view the users, I recieve
AttributeError at /users/
'User' object has no attribute 'jobs'
The documentation about the PrimareyKeyRelatedField looks just like this. Do I maybe have to do something with the user model?
What works is the following:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'job_set')
but I don't like that solution as I want to have more control about how the list is presented (maybe change the ids to complete json objects or rename the attribut name from 'job_set' to 'job)
I really don't now what I am overseeing...
You can do two things,
jobs = serializers.PrimaryKeyRelatedField(many = True, source='job_set' queryset = Job.objects.all())
or
Set related_name='jobs' attribute to User relational field.
I have models like this:
class ModelA(models.Model):
name = models.CharField()
class ModelB(models.Model):
f1 = models.CharField()
model_a = models.ForeignKey(ModelA)
Serializers:
class ASerializer(serializers.ModelSerializer):
model_b_ids = serializers.CharField()
class Meta:
model = ModelA
write_only_fields = ('model_b_ids',)
views:
class AView(CreateModelMixin, GenericViewSet):
def perform_create(self, serializer):
model_b_ids = parse_somehow(serializer.validated_data["model_b_ids"])
#do something...
The problem I am getting is the with the "model_b_ids"
The user should submit it while sending post data.
I use it in perform_create to link to related models.
But thats not "real column" in ModelA so when I try to save it is raising exception.
I tried to it pop from validated_data but then again getting error somewhere that cannot read model_b_ids from model. Any idea on using this kind of field correctly ?
The Django Rest Framework does not have Meta attribute write_only_fields anymore
According to their docs you set write-only fields in extra_kwargs
e.g
class UserSerializer(ModelSerializer):
"""
``Serializer`` for ``User`` ..
"""
class Meta:
model = User
fields = ('id', 'email', 'first_name', 'last_name' ,'security_question', 'security_question_answer', 'password', 'is_active', 'is_staff')
read_only_fields = ('is_active', 'is_staff')
extra_kwargs = {
'security_question': {'write_only': True},
'security_question_answer': {'write_only': True},
'password': {'write_only': True}
}
Update
As #AKHIL MATHEW highlighted in his answer below
From DRF v3 onwards, setting a field as read-only or write-only can use serializer field core arguments mentioned as follows.
write_only
Set this to True to ensure that the field may be used when updating or creating an instance, but is not included when serializing the representation.
Defaults to False
Eg:
company = serializers.PrimaryKeyRelatedField(write_only=True)
In accordance with the Django REST Framework documentation:
The write_only_fields option on ModelSerializer has been moved to PendingDeprecation and replaced with a more generic extra_kwargs
that's why it's recommended to do like this: you should use extra_kwargs:
extra_kwargs = {
'model_b_ids': {'write_only': True},
'another_field': {'read_only': True}
}
or:
model_b_ids = serializers.IntegerField(write_only=True)
Probably you're overseeing that your ModelA has the property modelb_set. In Django you describe the relationship in one model class. Django offers a backward relationship by lower-casing the target model and suffixing it with _set. So you could do:
a = ModelA.objects.get(pk=1)
a.modelb_set.all()
This would get the element with ID (or primary key) 1 from ModelA and retrieve all related ModelB elements.
You can set a value for related_name to overwrite the default value:
class ModelB(models.Model):
f1 = models.CharField()
model_a = models.ForeignKey(ModelA, related_name='model_b')
In DRF you can slightly adapt your serializer:
class ASerializer(serializers.ModelSerializer):
model_b = serializers.PrimaryKeyRelatedField(many=True, read_only=False)
class Meta:
model = ModelA
write_only_fields = ('model_b',)
With serializers.CharField() you can't post values and write them to the model, because it isn't a model field.
Give this example a try. Tinker and experiment. It should bring you closer to the solution.
EDIT:
I'm not really sure how Django creates the name for backward relationship for PascalCase class names. Is it model_b_set for ModelB? Or is it modelb_set? You can try and find it out.
From docs you can use read_only
Read-only fields are included in the API output, but should not be included in the input during create or update operations. Any 'read_only' fields that are incorrectly included in the serializer input will be ignored.
Set this to True to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.
Defaults to False
As example:
We can use it on Serializer fields:
model_b_ids = serializers.IntegerField(read_only=True)
or we can use it in extra_kwargs:
extra_kwargs = {
'model_b_ids': {'read_only': True}
}
From DRF v3 onwards, setting a field as read-only or write-only can use serializer field core arguments mentioned as follows.
Core arguments
Each serializer field class constructor takes at least
these arguments. Some Field classes take additional, field-specific
arguments, but the following should always be accepted:
read_only
Read-only fields are included in the API output but should
not be included in the input during create or update operations. Any
'read_only' fields that are incorrectly included in the serializer
input will be ignored.
Set this to True to ensure that the field is used when serializing a
representation, but is not used when creating or updating an instance
during deserialization.
Defaults to False
Eg:
price = serializers.IntegerField(read_only=True)
write_only
Set this to True to ensure that the field may be used when
updating or creating an instance, but is not included when serializing
the representation.
Defaults to False
Eg:
company = serializers.PrimaryKeyRelatedField(write_only=True)
Well you could override the serializer.save() method on ASerializer to instantiate modelA object, set its attributes, save it, then set relations on existing modelB objects, save them as well and drink to success.
But I think maybe setting that related_name and RelatedField on serializer as was suggested would do exactly the same thing.... with less typing.. and overall better:)