Django count foreign key through relation - python

I am building a simple forum application and I need some help with counting foreign key objects via through relation.
Let's say my models look like this:
class Forum(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
slug = models.SlugField(unique=True, blank=True)
class Thread(models.Model):
title = models.CharField(max_length=255)
forum = models.ForeignKey(to=Forum, related_name='threads')
slug = models.SlugField(unique=True, blank=True)
class Post(models.Model):
body = models.TextField()
author = models.ForeignKey(User)
thread = models.ForeignKey(to=Thread,related_name='posts')
Now we create forum object.
forum = Forum.objects.get(slug=forum)
We can count the number of threads inside forum like this: forum.threads.count()
My question is, how can i count all the posts in a forum?
I've tried something like all_posts = forum.thredas.posts.count() but as expected it didn't work.
Thanks!

Generally in Django it is a good principle that when you want to do something with a model, you should start your query from that model. So, since you need to count posts, you should start with the Post model.
From there you can use the double-underscore syntax to filter to the particular Forum you want.
forum_posts = Post.objects.filter(thread__forum=my_forum)
forum_post_count = forum_posts.count()

Related

How to access foreign key table's data in Django templates?

I want to access foreign key table's data into django templates.
my code is as below.
class TutorialCategory(models.Model):
tutorial_category = models.CharField(max_length=200)
category_summary = models.CharField(max_length=200)
category_slug = models.CharField(max_length=200, default=1)
class TutorialSeries(models.Model):
tutorial_series = models.CharField(max_length=200)
tutorial_category = models.ForeignKey(TutorialCategory, verbose_name="Category", on_delete=models.SET_DEFAULT)
series_summary = models.CharField(max_length=200)
Tutorial_obj = TutorialSeries.objects.get(pk=1)
{{ Tutorial_obj.tutorial_series}}
{{Tutorial_obj.category_summary}} // Not able to access TutorialCategory
I have searched on SO also & found to use _set which I have used but still not able to access table.
Pls if anyone have suggestion pls guide me .
You want
{{Tutorial_obj.tutorial_category.category_summary}}
Not sure if that was just a silly error or a misunderstanding of how it's supposed to work
BTW stick to the conventions: an instance really should be lower case tutorial or tutorial_obj if you insist.

How can I construct a Django model whose fields are dependent upon another model's fields

I currently am making a simple newspaper Django application, and am working on the Articles model which looks as follows:
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
#date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
topic = models.CharField(max_length=255)
score_choices = [(-5,'-5'), (-4, '-4'), (-3,'-3'), (-2, '-2'), (-1,'-1'),
(0,'0'),(1,'1'), (2,'2'), (3,'3'), (4,'4'), (5,'5')]
score = models.IntegerField(choices=score_choices, default=0)
I am attempting to create another model that looks something like this:
class Topic(models.Model):
topic_name = models.CharField(max_length=255)
average_score =
Within the topic model, what I would like to do is somehow query all the Articles that have topic_name as their topic, and then return a list of scores that have been entered for Articles with that topic.
I'm currently pretty lost on this issue and I'm not even sure anymore if using the Django models is the best route. I've been reading through the Django Documentation as well as Third-Party books for a while but I can't find any reference here.
To summarize, I have two models: Article and Topic. Article has a field called 'topic' as well and I would like to create a field for my Topic class that is a function of the score field for all Article objects whose 'topic' field agrees with that of my separate Topic class. I apologize if this is confusing and I don't know all the terminology as I am trying to teach myself.
I have read through Django Documentation's pages on Models, Queries, Many-to-Many Relationships and various other properties. I still am unsure as to the solution.
Something like the following would work, using aggregation:
from django.db.models.aggregates import Avg
class Topic(models.Model):
topic_name = models.CharField(max_length=255)
def average_score(self):
return Article.objects.filter(topic=self.topic_name).aggregate(avg=Avg('score')).get('avg')

Using tastypie to retrieve data from foreign key

These are two models in my Django app :
models.py
class Posts(models.Model):
title = models.CharField(max_length=200, blank=True)
author = models.ForeignKey(user,on_delete=models.CASCADE,default=None, blank=True)
content = models.TextField()
class Unposted(models.Model):
article = models.ForeignKey(Posts, on_delete=models.CASCADE)
upload_at = models.DateTimeField(default=datetime.now, blank=True)
I'm trying to retrieve data from Posts using an API request to Unposted.
Here's what I have until now but I'm unsure how to get data from the Posts model. Right now I just get a JSON response with only the upload_at field.
resources.py
class UnpostedResource(ModelResource):
class Meta:
queryset = Unposted.objects.all()
resource_name = 'unposted'
If I'm not wrong, u can just import your Posts model and then just by for loop make an array with posts models using foreign key from unposted to filter your posts =) Sounds weird and I'm not sure about effectiveness, but looks pretty nice. It will look smth like:
queryset = Posts.objects.filter(article_in=[get(i.article) for i in Unposted.objects.all()])
In the case, Posts is a foreignkey of Unposted, thus you need to define foreignkey field in the resource for the corresponding field in model, this tutorial maybe can help you.

How to setup many to many one to many and many to one relationship in django

From the last seven days I am trying to build a blog using django and I figured out the model for my blog as follows
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
created_at = models.DateTimeField('created date', auto_now_add=True, auto_now=False)
updated_at = models.DateTimeField('updated date', auto_now_add=False, auto_now=True)
def __str__(self):
return self.title
class Author(models.Model):
name = models.CharField(max_length=150)
email = models.EmailField(blank=True)
bio = models.TextField()
#This line define many author can have a post
#but I want manypost can only have single author.
#in my view to accomplish this i need to define author in Post class
#on defining author=ForeignKey(Author) in post, It throws an error Author is not defined
post = models.ForeignKey(Post)
def __str__(self):
return self.author
class Category(models.Model):
cat_name = models.CharField(max_length=200)
post = models.ManyToManyField(Post)
def __str__(self):
return self.cat_name
The thing that I am so much confused is the relation between the Post, Categories, Author and Tag.
Relation What I wanted to set is
author can have many posts, A post can have only single author
categories can have many posts, A post can have many categories
a tag can have many posts a post can have many tags
But the models that I am created above is not working as I expected(I am so confused).
when I put the author field in Post Class, so that i would be a relation like, an author can have many posts, but I got the error Author is not defined.(as I know the interpreter run code from top to bottom). How do I accomplish
You have two options:
Change Author and Post position, thus Page can see Post definition.
Use Lazy call as: author= models.ForeignKey("Author")
In this way, Django will wait until all models load then resolve the dependencies.
Try model structure syntax:
class Author(models.Model):
name = models.CharField(max_length=150)
email = models.EmailField(blank=True)
bio = models.TextField()
def __str__(self):
return self.author
class Post(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=200)
body = models.TextField()
created_at = models.DateTimeField('created date', auto_now_add=True, auto_now=False)
updated_at = models.DateTimeField('updated date', auto_now_add=False, auto_now=True)
def __str__(self):
return self.title
class Category(models.Model):
cat_name = models.CharField(max_length=200)
post = models.ManyToManyField(Post)
def __str__(self):
return self.cat_name
class Tag(models.Model):
tag_name = models.CharField(max_length=200)
post = models.ManyToManyField(Post)
def __str__(self):
return self.tag_name
This will solve your three requirements:
1.) Author can have many posts because I set the Post Model into one-to-many field
2.) Categories can have many posts vice versa (This is already set according to your code)
3.) Tag can have many posts vice versa (Very similar to your already made Category Model where I made the field many-to-many between the two)
The reason why you got an error is because you made your author to post relation to many-to-one (many authors in one post) according to your model structure
Now to test it simply migrate all these changes and quickly test it in your admin page
author can have many posts, A post can have only single author
Post model should have a ForeignKey pointing to Author.
class Post(...):
author = models.ForeignKey('Author')
categories can have many posts, A post can have many categories
Post model should have a ManyToManyField pointing to Category.
class Post(...):
category = models.ManyToManyField('Category')
a tag can have many posts a post can have many tags
Same as number 2.

