How to make Django Rest API fore nested comments? - django

I want to make a nested comment model for an android app and I am using Django Rest framework. I have defined two models Post and Comment as follow:
class Post(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
author = models.ForeignKey('CustomUser',on_delete=models.CASCADE, related_name="author")
created_at = models.DateTimeField(auto_now=True, editable=False)
tag = models.ForeignKey('Tag', on_delete=models.CASCADE, blank=True, null=True)
class Comment(models.Model):
p_post = models.ForeignKey('Post', on_delete=models.CASCADE)
description = models.TextField()
author = models.ForeignKey('CustomUser', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True, editable=False)
p_comment_id = models.ForeignKey('self', blank=True)
is_anon = models.BooleanField(default=False)
What I am having problem is if I want to get the list of comments on app, so, how should I deal with it? I have following points in my head:
I can not return the complete list of comments, as it will be a very long list
So, how do I chose to restrict to return top 5 comments along with their top 5 child comments.

If you add related_name to p_post:
p_post = models.ForeignKey('Post', on_delete=models.CASCADE, related_name="comments")
You will be able to loop through them like so:
for post in Post.objects.order_by('created_at').all()[0:5]:
for comment in post.comments.order_by('created_at').all()[0:5]:
print(comment.description) # do whatever you want with comment
Note: [0:5] for limiting to the top 5
You also will want to prefetch the comments when querying for posts: Post.objects.prefetch_related('comments')
Edit:
Reading your question again, I see that this is for an API response. I would look into rest_framework.serializers.ModelSerializer
class CommentSerialzier(serializers.ModelSerializer):
class Meta:
model = Comment
class PostSerializer(serializers.ModelSerializer):
comments = CommentSerializer(many=True)
class Meta:
model = Post

Related

Django Filtering to Get Popular Posts

I have two different models. HitCount model stores IP addresses whose was viewed Post. And what i want is filtering popular 3 posts which viewed more. I've tried some queries but i couldn't. I am sharing my models with you.
class Post(ModelMeta, models.Model):
title = models.CharField(max_length=255, verbose_name='Başlık', unique=True)
slug = models.SlugField(max_length=255, unique=True)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='blog_posts', verbose_name="Yazarı")
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='blog_posts',
verbose_name="Kategorisi", null=True)
tags = models.ManyToManyField(Tag, related_name='blog_posts', verbose_name='Etiketler')
image = models.ImageField(verbose_name='Fotoğraf (800x460)')
content = RichTextField()
description = models.TextField(null=True)
status = models.IntegerField(choices=STATUS, default=0, verbose_name='Yayın Durumu')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='Oluşturulma Tarihi')
updated_at = models.DateTimeField(auto_now=True, verbose_name='Güncellenme Tarihi')
#property
def get_hit_count(self):
return HitCount.objects.filter(post=self).count()
class HitCount(models.Model):
ip_address = models.GenericIPAddressField()
post = models.ForeignKey("Post", on_delete=models.CASCADE)
def __str__(self):
return f'{self.ip_address} => {self.post.title}'
You can try something like this :
most_viewed_posts = Post.objects.all().order_by('-get_hit_count')[3]
I don't think that you can order by 'get_hit_count', but I think those questions can help you : Django order_by a property
Using a Django custom model method property in order_by()
I did what i want with sorted method. Thanks Alexandre Boucard for the resources.
Solution;
sorted(Post.objects.filter(status=1), key=lambda a: a.get_hit_count, reverse=True)
reverse=False as a default and it sorts ascending in this case i want to get reversed so i used reverse=True

How does one count a foreign key item, esp 'author' created with Django's User model?

Need help getting a better grip with 1) accessing and counting foreign key items in Django and 2) counting foreign key item that is created through Django's built-in User:
#1)
The answer here suggests using Django's annotate function: eg. questions = Question.objects.annotate(number_of_answers=Count('answer')) (question being a foreign key item to answer). But it is not clear to me where this line belongs to (in the case of the example, question or answer), or which part of an app-models.py or views.py. I tested in both models.py and views.py
Here are my models (only the essential lines here):
class Post(models.Model):
post = models.TextField(max_length=1000)
author = models.ForeignKey(User, related_name="author", on_delete=models.CASCADE)
class Comment(models.Model):
comment = models.TextField(max_length=1000)
commenter = models.ForeignKey(User, on_delete=models.CASCADE)
post_connected = models.ForeignKey(Post, related_name='posts', on_delete=models.CASCADE, default=None, null=True)
#2) How does one count a foreign key item created using Django's built-in model, User?
Should I have created a model called "Author" first?
I want to tell you something about related_name:
related_name help you access objects of another model for example
class Post(models.Model):
post = models.TextField(max_length=1000)
author = models.ForeignKey(User, related_name="posts", on_delete=models.CASCADE)
class Comment(models.Model):
comment = models.TextField(max_length=1000)
commenter = models.ForeignKey(User, on_delete=models.CASCADE)
post_connected = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE, default=None, null=True)
with modelobject.related_name.all() get objects of another models in this example userobject.posts.all() you can get all post related to user object.
and with post.comments.all() can get all comments related to the post.

