How to serialize object field in django rest framework - python

I have Profile model, which is auth model. And I have Blog model. I want to serialize model as it will give me {author: {user_name:.., photo: photo_path}, blog_title:some_title, ..}. Shortly, I want use author field as inner serialiser. I have already ProfileSerialiser and BlogSerializer. Here's my BlogList serializer:
class BlogListSerializer(serializers.ModelSerializer):
author = MiniProfileSerializer()
class Meta:
model = Blog
fields = ['title', 'content', 'like_count', 'author']
read_only_fields = ['views', 'author', 'like_count']
And MiniProfileSerializer:
class MiniProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ['user_name', 'image']
and view:
class BlogListAPIView(generics.ListCreateAPIView):
serializer_class = BlogListSerializer
queryset = Blog.published.all()
permission_classes = [permissions.IsAuthenticatedOrReadOnly]

Django REST Framework does not support writing to a nested serializer out of the box. You can check out DRF Writeable Nested, or write your own custom behavior on create by overwriting create() in the BlogListSerializer.
EDIT: Here's some more docs on the topic: https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers

Related

Django REST: Custom field, list may not be empty

I'm trying to add the employees field to my custom user model in Django REST 2.2. This is how I implemented my custom user (first answer). The employees field is just a list of custom users (so it's related to itself, with a many-to-many relationship).
When I try to add a custom user model from the django interface, it says "this list may not be empty". How can I make it so it can be empty? I thought that's what I added "required=False" for.
users/models.py
class CustomUser(AbstractUser):
employees = models.ManyToManyField("self", related_name='employees')
users/serializers.py (CustomRegisterSerializer is used for registering with rest-auth, CustomUserSerializer is used to view and edit)
class CustomRegisterSerializer(RegisterSerializer):
employees = serializers.RelatedField(many=True, required=False, queryset=CustomUser.objects.all())
def get_cleaned_data(self):
data_dict = super().get_cleaned_data()
data_dict['employees'] = self.validated_data.get('employees', '')
return data_dict
class CustomUserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('id', 'email', 'employees')
users/views.py
class CustomUserViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer

Django REST POST with PK to HyperlinkedModelSerializer, how to translate PK to URL?

