Providing custom field in serializer using model data - python-3.x

In Problem model I'm storing a list of users who have done it. In Problem serializer when user will request his data I want to show him if he has done certain problem. So I created custom field in serializer class and want to fill it using models data.
this is what I have done.
from rest_framework import serializers
from dsa.models import Problem
class ProblemSerializer(serializers.ModelSerializer):
isDoneByUser = serializers.BooleanField(default=False)
class Meta:
model = Problem
fields = ['id', 'topic', 'title', 'link', 'isDoneByUser']
def perform_create(self, serializer):
user = self.request.user
userlist = serializer.data.get('isDone')
print(userlist)
if user in userlist:
self.isDoneByUser = True
here is the model
from django.db import models
from django.contrib.auth.models import User
class Problem(models.Model):
topic = models.CharField(max_length=100)
title = models.CharField(max_length=100)
link = models.URLField()
isDone = models.ManyToManyField(User)
class Meta:
ordering = ['topic']
But this always setting isDoneByUser = False(default value)
please help!

You cannot set isDoneByUser to True as it does not exist in your model.
You can however get the boolean with a SerializerMethodField:
class ProblemSerializer(serializers.ModelSerializer):
isDoneByUser = serializers.SerializerMethodField()
def get_isDoneByUser(self, instance):
user = self.context['request'].user
return instance.isDone.filter(pk=user.pk).exists()
class Meta:
model = Problem
fields = ['id', 'topic', 'title', 'link', 'isDoneByUser']

Related

Error: (admin.E035) The value of 'readonly_fields[0]' is not a callable

