Django Filtering to Get Popular Posts - django

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

Related

Django Joining Tables

I am trying to get the information from one table filtered by information from another table (I believe this is called joining tables).
I have these two models:
class Listing(models.Model):
title = models.CharField(max_length=64)
description = models.CharField(max_length=500)
price = models.DecimalField(max_digits=11, decimal_places=2, validators=[MinValueValidator(Decimal('0.01'))])
category = models.ForeignKey(Category, on_delete=models.CASCADE, default="")
imageURL = models.URLField(blank=True, max_length=500)
creator = models.ForeignKey(User, on_delete=models.CASCADE, related_name="creator", default="")
isOpen = models.BooleanField(default=True)
def __str__(self):
return f"{self.id} | {self.creator} | {self.title} | {self.price}"
class Watchlist(models.Model):
listing = models.ForeignKey(Listing, on_delete=models.CASCADE, related_name="listingWatched", default="")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="userWatching", default="")
What I need to do is to get all the listings from a specific user Watchlist, the idea is to generate a page with all of the information of each of the listings that are in the user's watchlist. What should I do?
Thanks in advance!
Since is a foreign key, in Django you can access the information by calling the attribute
For example:
my_user = Watchlist.objects.get(pk=1)
print(my_user.listing.title)
You can also access to that attrbute in a query in case you need to filter upwards some value
values = Watchlist.objects.all().filter(listing__title='MyTitle')
my_titles = [x.title for x in values]
print(my_titles)
Or in your case, if you want to list all the title for a specific user
values = Watchlist.objects.all().filter(user='foo_user')
my_titles = [x.listing.title for x in values]
print(my_titles)
More documentation here

Storing data in different tables or using bool fields

I have an Article table
class Article(models.Model):
"""
Model to keep articles
"""
ext_id = models.UUIDField(primary_key=True, db_index=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=255, unique=True, db_index=True)
content = models.TextField()
summary = models.TextField()
img_url = models.URLField(max_length=200)
author = models.CharField(max_length=50, blank=True, null=True)
sport = models.ForeignKey('Sport')
posted_on= models.DateTimeField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __unicode__(self):
return "%s by %s" % (self.title, self.author)
A table where I store articles liked by a user :
class LikedArticle(models.Model):
"""
Articles that a user wants to read
"""
ext_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
article = models.ForeignKey(Article)
profile = models.ForeignKey(Profile)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
and unliked :
class UnlikedLikedArticle(models.Model):
"""
Articles that a user does not want to read
"""
ext_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
article = models.ForeignKey(Article)
profile = models.ForeignKey(Profile)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
Now here, both the tables liked and unliked, are structurally the same.
I find it better to store it like this instead of storing say a bool field called is_liked because I exactly know what data I am storing. So I don't have to query a huge set of articles when I know that I am only interested in LikedArticle.
Is this the correct approach ? I am only confused because structurally they look the same and something doesn't feel right about this design.
the best approach that i recommend is to use one table and add is_liked field. (and add index to this field, so you get high performance queries)
but if still you want to use your approach with 2 table, then you need to fix your design.
use one abstract model that has all fields, and the Like and Unlike tables inherit from the abstract model
class ActionOnArticle(Model):
your fields here..
class Meta:
abstract = True
class LikedArticle(ActionOnArticle):
class UnLikedArticle(ActionOnArticle):
I think is_liked is not a good option if you want to save other information per profile, like that: who liked what and when and so on. If you want to lose those info so my suggestion is to use many to many relationship and the article model will be something like that:
class Article(models.Model):
"""
Model to keep articles
"""
ext_id = models.UUIDField(primary_key=True, db_index=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=255, unique=True, db_index=True)
content = models.TextField()
summary = models.TextField()
img_url = models.URLField(max_length=200)
author = models.CharField(max_length=50, blank=True, null=True)
sport = models.ForeignKey('Sport')
posted_on= models.DateTimeField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
likes = models.ManyToManyField(Profile)
unlikes = models.ManyToManyField(Profile)
def __unicode__(self):
return "%s by %s" % (self.title, self.author)
https://docs.djangoproject.com/en/1.8/topics/db/examples/many_to_many/
While if you want to save the info mentioned at the beginning of my reply, I think #Eyal answer is fine
I'd use the "is_liked" BooleanField and filter on it to just get the liked or disliked articles. Filtering on a BooleanField (add db_index=True on the field options) will be extremely fast with any decent database so you are very unlikely to get a noticable performance increase using separate tables even if they were huge.

Django instance - Combine two attribute values in model

