how to query to get the user from m2m relation - django

I have a model for forum. Its just the basics, and I am trying the grasp the relationship and how to query with them. So, I have a forum with field for question, body, published date, image, and likes. I guess my model design is correct, if not please correct me. So, everything is works as I wanted. Just that, how do I get all the Users who liked the forum and count the likes? How can i query it? Please guide me through.
Thank you.
models.py:
class Forum(models.Model):
question = models.CharField(max_length=150)
body = models.TextField()
pub_date = models.DateTimeField(default=datetime.now)
image = models.ImageField(upload_to=get_upload_file_name)
creator = models.ForeignKey(User, related_name="creator_set")
likes = models.ManyToManyField(User, through="Like")
def __unicode__(self):
return self.question
class Like(models.Model):
forum = models.ForeignKey(Forum)
liked = models.ForeignKey(User)
liked_date = models.DateTimeField(default=datetime.now)
def __unicode__(self):
return "%s likes %s" % (self.liked, self.forum)

Isn't this suppose to work?:
Forum.objects.get(pk=1).likes.all()
Forum.objects.get(pk=1).likes.count()

Related

Django querying foreign key from backward

I am trying to query from backward: at fist see my models:
from django.db import models
class Blog(models.Model):
title = models.CharField(max_length=100, unique=True)
body = models.TextField()
category = models.ForeignKey('blog.Category', on_delete=models.CASCADE)
def __unicode__(self):
return '%s' % self.title
class Category(models.Model):
name = models.CharField(max_length=100, db_index=True)
I have many category and many post, one category name is tech I am trying to get all the post those are in tech category.
I tried like this. Category.objects.filter(contain__exact='tech') but it is not work anymore.
Can anyone help me to figure get it done?
Best way to get all the post in tech category using foreign key.
tech_blogs = Blog.objects.filter(category__name__icontains='tech')
and also change
category = models.ForeignKey('Category', on_delete=models.CASCADE)

Many foreign keys in a model, better way to do models?

I'm kind of new to django. While writing the models for an app I'm doing, I felt like I was doing something wrong because of all the foreign keys I was using for a single model (ticket model to be specific)
My thinking at the beginning was that I wanted each Ticket to keep the information on it's creator, what team this ticket is assigned to and the comments made on the ticket. And other information that don't need foreign keys. Am I doing this right ? I dont know why, but I feel like there is a better way.
class Team(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=2000)
members = models.ManyToManyField(User, through='Team_members')
def __str__(self):
return self.name
class Ticket(models.Model):
name = models.CharField(max_length=200)
creator = models.ForeignKey(User, on_delete=models.CASCADE)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
comments = models.ForeignKey(Comment, on_delete=models.CASCADE)
#worker = models.ForeignKey(User, on_delete=models.CASCADE) *to be finished
description = models.CharField(max_length=500)
status = models.BooleanField(default=False)
date_opened = models.DateTimeField('date opened')
date_closed = models.DateTimeField('date closed',null=True, blank=True)
def __str__(self):
return self.name
class Team_member:
team = models.ForeignKey(Team)
user = models.ForeignKey(User)
date = models.DateTimeField('date joined')
class Comment:
text = models.CharField(max_length=2000)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.text
Your question actually has very little (like, nothing?) to do with Django.
Please read about database normalization, it should answer your questions.
Regarding your models, I could notice the following:
Your models look quite good. Don't be afraid of foreign keys, they are the main reason you use a relational database :)
I assume, User might be a member of a Team (service?) or somebody who opens a ticket. If so: when you will have worker foreign key, you most likely won't need team in the Ticket model. It will be redundant, as worker would have a relation to Team.
Nitpicking: Team_member is not pythonic, a PEP8 compliant version would be TeamMember

how to add likes of an object for the given user

