Subquery in Django ORM - python

I have following models. My goal is to extract 2 recent Comments per Post. Is that possible?
class Post(models.Model):
author = models.ForeignKey(Author, related_name="posts", on_delete=models.CASCADE)
title = models.CharField(max_length=256)
text = models.TextField(blank=True, default="")
created_at = models.DateTimeField(default=datetime.now, blank=True)
#property
def comments_number(self):
return self.comments.count()
def __str__(self, *args, **kwargs):
return f"{self.title}"
class Comment(models.Model):
post = models.ForeignKey(Post, related_name="comments", on_delete=models.CASCADE)
author = models.ForeignKey(Author, related_name="comment", on_delete=models.CASCADE)
text = models.TextField()
created_at = models.DateTimeField(default=datetime.now, blank=True)
The closest try I've got is this one:
newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
recent_comments = Post.objects.annotate(newest_comments=Subquery(newest.values('text')[:2]))
And than when I call recent_comments.values_list() I can see the newest one comment per Post obj (only one) but this is not what I want exactly. I have spend a lot of time on it guys and have no clue...

Related

Serializer for Recursive Comment in Django

models.py
class Comments(models.Model):
content = models.CharField(max_length=500)
sub_comment_id = models.ForeignKey('self', related_name='sub_comments', null=True, blank=True,
on_delete=models.CASCADE)
author_id = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='user_comments', on_delete=models.CASCADE)
article_id = models.ForeignKey(Article, related_name='article_comments', on_delete=models.CASCADE)
like = models.IntegerField(default=0)
dislike = models.IntegerField(default=0)
is_sub = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = models.Manager()
def __str__(self):
return self.content
what can i do for showing all recursive comments in Comment Serializer?
i use django rest framework-recursive but does not work
I have never try something like this, but i don't see why it wouldn't work
CommentSerializer(serializers.Serializer):
content = serializers.CharField()
...
sub_comments = serializers.SerializerMethodField()
def get_sub_comments(self, comment):
return self.__class__(comment.sub_comments.all(), many=True).data

For blog post i used tags by many_to_many filed. Now i try to use Django_Taggit for tag field, but i face some error while migrate

Old MODELS.py
when use tags by many_to_many fields
class Tag(models.Model):
tag_name = models.CharField(max_length=64, unique=True)
tag_slug = models.SlugField(max_length=64, unique=True)
created_on = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
def __str__(self):
return self.tag_name
def get_absolute_url(self):
return reverse("news:tag-detail", kwargs={"slug": str(self.tag_slug)})
class News(models.Model):
title = models.CharField(max_length=192, unique=True)
slug = models.SlugField(max_length=192, unique=True)
cover_photo = models.ImageField(upload_to='news', blank=True, null=True)
summary = models.CharField(max_length=280)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='post_author')
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=1)
# tags = models.ManyToManyField(Tag, blank=True, related_name='post_tag')
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("news:post", kwargs={"slug": str(self.slug)})
current models.py
After install Django_Taggit
i remove tags model and rewrite tags line
class News(models.Model):
title = models.CharField(max_length=192, unique=True)
slug = models.SlugField(max_length=192, unique=True)
cover_photo = models.ImageField(upload_to='news', blank=True, null=True)
summary = models.CharField(max_length=280)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='post_author')
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=1)
tags = TaggableManager()
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("news:post", kwargs={"slug": str(self.slug)})
Also i remove tags from view.py and urls path and update html
but when i try to 'python manage.py migrate' i face this error
ValueError: Cannot alter field news.News.tags into news.News.tags - they are not compatible types (you cannot alter to or from M2M fields, or add or remove through
= on M2M fields)
First remove the tags field and (makemigrations->migrate), then as you don't have tags as a field anymore add the new taggit field and again (makemigrations->migrate).
If you want to save the current tags, I can think of couple of options.
Create new field for example tags_taggit, and then run a script to translate the current tags into the new tags_taggit field. Then proceed with the steps I told you first
Create fixtures, then run a script to iterate over the fixtures and save the tags into the new field.

Django Blog Posts Ordered From Newest to Oldest

I am setting up a blog website and when I add blog posts, the oldest is on the top of the list. How do I reverse this so that the newest posts are on top of the page?
This is my pages/models.py I don't know if ordered_posts = Post.objects.order_by('created_date') is in the right place. I'm not sure where to put it. Any help would be appreciated. Thanks!
class Post(models.Model):
title = models.CharField(max_length=50)
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(auto_now_add=True blank=True, null=True)
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = models.TextField()
ordered_posts = Post.objects.order_by('-created_date')
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
You can define ordering in your class Meta.
This is a tuple or list of strings and/or query expressions. Each string is a field name with an optional “-” prefix, which indicates descending order. Fields without a leading “-” will be ordered ascending.
class Post(models.Model):
title = models.CharField(max_length=50)
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(auto_now_add=True blank=True, null=True)
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = models.TextField()
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
class Meta:
ordering = ['created_date']
See docs

How to do subcomments

from django.db import models
class Post(models.Model):
post_title = models.CharField(max_length=120, default=None)
post_text = models.TextField()
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.post_title
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
sub_comment = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True)
author = models.CharField(max_length=50)
comment_text = models.CharField(max_length=250)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.author
Hello, i've got a question. How to preform displaying comment as a thread if i have models like this?
A comment can have multiple subcomments, so this model won't work. Replace sub_comment with parent = models.ForeignKey(..., related_name='subcomments'). Then you will be able to say comment.subcomments which will give you a related object manager, so comment.subcomments.all() will be a query of all subcomments that you can iterate over.

order_by did't work after filtering by foreign key

I have a model like this
class Category(models.Model):
title = models.CharField(max_length=100, db_index=True)
slug = models.SlugField(max_length=100, db_index=True)
def __str__(self):
return "%s"%self.title
class Video(models.Model):
title = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=100, unique=True)
idlink = models.CharField(max_length=50)
posted = models.DateField(db_index=True, auto_now_add=True)
category = models.ForeignKey(Category)
def __str__(self):
return "%s"%self.title
And my views.py is
def list_video_cat(request, slug):
video = Video.objects.filter(category__slug=slug).order_by('-posted')
return render(request, 'category.html', {'videos':video})
I want to show my post new to old, but it seems to did not work at this situation. What should I do?
P/S the "duplicated post" does not solve my problem

Categories