django taggit prevent overlapping tags across different models

I have two different models.
class MessageArchive(models.Model):
from_user = models.CharField(null=True, blank=True, max_length=300)
archived_time = models.DateTimeField(auto_now_add=True)
label = models.ForeignKey(MessageLabel, null=True, blank=True)
archived_by = models.ForeignKey(OrgStaff)
tags = TaggableManager()
Now say, I have defined spam, todo, urgent tags for messages.
and then I have another model:
class PersonArchive(models.Model):
from_user = models.CharField(null=True, blank=True, max_length=300)
archived_time = models.DateTimeField(auto_now_add=True)
label = models.ForeignKey(MessageLabel, null=True, blank=True)
archived_by = models.ForeignKey(OrgStaff)
tags = TaggableManager()
I define awesome, legend, rockstar for the model person. There might few more be defined.
As is quite clear, I do not want the tags for person and message to overlap.
How should I achieve that? Thanks!
You can utilize the limit_choices_to feature on ForeignKeyFields and ManyToManyFields. Your models.py file might look like this:
class PersonArchive(models.Model):
tags_field = models.ManyToManyField(Tag, related_name="people_archives", limit_choices_to={'message_archives__isnull': True})
class MessageArchive(models.Model):
tags_field = models.ManyToManyField(Tag, related_name="message_archives", limit_choices_to={'people_archives__isnull': True})
You your case, as far as I understand, you want different base families of tag for the two different models.
Take in account I'm not an expert on taggit, so the solution I'm proposing can be a bit overcomplitated, but is the first that jump me in mind by looking at the source code.
You can achieve that by extending the TaggableRel class used by TaggableManager and add a condition to the limit_choices_to parameter:
Extend TaggableRel
class CustomTaggableRel(TaggableRel):
def __init__(self, field, model_name):
super(TaggableRel, self ).__init__(field)
self.limit_choices_to = {'content_type': model_name}
Than you extend TaggableManager in the following way:
class CustomTaggableManager(TaggableManager):
def __init__(self, model_name=None, verbose_name=_("Tags"),
help_text=_("A comma-separated list of tags."), through=None, blank=False):
super(TaggableManager, self ).__init__(verbose_name, help_text, through, blank)
self.rel = CustomTaggableRel(self, model_name)
Than you your models:
class PersonArchive(models.Model):
.
.
.
tags = CustomTaggableManager(model_name="PersonArchive")
This should do the trick, didn't try the solution and I write it down very fast, but this could drive you on the right path.
Just dealt with this myself. I decided to let my tags intermingle because I found a way to only filter tags for specific models. This will only filter tags for modelname. You can expand the filter as desired.
Tag.objects.filter(taggit_taggeditem_items__content_type__model='modelname')

Categories

Resources