I have 3 models. One model is the User model, another is a Post model, and the other is a notifications model. I want to use Django's REST framework to show all of the notifications for the signed in user, plus each user that interacted with the signed in user.
class Notification(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='actors')
actor = models.ForeignKey(User, on_delete=models.CASCADE, related_name='users')
post = models.ForeignKey(Post, on_delete=models.CASCADE, blank=True, null=True)
type = models.ForeignKey(NotifType, on_delete=models.CASCADE)
is_read = models.BooleanField()
created_at = models.DateTimeField(auto_now_add=True)
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.CharField(max_length=200)
share_count = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
url = models.CharField(max_length=150)
serializers.py
class NotificationSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
views.py
class GetNotifications(ListAPIView):
serializer_class = NotificationSerializer
def get_queryset(self):
user = get_object_or_404(User, id=self.request.user.id)
return User.objects.select_related().filter(users__user=user).order_by("-users__created_at")
What I have currently returns all users who have interacted with the signed in user. However, it doesn't return the details about the notification. I want all details about each notification, including the details about the post. So the output should be something like this:
{
"post": {
"id": 1,
"status": "Hello!",
.
.
.
},
"user": {
"username": "Ben",
"avatar": "example.png"
.
.
},
is_read: 1,
created_at: 2017-07-21,
type: 2
}
change your view as:
class GetNotifications(ListAPIView):
serializer_class = NotificationSerializer
def get_queryset(self):
## user = get_object_or_404(User, id=self.request.user.id)
## i believe the above line is redundant, you can use self.request.user to access the loged-in user
return Notification.objects.select_related().filter(user=self.request.user).order_by("created_at")
then change your notification serializer as:
class NotificationSerializer(serializers.ModelSerializer):
class Meta:
model = Notification
exclude = ('user',)
depth = 1
or you can define new serializer for actor and post and use it like this:
class NotificationSerializer(serializers.ModelSerializer):
actor = ActorSerializer()
post = PostSerializer()
class Meta:
model = Notification
exclude = ('user',)
You define the serializer for user and posts. Your serializers.py should be
class NotificationSerializer(serializers.ModelSerializer):
post = PostSerializer()
user = UserSerializer()
class Meta:
model = Notification
fields = '__all__'
try this
class NotificationSerial(serializers.ModelSerializer):
class Meta:
model = Notification
fields = '__all__'
class PostSerial(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
class NotificationSerializer(serializers.ModelSerializer):
post = PostSerial(many=True, source='post_set')
user = NotificationSerial(many=True, source='actors')
class Meta:
model = User
fields = '__all__'
Related
Good day,
I would like to ask, if there's a possibility to gain additional data inside my serializers?
These are my models...
models.py
class Chair(models.Model):
name = models.CharField(max_length=100, null=False, blank=False, unique=True)
bookable = models.BooleanField(default=False)
user_created = models.CharField(max_length=100)
date_created = models.DateField(auto_now_add=True)
class Booking(models.Model):
chair = models.ForeignKey(Chair, on_delete=models.CASCADE)
day = models.DateField()
user_name = models.CharField(max_length=100)
user_created = models.CharField(max_length=100)
date_created = models.DateField(auto_now_add=True)
and these my serializers...
serializers.py
class BookingSerializer(serializers.ModelSerializer):
class Meta:
model = Booking
fields = '__all__'
class ChairSerializer(serializers.ModelSerializer):
class Meta:
model = Chair
fields = '__all__'
When making a request inside js like this...
views.py
#api_view(['GET'])
def bookings_by_date(request, pk):
bookings = Booking.objects.filter(day=pk)
serializer = BookingSerializer(bookings, many=True)
return Response(serializer.data)
script.js
let url = '...here's my url for Booking...';
fetch(url)
.then((resp) => resp.json())
.then(function(data) {
// do something here
});
...I would like to get not only the id of the Chair (models.Foreignkey), but also it's name. My first thought was doing something like this...
class ChairSerializer(serializers.ModelSerializer):
class Meta:
model = Chair
fields = [
...
'chair',
'chair__name',
...
]
...but this doesn't seem to work! Does anyone know a solution for my problem? Thanks for all your help and have a great weekend!
You can use one of this two ways:
1-) Using SerializerMethodField. You can add readonly fields with this way. You should add get_<field_name> method or give a method name that you want to run for this field with name keyword. You can look the document for more details.
class BookingSerializer(serializers.ModelSerializer):
chair__name = serializers.SerializerMethodField()
class Meta:
model = Booking
fields = '__all__'
def get_chair_name(self, obj):
return obj.chair.name
2-) Using CharField with source attribute:
You can define basically this field fill from where.
class BookingSerializer(serializers.ModelSerializer):
chair__name = serializers.CharField(source='chair__name')
class Meta:
model = Booking
fields = '__all__'
I'm trying to build a queryset which combines two query results, namely from Category and Course. Every Course has a Category foreign key. Is there a way to add the respective Courses to each Category?
Example:
{
"id": 61,
"name": "fgfdf",
"courses":
{
"id": 1,
"category": 61,
"title": "mytitle"
"active": true
},
{
...
}
}
Url
path('dict/<pk>/', DictView.as_view(), name='detail')
Models
class Category(models.Model):
name = models.CharField(max_length=255, blank=False, null=False)
class Course(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True)
title = models.CharField(max_length=255, blank=False, null=False)
active = models.BooleanField(default=True)
View
This is what I imagined but it's obviously incorrect, I've done some research but I couldn't find what I needed.
class DictView(RetrieveAPIView):
queryset = Category.objects.all()
serializer_class = CategorySerializer
def get_queryset(self):
queryset = Category.objects.all()
courses = list(Course.objects.filter(category=pk))
queryset['courses'] = courses;
return queryset
One way is defining serializers like this:
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = "__all__"
class CategorySerializer(serializers.ModelSerializer):
courses = CourseSerializer(source='course_set', many=True)
class Meta:
model = Category
fields = "__all__"
Then, you don't need to override get_queryset anymore.
If you wish to apply filters for courses, say you only want active courses, you can do the following:
class CategorySerializer(serializers.ModelSerializer):
courses = serializers.SerializerMethodField()
def get_courses(self, obj):
active_courses = obj.course_set.filter(active=True)
return CourseSerializer(active_courset, many=True).data
class Meta:
model = Category
fields = "__all__"
here is my models.py:
class Post(models.Model):
id = models.AutoField(primary_key=True)
body = models.TextField(max_length=10000)
date = models.DateTimeField(auto_now_add=True, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
liked_by = models.ManyToManyField(User, blank=True, related_name='liked_by')
class Meta:
ordering = ['-date']
serializers.py:
class PostSerializer(serializers.ModelSerializer):
user = UserSerializers()
total_likes = serializers.SerializerMethodField()
total_comments = serializers.SerializerMethodField()
class Meta:
model = Post
fields = ('id','body','date','user','total_likes','total_comments')
def get_total_likes(self, instance):
return instance.liked_by.count()
def get_total_comments(self, instance):
return instance.comment_set.count()
Q1: how do i check if a user exists in ManyToManyField of a single post?
Q2: shouldn't i use ManyToManyField in drf? then which would be better?
I don't have enough reps to comment, but if you have a post instance and a user instance, you could do something like:
post.liked_by.filter(id=user.id).exists()
Does that help you or are you asking where you should be implementing this? e.g. in your view or serializer etc...
i am trying to add CommentSerializer class to write comments with PostListSerializer , i want to display comment field bottom at every exist post
django:2.2
models.py
class Comment(models.Model):
id = models.UUIDField(default=uuid.uuid4,primary_key=True,editable=False)
author = models.ForeignKey(Account,on_delete=models.CASCADE,related_name='comments')
post= models.ForeignKey(Post,on_delete=models.CASCADE,related_name='comments')
comment_content = models.TextField(max_length=400)
commented_at = models.DateTimeField(auto_now_add=True)
edited_at = models.DateTimeField(auto_now=True)
image = models.ImageField(upload_to=random_url,blank=True,null=True)
parent = models.ForeignKey('self',null=True,blank=True,on_delete=models.CASCADE,related_name='replies')
active = models.BooleanField(default=True)
this is the serializers.py
class CommentCreateSerialzier(ModelSerializer):
class Meta:
model = Comment
fields = [
'comment_content','image'
]
class TripListSerializer(TaggitSerializer, GeoFeatureModelSerializerGIS):
tags = NewTagListSerializerField()
comments = SerializerMethodField()
detail_url = post_detail_url
user= SerializerMethodField()
class Meta:
model = Post
geo_field = 'location'
fields = [
'detail_url','user','name','city','tags','comments'
]
def get_user(self,obj):
return str(obj.user.username)
def get_comments(self,obj):
comment = Comment.objects.filter(post=obj,active=True)
comments = CommentSerialzier(comment,many=True).data
return comments
and this is my views.py
class CommentCreateSerializer(CreateAPIView):
serializer_class = CommentCreateSerialzier
message = 'you dont have permission to comment'
permission_classes = [IsAuthenticated]
def perform_create(self):
serializer.save(author=self.request.username)
how to add default post object in every single post ? and does it the same for replies as well
thanks for replying
These are my models and serializers. I want a representation of Question Model along with a list of people the question was asked to.
I am trying this:
#api_view(['GET', 'PATCH'])
def questions_by_id(request,user,pk):
question = Question.objects.get(pk=pk)
if request.method == 'GET':
serializer = QuestionSerializer(question)
return Response(serializer.data)
But I get an empty dictionary ({}). However when I remove the asked field from QuestionSerializer I get a complete representation of Question along with Places serialized nicely. What am I missing ?
class AskedToSerializer(serializers.ModelSerializer):
class Meta:
model = AskedTo
fields = ('to_user', 'answered')
class QuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
places = PlaceSerializer(many=True, required=False)
asked = AskedToSerializer(source='askedto_set', many=True)
fields = ('id', 'created_on', 'title', 'places', 'answered','asked')
extra_kwargs = {'created_by': {'read_only': True}}
class Question(BaseModel):
title = models.CharField(max_length=200, null=False)
places = models.ManyToManyField(Place, blank=True)
answered = models.BooleanField(default=False)
class AskedTo(BaseModel):
ques = models.ForeignKey(Question, on_delete=models.CASCADE)
to_user = models.ForeignKey(settings.AUTH_USER_MODEL)
replied = models.BooleanField(default=False)
class Place(models.Model):
g_place_id = models.CharField(max_length=20,primary_key=True)
json = models.TextField(null=True)
name = models.CharField(max_length=40)
I figured it out. There were two errors.
Changed this:
class AskedToSerializer(serializers.ModelSerializer):
class Meta:
model = AskedTo
fields = ('to_user', 'answered')
to this (notice the change in fields, fields on model and serializer didn't match)
class AskedToSerializer(serializers.ModelSerializer):
class Meta:
model = AskedTo
fields = ('to_user', 'replied')
Secondly, I needed to define any extra fields outside class Meta
class QuestionSerializer(serializers.ModelSerializer):
places = PlaceSerializer(many=True, required=False)
asked = AskedToSerializer(source='askedto_set', many=True)
class Meta:
model = Question
fields = ('id', 'created_on', 'title', 'places', 'answered','asked')
extra_kwargs = {'created_by': {'read_only': True}}
Notice the change in definition of places and asked.
In my case, I have this models.py:
class Section(models.Model):
title = models.CharField(max_length=500)
description = models.TextField(blank=True)
user = models.ForeignKey(Profile, related_name="sections", on_delete=models.CASCADE)
class Feed(models.Model):
title = models.CharField(max_length=500)
link_rss = models.URLField(max_length=500)
link_web = models.URLField(max_length=500)
description = models.TextField(blank=True)
language = models.CharField(max_length=50, blank=True)
logo = models.URLField(blank=True)
sections = models.ManyToManyField(Section, related_name="feeds")
And I completed the serializers.py this:
class FeedSerializer(serializers.ModelSerializer):
sections = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Feed
fields = '__all__'
class SectionSerializer(serializers.ModelSerializer):
feeds = FeedSerializer(many=True, read_only=True)
class Meta:
model = Section
exclude = ('user',)