Summarize the problem
<class 'news.admin.NewsAdmin'>: (admin.E035) The value of 'readonly_fields[0]' is not a callable, an attribut
e of 'NewsAdmin', or an attribute of 'news.News'.
This all code error. I learn Django, and write code how in author. But write this error :(
Describe what you`ve tried
I immediately insert problem in search, but not found decision
I read this question, but it not finished
This question elementary, author question not correct write variable
Show some code
admin.py
from django.contrib import admin
from .models import News, Category
class NewsAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'category', 'create_at', 'updated_at', 'is_published')
list_display_links = ('id', 'title',) # what be links in model
search_fields = ('title', 'content',)
list_editable = ('is_published',) # redact is published in menu
list_filter = ('is_published', 'category',) # create table, what in be setting sorted
fields = ('title', 'category', 'content', 'photo', 'get_photo', 'is_published', 'views',
'create_at', 'updated_at')
readonly_fields = ('get_photo', 'views', 'create_at', 'updated_at')
class CategoryAdmin(admin.ModelAdmin):
list_display = ('id', 'title') # displays
list_display_links = ('id', 'title') # links
search_fields = ('title',)
admin.site.register(News, NewsAdmin)
admin.site.register(Category, CategoryAdmin)
models.py
from django.db import models
from django.urls import reverse
class News(models.Model):
title = models.CharField(max_length=150)
content = models.TextField(blank=True)
create_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
photo = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
is_published = models.BooleanField(default=True)
category = models.ForeignKey('Category', on_delete=models.PROTECT)
views = models.IntegerField(default=0)
def get_absolute_url(self):
return reverse('view_news', kwargs={"news_id": self.pk})
def __str__(self): # return number position model
return self.title
objects = models.Manager()
class Meta:
verbose_name = 'NEWS'
verbose_name_plural = 'NEWS'
ordering = ['-create_at']
class Category(models.Model):
title = models.CharField(max_length=150, db_index=True, verbose_name='Title category')
def get_absolute_url(self):
return reverse('category', kwargs={"category_id": self.pk})
class Meta:
verbose_name = 'Category'
verbose_name_plural = 'Categories'
ordering = ['title']
def __str__(self): # String views. If not be this parameters, be number vice world
return self.title
Since you've put 'get_photo' in NewsAdmin.read_only_fields and it is not a model field, it's supposed to be a method or a property in either News or NewsAdmin.
You should change it to 'photo' because read_only_fields only meant for fields to be non-editable.
class NewsAdmin(admin.ModelAdmin):
...
readonly_fields = ('photo', 'views', 'create_at', 'updated_at')
Try to add 'views' to list_display.
Probably a field can't be in read_only_fields unless it's shown in list_display.

How to join two tables in django and serialize the same using one serializer?

I have been learning django and django rest framework since couple of weeks and I want to figure out how can I join two tables and serialize the data of same to return the json response using django rest framework.
I want to return result as json response:
{ 'user_id_id': 1, 'request_msg': 'Hi', 'response_msg': "Hi, Welcome" }
where result is
from django.db import connection
cursor = connection.cursor()
con = cursor.execute("SELECT backend_request_messages.user_id_id, backend_request_messages.request_msg as request_msg,backend_response_messages.response_msg as response_msg FROM backend_request_messages,backend_response_messages Where backend_request_messages.user_id_id=backend_response_messages.user_id_id=1 ")
Here is what I have tried :
#backend/Models.py
class User(models.Model):
username = models.CharField(max_length=50)
name = models.CharField(max_length=50, blank=True, null=True)
uid = models.CharField(max_length=12, blank=True, null=True)
age = models.CharField(max_length=3, blank=True, null=True)
active = models.BooleanField(default=True)
class Meta:
default_related_name = 'users'
def __str__(self):
return self.name
class Request_Messages(models.Model):
request_msg = models.CharField(max_length=100)
request_msg_created_at = models.DateTimeField(auto_now_add=True)
user_id = models.ForeignKey(
User, on_delete=models.CASCADE, null=True)
class Meta:
default_related_name = 'request_messages'
def __str__(self):
return self.request_msg
class Response_Messages(models.Model):
response_msg = response_msg = models.CharField(max_length=400)
response_msg_created_at = models.DateTimeField(auto_now_add=True)
user_id = models.ForeignKey(
User, on_delete=models.CASCADE, null=True)
class Meta:
default_related_name = 'response_messages'
def __str__(self):
return self.response_msg
#backend/serializers.py
class ListSerializer (serializers.Serializer):
user_id_id = serializers.IntegerField()
request_msg = serializers.CharField(max_length=100)
# request_msg_created_at = serializers.DateTimeField(read_only=True)
response_msg = serializers.CharField()
# response_msg_created_at = serializers.DateTimeField(read_only=True)
#backend/views.py
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Response_Messages, Request_Messages, User
from .serializers import ListSerializer
from django.db import connection
#api_view(['GET', 'POST'])
def chatbot(request):
if request.method == 'GET':
cursor = connection.cursor()
query_set = cursor.execute("SELECT backend_request_messages.user_id_id, backend_request_messages.request_msg as request_msg,backend_response_messages.response_msg as response_msg FROM backend_request_messages,backend_response_messages Where backend_request_messages.user_id_id=backend_response_messages.user_id_id=1 ")
columns = [column[0] for column in query_set.description]
results = []
for row in query_set.fetchall():
results.append(dict(zip(columns, row)))
serializer = ListSerializer(results)
return Response(serializer.data)
About serializers, You should refer to the docs (they're awesome and explain it best).
To give you a direction, I like to create a serializer for every model and if it's related to another model, I refer that in serializer, that way, You can easily customize behavior for each model (although not the only way at all).
So, about serializing I would do the following (notice my comments as well):
from django.contrib.auth.models import User
class User(User):
# Your user class, except, it should inherit Django's User/AbstractUser class.
class RequestMessages(models.Model):
request_msg = models.CharField(max_length=100)
request_msg_created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(
User, on_delete=models.CASCADE, null=True, related_name='requests_msg')
# NOTICE THE NEW RELATED NAME, WE'LL USE IT LATER.
class Meta:
default_related_name = 'request_messages'
def __str__(self):
return self.request_msg
class ResponseMessages(models.Model):
response_msg = response_msg = models.CharField(max_length=400)
response_msg_created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='responses_msg')
def __str__(self):
return self.response_msg
class RequestMsgSerializer(serializers.ModelSerializer):
# Specify what ever you like...
class Meta:
model = RequestMessages
fields = # Whatever you like to serialize.
class ResponseMsgSerializer(serializers.ModelSerializer):
class Meta:
model = ResponseMessages
fields = # Whatever you want serialized.
class UserSerializer(serializers.ModelSerializer):
# Using required = False will cause that every time you create a user they don't have to own messages.
requests_msg = RequestMsgSerializer(many=False, required=False)
responses_msg = ResponseMsgSerializer(many=False, required=False)
class Meta:
model = User
field = # Same as above ..
About your query, using raw SQL in Django is rear, usually, in most cases the Django built-in ORM will do the job and usually faster and better than you.
In your case, if you'll call your query like this for exmaple:
query_set = User.objects.filter(user=request.user)
the QuerySet object created will hit the DB one for the user object and X queries for all the associated messages with said user, so expensive.
But no need for a custom query with joins and stuff like that, Django has prefetch_related and select_related.
exmaple:
query_set = User.objects.filter(user=request.user).prefetch_related('requests_msg')
will reduce all the queries made for request messages associated to a user to only one!
Recap:
I wrote a lot because I'm still learning this stuff myself self and if you teach others you got it!
Refer to DRF's docs about serializers (there's even a dedicated section for nested serializers) and API Views, they really great.
Refer to Django's docs about prefetch related, select related and queries in general, again, Amazing docs that cover everything.
Don't just copy my code or anyone else's, there's no problem with that, just make sure you understand it first if not, you're bound to get stuck with it again!

Django rest frame work; Combining data from different models doesnot work

I tried combining data from two models. the serializers look like this.
class FindOwnerSaveSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'first_name', 'last_name','image')
#fields = ('__all__')
class SaveSerializer(serializers.ModelSerializer):
content = FindOwnerSaveSerializer(source='user',read_only=True)
class Meta:
model = Save
fields = ('project_id','content')
The save model looks like this
class Save(models.Model):
project_id = models.ForeignKey(Project, on_delete=models.DO_NOTHING)
user_id = models.ForeignKey(User, on_delete=models.DO_NOTHING)
and the view looks like this
class SaveView(UpdateAPIView):
serializer_class = SaveSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
try:
return Save.objects.filter(user_id=self.request.user)
except Exception as e:
logger.error(e)
return Response(data='false')
def get_object(self):
try:
if Project.objects.get(project_id=self.request.data['project_id']):
return Response(data='true')
except Exception as e:
logger.error(e)
return Response(data='false ')
the response keep looking like this. No user data is comming in.
[
{
"project_id": 78
}
]
What could be the problem.Iam using django 2.2.7 and rest framwework 3.10.3.
The problem with your source referrence, it should be source='user_id' not source='user'
class SaveSerializer(serializers.ModelSerializer):
content = FindOwnerSaveSerializer(source='user_id',read_only=True) # not `source='user'`
class Meta:
model = Save
fields = ('project_id','content')

DRF use nested serializer to create key object instead of array

Context
Say we take this example from the DRF relations guide.
# models.py
class Album(models.Model):
album_name = models.CharField(max_length=100)
artist = models.CharField(max_length=100)
class Track(models.Model):
album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
order = models.IntegerField()
title = models.CharField(max_length=100)
duration = models.IntegerField()
class Meta:
unique_together = ('album', 'order')
ordering = ['order']
def __str__(self):
return '%d: %s' % (self.order, self.title)
Using a serializer will get us this output
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.StringRelatedField(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
Will get us this output:
{
'album_name': 'Things We Lost In The Fire',
'artist': 'Low',
'tracks': [
'1: Sunflower',
'2: Whitetail',
'3: Dinosaur Act',
...
]
}
Question
How can i use the serializer to get the output like this:
{
'album_name': 'Things We Lost In The Fire',
'artist': 'Low',
'tracks': {
1: {order: 1, title: 'Sunflower'},
2: {order:2, title: 'Whitetail'},
3: {order:3, title: 'Dinosaur Act'},
...
}
}
This way we have an object with tracks instead of a numeric array. So i can do this.props.album.tracks[2].title this instead of this.props.album.tracks.find(track => track.order == 2}).title in javascript.
``I have an use case in where this seems to be more convenient in Reactjs.
What i have tried
I thought about overriding the to_representation method. But i see that this will get me an recursive loop.
class TrackSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
print(self)
return '%s: { %s }' % (instance.order, self.to_representation(instance))
class Meta:
fields = '__all__'
model = Track
Furthermore i have searched and read the docs pretty well. But didn't find any solution for what i think should be a pretty logical solution to have out of the box. Making me think that i am wrong and missing something.
Thanks in advance.
Define a new TrackSerializer and use it in AlbumSerializer class as,
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ('id', 'order', 'title')
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['tracks'] = {track['id']: track for track in representation['tracks']}
return representation

instance expected, got OrderedDict Django Rest Framework writable nested serializers

I am creating a survey kind of app, so i have three models Form, Questiosn, Choices[for multiple choice questions]
I followed this tutorial http://www.django-rest-framework.org/api-guide/relations/#nested-relationships
It works fine for 1 level nested relations, but for 2 levels it gives
TypeError: 'Choice' instance expected, got OrderedDict([(u'title', u'option1')])
class ChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = ['title']
class QuestionSerializer(serializers.ModelSerializer):
choices = ChoiceSerializer(many=True, required=False)
class Meta:
model = Question
fields = ['title', 'type', 'required','order','choices']
def create(self, validated_data):
choices_data = validated_data.pop("choices")
question = Question.objects.create(**validated_data)
for choice_data in choices_data:
Choice.objects.create(question=question, **choice_data)
return question
class FormSerializer(serializers.ModelSerializer):
questions = QuestionSerializer(many=True)
class Meta:
model = Form
fields = ['title', 'description', 'created', 'active', 'hash','questions']
read_only_fields = ['active','hash']
def create(self, validated_data):
questions_data = validated_data.pop('questions')
form = Form.objects.create(**validated_data)
for question_data in questions_data:
Question.objects.create(form=form, **question_data)
return form
EDIT
Solved using the manual way, In FormSerializer override the create method,
#transaction.atomic
def create(self, validated_data):
try:
with transaction.atomic():
questions_data = validated_data.pop('questions')
form = Form.objects.create(**validated_data)
for question_data in questions_data:
question = Question.objects.create(form=form,
title=question_data['title'],
type=question_data['type'],
required=question_data['required'])
if question.type == Question.RADIO or question.type == Question.CHECKBOX:
choices_data = question_data.pop('choices')
for choice_data in choices_data:
choice = Choice.objects.create(question=question, title=choice_data['title'])
return form
except Exception, e:
raise serializers.ValidationError("Cannot Save Form %s" % e)
I also struggled with this and I believe the proper way to handle this is:
class ChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = ['title']
class QuestionSerializer(serializers.ModelSerializer):
choices = ChoiceSerializer(many=True, required=False)
class Meta:
model = Question
fields = ['title', 'type', 'required','order','choices']
class FormSerializer(serializers.ModelSerializer):
questions = QuestionSerializer(many=True)
class Meta:
model = Form
fields = ['title', 'description', 'created', 'active',
'hash','questions']
read_only_fields = ['active','hash']
def create(self, validated_data):
questions_data = validated_data.pop('questions')
form = Form.objects.create(**validated_data)
for question_data in questions_data:
choices_data = question_data.pop('choices')
Question.objects.create(form=form, **question_data)
for choice_data in choices_data:
choice = Choice.objects.create(question=question, **choice_data)
return form
An easy way to screw this up is to not pop choices before creating the Question object. When you do that, you'll get an instance expected, got OrderedDict( 500 error.
Note also that you do not need to define create() on the QuestionSerializer. All child processing is done at the top level.

Resources