I'm new to Django and Django REST. I have been creating a simple practice project.
Models:
class Locker(models.Model):
locker_owner = models.ForeignKey(User, related_name='lockers', on_delete=models.CASCADE)
locker_desc = models.CharField(max_length=100)
locker_rating = models.IntegerField(default=0)
Serializers:
class LockerSerializer(serializers.ModelSerializer):
locker_owner = serializers.HyperlinkedRelatedField(
view_name='user-detail',
lookup_field='id',
queryset=User.objects.all())
# how to add locker owner with id?
class Meta:
model = Locker
fields = ('url', 'locker_desc', 'locker_rating', 'locker_owner')
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'id', 'username', 'email', 'groups')
Views:
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
class LockerViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows lockers to be viewed or edited.
"""
# def create(self, request):
queryset = Locker.objects.all()
serializer_class = LockerSerializer
I use this to POST:
ttp -f POST localhost:8000/lockers/ locker_owner_id=2 locker_desc='desc of locker 3' locker_rating=150
But then the response is
"locker_owner": [
"This field is required."
]
Main Point:
I would like to create a new locker, and use User id as its locker_owner, yet still maintain the HyperlinkedModelSerializer. It won't let me, since they need url for locker_owner. Once I use hyperlink in the locker_owner of my POST request it works, but I don't know how to translate locker_owner=2 to it's url.
Any help would be appreciated. I have been looking for answers in days. Thank you!
This is not something you can do out-of-the-box. You will need to implement your own custom serializer Field, and override the to_representation method:
serializers.py
from rest_framework.reverse import reverse
class CustomRelatedField(serializers.PrimaryKeyRelatedField):
def to_representation(self, value):
return reverse('<your-user-detail-view-name>', args=(value.pk,), request=self.context['request'])
class LockerSerializer(serializers.ModelSerializer):
locker_owner = CustomRelatedField(queryset=User.objects.all())
class Meta:
model = Locker
fields = ('url', 'locker_desc', 'locker_rating', 'locker_owner')
You can then simply POST a simple JSON to create a new Locker object:
{
"locker_owner": 2,
"locker_desc": 'desc of locker 3',
"locker_rating": 150
}
I have found the solution myself looking at the tutorials available. The other answers have not really answered the question fully.
For those wanting to get url of a foreign key to be saved, here, locker_owner, just get them using hyperlinked related field
In my serializer:
class LockerSerializer(serializers.HyperlinkedModelSerializer):
locker_owner=serializers.HyperlinkedRelatedField(
read_only=True,
view_name='user-detail')
class Meta:
model = Locker
fields = ('locker_desc', 'locker_rating', 'locker_owner')
I was trying to get the id in the lookup field, but actually the lookup field is searching the id from my url. That's why it could not find it. Simple and done. Thank you for all the answers.

How to serialize the return value of a method in a model?

I have a Django app that uses Django REST Framework and Django-allauth. Now, I'm trying to retrieve the avatar URL that's present in the social account. However, I'm having trouble forming the serializer.
For background info, the allauth's SocialAccount is related to the user model via a foreign key:
class SocialAccount(models.Model):
user = models.ForeignKey(allauth.app_settings.USER_MODEL)
# the method I'm interested of
def get_avatar_url(self):
...
Now, here's the serializer I currently have:
class ProfileInfoSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'first_name', 'last_name')
In the end, I'd like to have an extra field avatar_url which takes the result of the method call in the SocialAccount model. How do I do that?
I found a solution using a SerializerMethodField:
class ProfileInfoSerializer(serializers.ModelSerializer):
avatar_url = serializers.SerializerMethodField()
def get_avatar_url(obj, self):
return obj.socialaccount_set.first().get_avatar_id()
class Meta:
model = User
fields = ('id', 'first_name', 'last_name', 'avatar_url')

django-restframework serialize display

when user goes to http://127.0.0.1:8000/movies/, I don't want to show the Showtimes
but when user goes to http://127.0.0.1:8000/movies/1/ , show it .
I want to ask if there is method to do this??
The method I use now is write 2 ModelSerializer to display it.
Please guide me . Thank you!!
This is my original code (not the 2 ModelSerializer method)
urls.py:
urlpatterns = patterns(
'',
url(r'^movies/$', MovieList.as_view(), name='movie-list'),
url(r'^movies/(?P<pk>[0-9]+)/$', MovieDetail.as_view(), name='movie-detail'),
This is my views.py :
class MovieMixin(object):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
class MovieFilter(django_filters.FilterSet):
class Meta:
model = Movie
fields = ['which_run',]
class MovieList(MovieMixin, generics.ListAPIView):
filter_class = MovieFilter
class MovieDetail(MovieMixin, generics.RetrieveAPIView):
pass
This is my serializes.py
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = ('id', 'title','Showtimes',)
You can do this with two serializers, by swapping out the serializer in the get_serializer_class method on the serializer. This will work with all generic views, including ViewSet instances. In your case, you can also just override serializer_class on the detail view with the custom serializer.
class MovieMixin(object):
queryset = Movie.objects.all()
class MovieList(MovieMixin, generics.ListAPIView):
filter_class = MovieFilter
serializer_class = MovieSerializer
class MovieDetail(MovieMixin, generics.RetrieveAPIView):
serializer_class = MovieDetailSerializer
There are also plugins that allow you to do this, the most notable being the one included with drf-extensions.
These will both require a new serializer that will handle just the detail view representation.
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = ('id', 'title', )
class MovieDetailSerializer(MovieSerializer):
class Meta(MovieSerializer.Meta:
fields = MovieSerializer.Meta.fields + ('Showtimes', )
This will allow you to have two different serialized responses for the list view and the detail view.

ForiegnKey field serializer in Django Rest framework

Before posting this question I've read few questions on SOF. but they are from 2012 and very confusing as well.
for e.g Django Rest Framework - Get related model field in serializer
my question is very straight forward
models.py
class User(models.Model):
username = models.CharField(max_length=100,unique=True)
password = models.CharField(max_length=100,null=False,blank=False)
class Car(models.Model):
user = models.ForeignKey(User)
car_name = models.CharField(max_length=100,null=True,blank=True)
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username','password' )
class CarSerializer(serializers.ModelSerializer):
#user = ?? what should I write or is there any better approach for serializing Car objects
class Meta:
model = Car
fields = ('user','car_name')
views.py
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
class CarViewSet(viewsets.ModelViewSet):
queryset = Car.objects.all()
serializer_class = CarSerializer
Please suggest all possible approaches.
1 more query. which one is better ModelSerializer or HyperlinkModelSerializer. as I saw different different answers containing these two.
You just need to do:
class CarSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Car
fields = ('user','car_name')
that is all.
Also, you should take a look to the kindnesses of serializers.Field and serializers.SerializerMethodField, you can play with them and customize your response data as much as you wish.
As to the question around HyperlinkedModelSerializer-ModelSerializer, very clear here:
The HyperlinkedModelSerializer has the following differences from ModelSerializer:
It does not include the pk field by default.
It includes a url field, using HyperlinkedIdentityField.
Relationships use HyperlinkedRelatedField, instead of PrimaryKeyRelatedField.
Hope that helps.

Categories