I have a model for forum. There I have a field for question, body, pub_date, image, creator, likes. From the admin, I can add the likes for a given user for a particular forum. But i'm confused all now, how to add likes for the request.user in the views?
models.py:
class Forum(models.Model):
question = models.CharField(max_length=150)
body = models.TextField()
pub_date = models.DateTimeField(default=datetime.now)
image = models.ImageField(upload_to=get_upload_file_name)
creator = models.ForeignKey(User, related_name="creator_set")
likes = models.ManyToManyField(User, through="Like")
def __unicode__(self):
return self.question
class Like(models.Model):
forum = models.ForeignKey(Forum)
liked = models.ForeignKey(User)
liked_date = models.DateTimeField(default=datetime.now)
def __unicode__(self):
return "%s likes %s" % (self.liked, self.forum)
I thought of doing like this:
>>>forum = Forum.objects.get(id=1)
>>>user = request.user
>>>user.like_set.add(forum)
But, it didn't help. Please, any help will be appreciated. Thank you.
First you need to create a URL that targets the view. The URL would pass a forum_id as a URL parameter.
from datetime import datetime
from django.shortcuts import get_object_or_404
#login_required
def update_likes(request, forum_id):
forum = get_object_or_404(Forum, id=forum_id)
like, _ = Like.objects.get_or_create(user=request.user, forum=forum,
defaults={'liked_date': datetime.now()})
#rest of the code here.
This is one way. You could also do it in the way you thought of doing it, but you will have to manually control the duplicates that could get generated. (you could specify a unique_together on the ('forum', 'liked') )
and to delete
#login_required
def delete_likes(request, forum_id):
forum = get_object_or_404(Forum, id=forum_id)
like = get_object_or_404(Like, user=request.user, forum=forum)
like.delete()
#rest of the code here.

Django Admin Inline objects

I'm completely new to Django coming from PHP and therefore struggling a little with the terminology. This makes searching for an answer quite hard. Hopefully, somebody can tell me if this can be done within the excellent Django admin.
Ok, so the idea is that I have a questionaire which will be filled in by members of the design world. The questionaire class has very few fields, title, introduction, date.
The questions have their own class, there is a limited number in this case 20 and they are the same on each questionaire.
Therefore I have an answers class, the answer belongs to both a questionaire and a question.
class Questionaire(models.Model):
title = models.CharField(max_length=255)
intro = models.TextField(max_length=4000)
date_entered = models.DateField()
date_modified = models.DateField()
def __unicode__(self):
return self.title
class Question(models.Model):
title = models.CharField(max_length=255)
number = models.IntegerField()
def __unicode__(self):
return self.title
class Answer(models.Model):
response = models.TextField(max_length=4000)
questionaire = models.ForeignKey('articles.Questionaire')
question = models.ForeignKey('articles.Question')
def __unicode__(self):
return self.response
Sorry about the formatting above
What I am needing in the Questionaire admin is for each question, an answer field is available inline. If possible with the question name as the form field name.
Is this possible within Django admin?
Would be most grateful for any assistance
See: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodeladmin-objects
class AnswerInlineAdmin(admin.StackedInline):
model = Answer
extra = 1
class QuestionAdmin(admin.ModelAdmin):
...
inlines = [AnswerInlineAdmin]

Django counting related objects in model layer

It is possible to do something like this working:
class Book(models.Model):
voters = models.ManyToManyField(User, blank=True)
vote = models.IntegerField() # summary of all votes
def average_vote(self):
return int(vote/self.annotate(Count('voters')))
Maybe something like this?
class Book(models.Model):
voters = models.ManyToManyField(User, blank=True)
vote = models.IntegerField() # summary of all votes
def average_vote(self):
return int(self.vote/self.voters.all().count())
Let me know if that works. I haven't tested it.
Just override the default manager to make it always return an annotated queryset:
class BookUserManager(models.Manager):
def get_query_set(self, *args, **kwargs):
return super(BookUserManager, self).get_query_set(*args, **kwargs).annotate(average_vote=models.Avg('books__vote'))
class BookUser(User):
objects = BookUserManager()
class Meta:
proxy = True
class Book(models.Model):
# Next line has been changed to use proxy model. This *will* affect the m2m table name.
voters = models.ManyToManyField(BookUser, blank=True, related_name='books')
vote = models.IntegerField() # summary of all votes
objects = BookManager()
Then, you can get at the value like any other attribute on your the user model:
user = BookUser.objects.get(username='joe')
print user.average_vote
Update: Sorry... got that all wrong. That's what I get for reading the question too quickly. You'd actually need to annotate User not Book, but since User is coming from django.contrib.auth (I'm assuming) that's not going to be possible, or at least it requires more steps. Code above has been updated.