Can someone tell me how to combine two or more attribute values of in another field by using instance?
Models.py:
fn_id = models.ForeignKey(FilemNumber, null=True, blank=True)
ln_id = models.ForeignKey(LineNumber, null=True, blank=True)
pn_id = models.ForeignKey(PhotoNumber, null=True, blank=True)
title = models.CharField(max_length=255,blank=True, null=True)
I want to combine fn_id, ln_id and pn_id and save the combination of the three values into field title.
You can do this:
from django import models
class BaseModel(models.Model):
fn_id = models.ForeignKey(FilemNumber, null=True, blank=True)
ln_id = models.ForeignKey(LineNumber, null=True, blank=True)
pn_id = models.ForeignKey(PhotoNumber, null=True, blank=True)
class YourModel(models.Model):
common = models.OneToOneField(BaseModel)
# I suppose that you want to get title, so let define title method
# if obj is an instance of YourModel, you can access title like this:
# obj.title
#property
def title(self):
return '{}{}{}{}'.format(self.id, self.common.fn_id,
self.common.ln_id, self.common.pn_id)
Lets read this article: https://docs.djangoproject.com/en/1.8/ref/models/fields/#onetoonefield

Django save two models with two foreign keys

One Article can have only 1 current Revision, but can have multiple revisions in history. Each Revision belongs to Article.
Models:
class Article(models.Model):
published = models.BooleanField(default=False)
current_revision = models.ForeignKey('Revision', related_name='current_revision', blank=False, default=None)
class Revision(models.Model):
article = models.ForeignKey('Article', null=True)
title = models.CharField('Title', max_length=250, blank=False, default='(no title)')
content = RedactorField('Content')
created_at = models.DateTimeField('Created at', auto_now=True)
slug = models.SlugField('Slug', blank=False, null=True)
View:
if article_form.is_valid() and revision_form.is_valid():
article = article_form.save(commit=False)
revision = revision_form.save()
article.current_revision = revision
article.save()
print(article)
revision.article = article
revision.save()
Is it okay to call save 3 times? Or is it possible to save 2 models with 2 saves?
It's ok to call save() 3 times, but, about your implementation.
I think, your models are not the best way to represent
One Article can have only 1 current Revision, but can have multiple revisions in history
Why not just, use a flag, to know if a revision is the current one, is better to check attributes than navigate between relationships
class Article(models.Model):
published = models.BooleanField(default=False)
class Revision(models.Model):
article = models.ForeignKey('Article', null=True)
title = models.CharField('Title', max_length=250, blank=False, default='(no title)')
content = RedactorField('Content')
created_at = models.DateTimeField('Created at', auto_now=True)
slug = models.SlugField('Slug', blank=False, null=True)
current = models.BooleanField(default=True)
#In your views
if article_form.is_valid() and revision_form.is_valid():
article = article_form.save()
#set prior current revision flag to False
last_current_revision = article.revision_set.filter(current=True)
last_current_revision.update(current=False)
revision = revision_form.save()
revision.article = article
revision.save()
In this way is less confusing.

Django List Ordering

I have a model called bank that has Credit class associated to a user.
Then I have a model called program that has NewProgram class associated also to a user.
Now, I would like to list out all NewProgram objects order by users Credit ascending to my views.py.
And i have no idea how am i going to do that using .order_by method.
I hope someone who could give me some hint.
Heres my code:
Appname: Bank
models.py
class Credit(models.Model):
credit_balance = models.DecimalField(max_digits=6, decimal_places=2)
depositor = models.ForeignKey(User, unique=True)
last_updated = models.DateTimeField(auto_now=True)
def __unicode__(self):
return u'%s' % self.depositor.username
Appname: Programs
class NewProgram(models.Model):
program_creator = models.ForeignKey(User, related_name='program_creator')
joining_credit_value_offer = models.DecimalField(max_digits=6, decimal_places=2)
site = models.ForeignKey('ProgramSite')
uid = models.CharField(max_length=50)
title = models.CharField(max_length=30)
desc = models.CharField(max_length=150)
content = models.TextField(blank=False)
is_published = models.BooleanField(default=True)
referrals = models.ManyToManyField(User, through='ReferredUser')
creation_date = models.DateTimeField(auto_now_add=True)
Heres what i'm trying to accomplish
list = NewProgram.objects.all().order_by(<Users Credit><ASC>)
Thanks a lot, Any help will be much appreciated.
You can try using this
list = NewProgram.objects.all().order_by('-program_creator__credit__credic_balance')
Django follows the relationships through __ .
Hello you can use this:
#Note, no need to use .all()
list = NewProgram.objects.filter(credit_set__depositor="some_user")