How can I show a dropdown in my form with the title of the objects in the table? Django ModelForm

Hi I've been trying to create a simple app for workflows or binary protocols (yes or no instructions, very helpful sometimes)
I have created a simple form with ModelForm:
class BlocForm(forms.ModelForm):
class Meta:
model = Bloc
fields = [
'description',
'loop_child'
]
and my model looks like this:
class Loopeable(models.Model):
protocol = models.ForeignKey(Protocol, on_delete=models.CASCADE, null=True)
description = models.TextField()
pointing_at = models.IntegerField()
class Bloc(models.Model):
description = models.TextField()
protocol = models.ForeignKey(Protocol, on_delete=models.CASCADE)
parent = models.ForeignKey('self',on_delete=models.CASCADE, null=True, blank=True)
loop_child = models.ForeignKey(Loopeable, on_delete=models.CASCADE, null=True, blank=True)
question = models.BooleanField(default=False)
end_bloc = models.BooleanField(default=False)
And my problem is that instead of having this loop_chile dropdown list of ugly objects I would like to get the description in the Loopeable Model, is there a way to get some data that is not just "Loopeable Object (id_number)". I didn't add my views.py in order to keep the post short, but I implemented the for by simply doing something like:
form = BlocForm(request.POST or None)
if form.is_valid(): ...rest of the code
If anyone has some ideas I will be grateful!! Thanks...

Django - Show only a specific dynamic fields per models in django-eav2

I'm trying to figure it out on how I can show only a specific set of dynamic fields in eav to a unique registered model in my apps.models. But I don't know how to this, I've also read the documents but I can't seem to find anything about it, or maybe I've come across it and didn't understand.
Now, what is happening is that, when I add an attribute in the django admin. It also adds the dynamic field in all the models registered in the eav.
What I want to do is that;
model 1 - dynamic_field1, dynamic_field2, dynamic_field3
model 2 - dynamic_field4, dynamic_field5, dynamic_field6
Btw, I'm currently using the django-eav2 the documentation is in the link. I've found my solution for my initial use case here link
Below codes are basically on how to register my models to the eav. Here is my sample models
class ClientName(models.Model):
name = models.CharField(max_length=250, null=True, blank=True)
description = models.TextField(null=True, blank=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return str(self.name)
class CallDetails(models.Model):
client_name = models.ForeignKey(ClientName, on_delete=models.PROTECT, null=True, blank=True, db_index=True)
letter_info = models.TextField(null=True, blank=True)
def __str__(self):
return str(self.client_name)
class Meta:
verbose_name = 'Call Detail'
ordering = ['client_name']
eav.register(ClientName)
eav.register(CallDetails)
below is my admin.py
class CallDetailsAdminForm(BaseDynamicEntityForm):
model = CallDetails
class CallDetailsAdmin(BaseEntityAdmin):
form = CallDetailsAdminForm
admin.site.register(CallDetails, CallDetailsAdmin)

Excluding objects from Django queryset based on recency

I have a reddit-like Django app where users can post interesting urls (links) and then publicly comment under them. The two data models to represent this are:
class Link(models.Model):
description = models.TextField(validators=[MaxLengthValidator(500)])
submitter = models.ForeignKey(User)
submitted_on = models.DateTimeField(auto_now_add=True)
class Publicreply(models.Model):
submitted_by = models.ForeignKey(User)
answer_to = models.ForeignKey(Link)
submitted_on = models.DateTimeField(auto_now_add=True)
description = models.TextField(validators=[MaxLengthValidator(250)])
How do I query for all Links which have at least 1 or more publicreply, and secondly where the latest publicreply is not by self.request.user? I sense something like the following:
Link.objects.filter(publicreply__isnull=False).exclude(**something here**)
Please advise! Performance is key too, hence the simpler the better!
For performance and simplicity you could cache both the number of replies and the latest reply:
class Link(models.Model):
...
number_of_replies = models.PositiveIntegerField(default=0)
latest_reply = models.ForeignKey('myapp.Publicreply', related_name='+', blank=True, null=True, on_delete=models.SET_NULL)
When a reply is entered, update the corresponding link.number_of_replies and link.latest_reply.
The query would then be:
Link.objects.filter(number_of_replies__gte=1)\
.exclude(latest_reply__user=request.user)