I created a serializer which the "user" below is from another Serializer which i imported, now the imported serializer(PubliceProfileSerializer) works fine on its own but it does not display the content of USER when i call it my browser from this serializer. Every other item shows except the user. Please help
from rest_framework import serializers
from users.api.serializers import PublicProfileSerializer
from blog.models import Post
class PostSerializer(serializers.ModelSerializer):
user = PublicProfileSerializer(source='users.profile', read_only=True)
category = serializers.SerializerMethodField()
label = serializers.SerializerMethodField()
class Meta:
model = Post
fields = '__all__'
def get_category(self, obj):
return obj.get_category_display()
def get_label(self, obj):
return obj.get_label_display()
Add you your serializer the list of fields. Replace
fields = '__all__'
with
fields = ('id', 'user', 'category', 'label')
because:
fields = '__all__'
will only populate id, category and label from the Post model, but will not provide the nested user serializer, so it becomes:
class Meta:
model = Post
fields = ('id', 'user', 'category', 'label')
or
class PostSerializer(serializers.ModelSerializer):
user = PublicProfileSerializer(many=False,
source='users.profile',
read_only=True)
category = serializers.SerializerMethodField()
label = serializers.SerializerMethodField()
class Meta:
model = Post
fields = ('id', 'user', 'category', 'label')
def get_category(self, obj):
return obj.get_category_display()
def get_label(self, obj):
return obj.get_label_display()
Related
I have a tow classes , the relationship between them many to many field , i wont to post data in this way
{"first_name":"mohammad", "last_name":"alqudah", "motivate":[ "Stay Fit","Look Younger" ] } instead of this way
{"first_name":"mohammad", "last_name":"alqudah", "motivate":[ 1,2 ] }
my Serializers
class MotivateSerializers(serializers.ModelSerializer):
class Meta:
model = Motivate
fields = ['name']
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = User
fields = ['lat','long','first_name','last_name','mobile_number','email','date_of_birth',
'gender','height','weight','relationship','number_of_household','number_of_pets','kind_of_pets','motivate']
my views.py
#api_view(['POST', ])
#permission_classes([IsAuthenticated])
def userdata(request):
user = request.user
serializer = UserSerializers(instance=user, data=request.data,many=False)
if serializer.is_valid():
serializer.save()
return Response("Data has been updated successfully")
else:
# print (serializer.errors)
return Response(serializer.errors)
You can use SlugRelatedField. Example:
class UserSerializers(serializers.ModelSerializer):
# New
motivate = serializers.SlugRelatedField(
slug_field="name",
queryset=Motivate.objects.all()
many=True
)
class Meta:
model = User
fields = [
"first_name", "last_name",
...
"motivate"
]
I use below solution to check is the user viewed the post or not.
Best way to make "viewed" attribute for messages inside user group?
and in django-rest-framework, i create a ListApiView to get all posts:
class PostListView(ListAPIView):
serializer_class = PostSerializer
permission_classes = (IsAuthenticated, )
pagination_class = PostListPagination
def get_queryset(self):
return Post.objects.filter(state='published').order_by('-created')
and the serializers:
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields= '__all__'
now i want a boolean field named "viewed" for each post in PostListView to show that is the authenticated user viewed this post or not.
something like this:
class PostSerializer(serializers.ModelSerializer):
viewed = serializers.BooleanField(read_only=True)
class Meta:
model = Post
fields= '__all__'
def check_is_viewed(current_user, post_instance):
# if user viewed this post:
viewed.value = True
# else:
viewed.value = False
You could use MethodField.
class PostSerializer(serializers.ModelSerializer):
viewed = serializers.SerializerMethodField()
class Meta:
model = Post
fields= '__all__'
def get_viewed(self, obj):
return obj.viewers.exist()
I have a model and viewset related to this model,
here is my code :
class EMAILTemplate(models.Model):
""" Message SMS Template """
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
body = models.TextField()
tokens = models.TextField()
created = models.DateTimeField(auto_now_add=True)
def save(self, *args, **kwargs):
self.tokens = ",".join(re.findall(r'{{\s*(.*?)\s*}}', self.body))
super().save(*args, **kwargs)
I don't want field tokens to be in my create form in Django rest framework create or edit form, because as you see It's going to be extracted from body field.
but I want to have this field in view single model or list of models.
and here is my ModelSerializer :
class EmailTemplateSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = EMAILTemplate
fields = ('name', 'body', 'user', 'tokens')
You can specify tokens as read only field:
class EmailTemplateSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = EMAILTemplate
fields = ('name', 'body', 'user', 'tokens')
read_only_fields = ('tokens',)
You can overwrite the current to_representation method
class EmailTemplateSerializer(serializers.HyperlinkedModelSerializer):
def to_representation(self, obj):
try:
if self.context['view'].action in ['list', 'detail']:
# get the original representation
ret = super(serializers.HyperlinkedModelSerializer, self).to_representation(obj)
# remove 'tokens' field
ret.pop('tokens')
return ret
except KeyError:
return super(serializers.HyperlinkedModelSerializer, self).to_representation(obj)
return super(serializers.HyperlinkedModelSerializer, self).to_representation(obj)
I want to save a sent json data to db by django-rest-framework.
the problem is, not saving the relation and returns error.
The bellow snippet is my models:
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='profile', on_delete=models.CASCADE)
name = models.CharField(max_length=30)
family = models.CharField(max_length=50)
class Klass(models.Model):
title = models.CharField(max_length=50)
description = models.CharField(max_length=500)
teacher = models.ForeignKey(Profile, related_name='teacher', on_delete=models.CASCADE)
I use below serializer for serializing/deserializing the Klass model.
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('pk', 'name', 'family')
class KlassSerializer(serializers.ModelSerializer):
teacher = ProfileSerializer()
class Meta:
model = Klass
fields = ('id', 'title', 'description', 'teacher')
now when I prepare a JSON object and send it to the view, it returns error. the below is the view class:
class KlassView(APIView):
"""for SELECT, INSERT Queries"""
def get(self, request, pk):
# somthing
#csrf_exempt
def post(self,request, pk=None):
"""For Creating A Class"""
serializer = KlassSerializer(data=request.data)
if serializer.is_valid():
teacher = ProfileSerializer(request.data['teacher']['pk'])
serializer.teacher = teacher.data
serializer.save()
return Response({'data': serializer.data})
else:
return Response({'data': serializer.errors})
and the error is:
The .create() method does not support writable nested fields by default.
Write an explicit .create() method for serializer mainp.serializers.KlassSerializer, or set read_only=True on nested serializer fields.
How can I save relation in KlassSerializer in order to save to db?
At first change your serializer like below:
class KlassSerializer(serializers.ModelSerializer):
# teacher = ProfileSerializer() # No need to this!
class Meta:
model = Klass
# fields = ('id', 'title', 'description', 'teacher')
fields = ('id', 'title', 'description') # Omit teacher
Then get profile from requested user and pass it to your serializer:
def post(self,request, pk=None):
"""For Creating A Class"""
serializer = KlassSerializer(data=request.data)
if serializer.is_valid():
teacher = ProfileSerializer(request.data['teacher']['pk'])
serializer.teacher = teacher.data
serializer.save(teacher=request.user.profile) # Retrieve teacher and stroe
return Response({'data': serializer.data})
else:
return Response({'data': serializer.errors})
Just override the create method of ModelSerializer in KlassSerializer.
class KlassSerializer(serializers.ModelSerializer):
teacher = ProfileSerializer()
class Meta:
model = Klass
fields = ('id', 'title', 'description', 'teacher')
def create(self, validated_data):
profile = Profile.objects.filter(pk=validated_data['teacher']['pk'])
if profile:
k = Klass()
k.teacher = profile
...
I've got two models: User and Ticket. Ticket has one User, User has many Tickets
I've accomplished that when i go to url /users/1/tickets, i'm getting the list of user's tickets.
I want to use hyperlinked relations, and here is what i see in my User model representation:
"tickets": [
"http://127.0.0.1:8000/tickets/5/",
"http://127.0.0.1:8000/tickets/6/"
]
But I want it to be like
"tickets": "http://127.0.0.1:8000/users/1/tickets"
Is there a way to do that with DRF?
The url:
url(r'^users/(?P<user_pk>\d+)/tickets/$',
views.TicketsByUserList.as_view(),
name='myuser-tickets'),
The view:
class TicketsByUserList(generics.ListAPIView):
model = Ticket
serializer_class = TicketSerializer
def get_queryset(self):
user_pk = self.kwargs.get('user_pk', None)
if user_pk is not None:
return Ticket.objects.filter(user=user_pk)
return []
User serializer (i tried to play with tickets field definition, changing type, view_name, but with no effect):
class UserSerializer(serializers.HyperlinkedModelSerializer):
tickets = serializers.HyperlinkedRelatedField(many=True, view_name='ticket-detail')
class Meta:
model = MyUser
fields = ('id', 'nickname', 'email', 'tickets')
Ticket serializer:
class TicketSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.HyperlinkedRelatedField(view_name='myuser-detail')
liked = serializers.Field(source='liked')
class Meta:
model = Ticket
fields = ('id', 'user', 'word', 'transcription', 'translation', 'liked', 'created', 'updated')
You can use a SerializerMethodField to customize it. Something like this:
class UserSerializer(serializers.HyperlinkedModelSerializer):
tickets = serializers.SerializerMethodField('get_tickets')
def get_tickets(self, obj):
return "http://127.0.0.1:8000/users/%d/tickets" % obj.id
class Meta:
model = MyUser
fields = ('id', 'nickname', 'email', 'tickets')
I hard-wired the URL in there for brevity, but you can do a reverse lookup just as well. This basically just tells it to call the get_tickets method instead of the default behavior in the superclass.
For the record, here is an example of the full solution based on Joe Holloway's answer:
from rest_framework.reverse import reverse
class WorkProjectSerializer(serializers.CustomSerializer):
issues = drf_serializers.SerializerMethodField()
def get_issues(self, obj):
request = self.context.get('request')
return request.build_absolute_uri(reverse('project-issue-list', kwargs={'project_id': obj.id}))
class Meta:
model = WorkProject
fields = '__all__'