How to count users posts in Django? - django

In a simple forum app in Django, on each thread I want to render posts by several users on the same page (on a user panel at the user's post, like all conventional forums).
Here are the models:
class Post(models.Model):
title = models.CharField(max_length=75, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
creator = models.ForeignKey(User, blank=True, null=True)
updated = models.DateTimeField(auto_now=True)
topic = models.ForeignKey(Topic)
body = models.TextField(max_length=10000)
class Topic(models.Model):
title = models.CharField(max_length=100)
description = models.TextField(max_length=10000, null=True)
forum = models.ForeignKey(Forum)
created = models.DateTimeField()
creator = models.ForeignKey(User, blank=True, null=True)
updated = models.DateTimeField(auto_now=True)
closed = models.BooleanField(blank=True, default=False)
published = models.BooleanField(blank=True, default=False)
visits = models.IntegerField(default = 0)
weight = models.IntegerField(blank=True, default=0)
slug = models.CharField(max_length=100, blank=True)
def num_posts(self):
return self.post_set.count()
def num_replies(self):
return max(0, self.post_set.count() - 1)
def last_post(self):
if self.post_set.count():
return self.post_set.order_by("-created")[0]
def __unicode__(self):
return unicode(self.creator) + " - " + self.title
def save(self, *args, **kwargs):
super(Topic, self).save(*args, **kwargs)
I have also this wierd model:
class PostCount(models.Model):
user = models.OneToOneField(User)
posts = models.IntegerField(default=0)
#classmethod
def create(cls, user):
postcount = cls(user=user)
return postcount
Which somehow magically returns number of topics by a user (not number of posts) so that they can be accessed in the template using {{topic.creator.postcount.posts}}.
And the view that render topics:
def topic(request, topic_id):
"""Listing of posts in a topic."""
posts = Post.objects.filter(topic=topic_id).order_by("created")
posts = mk_paginator(request, posts, DJANGO_SIMPLE_FORUM_REPLIES_PER_PAGE)
topic = Topic.objects.get(pk=topic_id)
topic.visits += 1
topic.save()
forum = topic.forum
return render_to_response("myforum/topic.html", add_csrf(request, posts=posts, pk=topic_id,
topic=topic, forum= forum), context_instance=RequestContext(request))
So I'm wondering how best to have number of posts by a user in template?

Do you not want to use the built in count, because that would solve your problem.
views.py- should get all the users, if you wanted a selected user group per se you would just use filter
context = {}
post_numbers = Post.objects.all().count()
context['post_numbers'] = post_numbers
Template
{{ post_numbers }}

Related

Django Admin, show inline based on slug

Have the following models
class FootballWebsite(models.Model):
"""Football service website."""
url = models.URLField, unique=True)
#football service
id = models.CharField(primary_key=True,
#is this domain blocked
blocked = models.BooleanField(default=False)
#is it online or offline
online = models.BooleanField(default=False)
updated = models.DateTimeField(auto_now=True, auto_now_add=True)
sub_categories = models.ForeignKey(SubCategory, default=1)
referral = models.TextField(blank=True)
mirror = models.ForeignKey('FootballWebsite', blank=True, null=True)
rank = models.PositiveIntegerField(default=0, blank=True, null=True)
screenshot = models.BooleanField(default=False)
class Meta:
"""Meta class."""
app_label = 'ahmia'
def __unicode__(self):
return u'%s' % (self.url)
"""The datetime when the football service was last seen online"""
try:
return self.footballwebsitestatus_set.filter(online=True).latest('time').time
except FootballWebsiteStatus.DoesNotExist:
return None
class FootballWebsiteDescription(models.Model):
"""Football service website description."""
about = models.ForeignKey(Footballebsite)
title = models.TextField(blank=True, null=True)
keywords = models.TextField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
relation = models.URLField(blank=True, null=True)
subject = models.TextField(blank=True, null=True)
type = models.TextField(blank=True, null=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=True)
language = models.TextField(null=True, blank=True)
contactInformation = models.TextField(null=True, blank=True)
officialInfo = models.BooleanField(default=False)
slug = AutoSlugField(populate_from=['title'], allow_duplicates=True, null=True)
class Meta:
"""Meta class."""
app_label = 'ahmia'
def __unicode__(self):
return unicode(self.about.url)
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(FootballebsiteDescription, self).save(*args, **kwargs)
def __unicode__(self):
return u'%s' % (self.title)
I have a huge amount of links, and i would like to bulk assign them into a category or mark them as blocked based on identical title slug.
Managed to at least get a list of title_slugs with the code below, but the following step, i would like to get an inline list with all sites that have an identical title_slug and bulk assign those all in their a category
class FootballWebsiteInline(admin.TabularInline):
model = FootballWebsite
class FootballWebsiteDescriptionAdmin(admin.ModelAdmin):
list_display = ['show_slug']
def show_slug(self, obj):
return format_html("<a href='{url}'>{url}</a>", url=obj.slug)
inlines = [
FootballWebsiteInline,
]
Above code obviously doesn' t work, since the title slug which can appear many times is not a primary key.
Is it possible to get an inline list based on the title slug in this case which is not a primary key at all, or am i going about this the wrong way?
When possible at all, some further tweaking would be to group the identical title slugs

I'm optimizing my django project backend, but I got many problems on "list_display" that contains ForeignKey

django masters all around the world
I'm Korean developer and started django 3 months ago.
Now I'm just a slave of my company.
Anyway, I have problem on optimizing django admin project, but no one has experienced the same problem.
This is my models "Project", "Answer", "Request".
# ------------------------------------------------------------------
# Model : Project
# Description : project model
# ------------------------------------------------------------------
class Project(models.Model):
class Meta:
verbose_name = ' project'
verbose_name_plural = ' project'
def __str__(self):
return str(self.id)
# ------------------------------------------------------------------
# Model : Request
# Description : Request model
# ------------------------------------------------------------------
class Request(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE, verbose_name='client')
project = models.ForeignKey(Project, on_delete=models.CASCADE, verbose_name='project')
product = models.ForeignKey(Subclass, on_delete=models.CASCADE, verbose_name='product')
category = models.ManyToManyField(Develop, verbose_name='category')
name = models.CharField('name', max_length=256, blank=True, null=True)
price = models.CharField('price', max_length=256, blank=True, null=True)
day = models.CharField('duedate', max_length=256, blank=True, null=True)
content = RichTextUploadingField('content', null=True)
file = models.FileField('file', upload_to=request_update_filename, blank=True, null=True)
created_at = models.DateTimeField('created_at', default=time)
add_meeting = models.BooleanField('add_meeting', default=False, null=True)
examine = models.BooleanField('check examing', default=False, null=True)
active_save = models.BooleanField('active-save', default=True, null=True)
class Meta:
verbose_name = ' request'
verbose_name_plural = ' requests'
def __str__(self):
return str(self.name)
class Answer(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE, verbose_name="client")
project = models.ForeignKey(Project, on_delete=models.CASCADE, verbose_name="project", null=True)
partner = models.ForeignKey(Partner, on_delete=models.CASCADE, verbose_name="partner")
class Meta:
verbose_name = ' Answer'
verbose_name_plural = ' Answer'
def __str__(self):
return str(self.id)
and this is my admin code
#admin.register(Project)
class ProjectAdmin(admin.ModelAdmin):
inlines = [RequestInline,AnswerInline]
list_display = ['request_name','client_email','project_price','project_created','count_answer','count_meeting','answer_status']
def request_name(self, obj):
project_id = obj.id
request_name = Request.objects.get(project = project_id)
return request_name
def client_email(self, obj):
project_id = obj.id
client = Request.objects.get(project=project_id).client
return client
def client_phone(self, obj):
project_id = obj.id
client = Request.objects.get(project=project_id).client
phone = User.objects.get(username=client).phone
return phone
def project_price(self, obj):
project_id = obj.id
request_price = Request.objects.get(project=project_id).price
return request_price
def project_created(self, obj):
project_id = obj.id
created_at = Request.objects.get(project=project_id).created_at
return created_at
def count_answer(self, obj):
project_id = obj.id
answer_qs = Answer.objects.all()
answer = Answer.objects.filter(project=project_id)
count = len(answer)
return count
def count_meeting(self, obj):
project_id = obj.id
answer_yes = Answer.objects.filter(project = project_id, state = 1)
count = len(answer_yes)
return count
def answer_status(self, obj):
project_id = obj.id
answer = Answer.objects.filter(project = project_id, info_check =1)
count = len(answer)
return count
There are many factors not included in the above, but what I want to solve is not to bring in the same queryset(Request, Answer).
The project itself is a structure that does not have attributes but is received only by foreign keys. Such a structure is making it difficult to find a solution.
I used select_related(prefetch_related too), but it does not work.
If you can give me some advice, I'd like to take some advice. thanks.
p.s. It is my first time asking question on this site, I apologize if there was anything rude.
admin.TabularInline will show the reverse foreign key in the admin detail page that may help you, but it seems that you have already used it in the inlines of ProjectAdmin.

How to count related objects of several users in Django?

In a simple forum app in Django, on each thread I want to render posts by several users on the same page (like what you see on VB and other classic forums).
Here are the models:
class Post(models.Model):
title = models.CharField(max_length=75, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
creator = models.ForeignKey(User, blank=True, null=True)
updated = models.DateTimeField(auto_now=True)
topic = models.ForeignKey(Topic)
body = models.TextField(max_length=10000)
class Topic(models.Model):
title = models.CharField(max_length=100)
description = models.TextField(max_length=10000, null=True)
forum = models.ForeignKey(Forum)
created = models.DateTimeField()
creator = models.ForeignKey(User, blank=True, null=True)
updated = models.DateTimeField(auto_now=True)
closed = models.BooleanField(blank=True, default=False)
published = models.BooleanField(blank=True, default=False)
visits = models.IntegerField(default = 0)
weight = models.IntegerField(blank=True, default=0)
slug = models.CharField(max_length=100, blank=True)
def num_posts(self):
return self.post_set.count()
def num_replies(self):
return max(0, self.post_set.count() - 1)
def last_post(self):
if self.post_set.count():
return self.post_set.order_by("-created")[0]
def __unicode__(self):
return unicode(self.creator) + " - " + self.title
def save(self, *args, **kwargs):
super(Topic, self).save(*args, **kwargs)
I have also this wierd model:
class PostCount(models.Model):
user = models.OneToOneField(User)
posts = models.IntegerField(default=0)
#classmethod
def create(cls, user):
postcount = cls(user=user)
return postcount
Which somehow magically returns number of topics by a user (not number of posts) so that they can be accessed in the template using {{topic.creator.postcount.posts}}.
And the view that render topics:
def topic(request, topic_id):
"""Listing of posts in a topic."""
posts = Post.objects.filter(topic=topic_id).order_by("created")
posts = mk_paginator(request, posts, DJANGO_SIMPLE_FORUM_REPLIES_PER_PAGE)
topic = Topic.objects.get(pk=topic_id)
topic.visits += 1
topic.save()
forum = topic.forum
return render_to_response("myforum/topic.html", add_csrf(request, posts=posts, pk=topic_id,
topic=topic, forum= forum), context_instance=RequestContext(request))
I've tried this
posts = Post.objects.filter(topic=topic_id).order_by("created").annotate(creator_post_count=Count(creator__post_set))
but it did not work.
So I'm wondering how best to count number of posts by a user in template?
Have you tried this? :
posts = Post.objects.filter(topic=topic_id).order_by('created').annotate(creator_post_count=Count('creator__post_set_id', distinct=True))
or to print {{ topic.creator.post_set.count }} directly in the template ?

How to join user profile to user topics in Django?

In Django 1.7, I am trying to make a user panel in which userprofile info (like avatar, country, etc.) are to be displayed along with their topics. Here is the view:
def topic(request, topic_id):
"""Listing of posts in a thread."""
posts = Post.objects.select_related('creator') \
.filter(topic=topic_id).order_by("created")
posts = mk_paginator(request, posts, DJANGO_SIMPLE_FORUM_REPLIES_PER_PAGE)
topic = Topic.objects.get(pk=topic_id)
topic.visits += 1
topic.save()
return render_to_response("myforum/topic.html", add_csrf(request, posts=posts, pk=topic_id,
topic=topic), context_instance=RequestContext(request))
The Topic model is:
class Topic(models.Model):
title = models.CharField(max_length=100)
description = models.TextField(max_length=10000, null=True)
forum = models.ForeignKey(Forum)
created = models.DateTimeField()
creator = models.ForeignKey(User, blank=True, null=True)
visits = models.IntegerField(default = 0)
And the UserProfile model:
class UserProfile(models.Model):
username = models.OneToOneField(User)
name = models.CharField(max_length=30, blank=True)
city = models.CharField(max_length=30, blank=True)
country = models.CharField(
max_length=20, choices= COUTNRY_CHOICES, blank=True)
avatar = ImageWithThumbsField(), upload_to='images', sizes=((32,32),(150,150),(200,200)), blank=True)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, blank=True)
However, when in topic.html I try to capture the userprofile info in template, e.g.
{{topic.creator.userprofile.name}}
or
{{topic.creator.userprofile.city}}
nothing is displayed. This happens for all fields that I try to fetch from UserProfile model, despite the fact that in the database the userprofile row for the user is not empty and I can get fields in other views.
I have been stuck on this for days so really appreciate your help.
Update: here is add_csrf, in case it might be relevant
def add_csrf(request, ** kwargs):
d = dict(user=request.user, ** kwargs)
d.update(csrf(request))
return d

using UserProfile to restrict access in view

I have an app that displays client assets on html posting pages. Each client authorized to use the system is assigned a profile:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
fullname = models.CharField(max_length=64, unique=False)
company = models.CharField(max_length=50, choices=CLIENT_CHOICES)
position = models.CharField(max_length=64, unique=False, blank=True, null=True)
...
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
def __unicode__(self):
return u'%s' % self.fullname
class Meta:
ordering = ['fullname']
class Admin:
pass
and there's a model for the post pages:
class PostPage(models.Model):
client = models.CharField(max_length=50, choices=CLIENT_CHOICES)
job_number = models.CharField(max_length=30, unique=True, blank=False, null=False)
job_name = models.CharField(max_length=64, unique=False, blank=False, null=False)
page_type = models.CharField(max_length=50, default='POST')
create_date = models.DateField(("Date"), default=datetime.date.today)
contact = models.ForeignKey(UserProfile)
contact2 = models.ForeignKey(UserProfile, related_name='+', blank=True, null=True)
contact3 = models.ForeignKey(UserProfile, related_name='+', blank=True, null=True)
contact4 = models.ForeignKey(UserProfile, related_name='+', blank=True, null=True)
def __unicode__ (self):
return u'%s %s %s' % (self.client, self.job_number, self.job_name)
class Admin:
pass
and finally, a very simple view function to display the pages:
def display_postings(request, job_number):
records = PostPage.objects.filter(job_number=job_number)
tpl = 'post_page.html'
return render_to_response(tpl, { 'records': records })
The problem is, if you work for and access the system from "ACME" company, there's no logic in the view that would prevent you from viewing records for "BETAMAX" company in addition to your own. How can I modify my view so that if say, user.profile.company = "ACME" , but the request returns a record where PostPage.client = "BETAMAX", access to the record is denied? Additionally, can I have one company group, say user.profile.company = "MY_COMPANY" that has access to all records?
Write a decorator that checks the company of the request.user for the view. The code would look something like this:
def belongs_to_company(func):
def decorator(request, *args, **kwargs):
has_permissions = False
# get current company
...
# get user's list of company
...
# if company not in user's list of company
if not has_permissions:
url = reverse('no_perms')
return redirect(url)
return func(request, *args, **kwargs)
return decorator
A better long term solution is to check out Role Based Access Control libraries like django-guardian