Retrieve all values from join? - python

I have 3 tables. User, Post, and Share. Post is a table that contains all posts. Post has a one to many relationship with Share. That being said, the Share table is a table where it indicates which posts a user has shared. Here's the structure of the tables:
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.CharField(max_length=200)
share_count = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
url = models.CharField(max_length=150)
class Share(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
shared_at = models.DateTimeField(auto_now_add=True)
Let's say we have a User with id 1. What I want to do is to show all posts + shares of that user ordered by date. Just like how Twitter does when you go to a User's Twitter profile. It shows all their Tweets + their Retweets ordered by date and time. What I've tried doing is this query:
Share.objects.all().select_related('post').get(user=1)
If I do this, I get an error that there is more than one share for this user. What am I doing wrong?
The error:
Example.models.MultipleObjectsReturned: get() returned more than one
Share -- it returned 2!

You should replace get() with filter()
See documentation for get and filter

.get() will return an error if none or more than one object is returned. Use .filter() instead to get a QuerySet:
Share.objects.all().select_related('post').filter(user=1)

Related

how to output data from a linked table in django?

I have a built-in User table and a Note table associated with it by key.
class Note(models.Model):
header = models.CharField(max_length=100)
note_text = models.TextField()
data = models.DateField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
That is, a registered user may have several notes. How do I get all these notes from this particular user (who has now visited his page)? I need to get these notes in views.py.
I tried different ways, don't know how to do that.
Hope this answer finds you well ...
First, you already have a user object in your request. But, still you want to filter out notes for other users too, then do
get_user = User.objects.get(id=id) # For any random user
get_user = request.user # For authenticated user
After getting the user, you simply filter it with the Note model like this ...
get_notes = Note.objects.filter(user=get_user)
You are good to go!

Django - Query by foreign key in views

I am trying to make a button on the post that when a user cliks on it, is requesting to be added to the post as an attendance and then, the author of the post has to approve that request.
Models.py
class Attending(models.Model):
is_approved = models.BooleanField(default=False)
attending = models.ManyToManyField(User, related_name='user_event_attending')
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField(blank=True)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
attending = models.ForeignKey(Attending, on_delete=models.CASCADE, verbose_name='atending', null=True)
My problem here is that every time I writte a query for the button is giving me erros and I couldn`t figure it out how to get the reverse of the foreign key.
This is my code on my views.py
def request_event(request, pk):
previous = request.META.get('HTTP_REFERER')
try:
query = Attending.objects.get(pk=pk)
request_attending = query.post_set.add(request.user)
messages.success(request, f'Request sent!')
return redirect(previous)
except query.DoesNotExist:
return redirect('/')
Thank you very much for your help in advance!
This: query.post_set is just relationship. You cannot call method add just like that. You can add to ManyToMany relation and I believe you want to add user to Attending.attending field, not directly to Post object. Change that to:
...
query = Attending.objects.get(pk=pk)
query.attending.add(request.user)
messages.success(request, f'Request sent!')
....
| Update |
I think you should consider rearraning your relationships. If I understand your plan, you should go this way:
class Attending(models.Model):
...
attendant = models.ForeignKey(User, related_name='events_attending', on_delete=models.CASCADE)
post = models.ForeignKey('Post', on_delete=models.CASCADE)
class Post(models.Model):
...
author = models.ForeignKey(User, on_delete=models.CASCADE)
For one Post object there can be many Attending objects, then you can use relations like that:
att = Attending.objects.first()
att.post # get related Post object from ForeignKey | there is only one
post = Post.objects.first()
post.attending_set.all() # get all related Attending objects
Post.objects.get(attending=att) # get Post object that the Attending object have in ForeignKey field
user = User.objects.first()
user.post_set.all() # get all Post objects that User is author in
user.events_attending.all() # get all related Attending objects
For more check Django Docs.

Django efficient Queryset with Foreign Key Models

I'm trying to find the most efficient way (as less db queries as possible) for the following model structure.
In my template I then want to pass all the data from all 3 models because I would have to show the post data as well as looping through the comments to create a comments list and display all the attachments for the different comments.
class Post(BaseModel):
user = models.ForeignKey('User', blank=True, null=True,
title = models.CharField(max_length=128)
content = models.TextField()
class Comment(BaseModel):
post = models.ForeignKey('Post', on_delete=models.CASCADE)
user = models.ForeignKey('User', on_delete=models.SET_NULL)
text = models.TextField()
class CommentAttachment(BaseModel):
comment = models.ForeignKey('Comment', on_delete=models.CASCADE)
name = models.CharField(max_length=128)
Should I fetch all data from CommentAttachment direction (meaning fetching all CommentAttachments where comment__post__id is the post id and then get all other data with select_related) or is there another way to start from the Post Model?
You can use prefetch_related or select_related in your query:
posts = Post.objects.filter(user=some_user).prefetch_related(
'comment_set', 'comment_set__commentattachment_set'
)
For example, after making a query as mentioned, the following command may retrieve all the comments for the first post in the queryset without making a SQL query:
posts.first().comment_set.all()

Django: Filtering Many To Many, Find an Instance where multiple connected model instances exist

I have the following model where a thread can have many people. I would like to find a thread which contains specific users if it exists.
class Thread(models.Model):
subject = models.CharField(max_length=150)
users = models.ManyToManyField(settings.AUTH_USER_MODEL, through="UserThread")
class UserThread(models.Model):
thread = models.ForeignKey(Thread, on_delete=models.CASCADE)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class Message(models.Model):
thread = models.ForeignKey(Thread, related_name="messages", on_delete=models.CASCADE)
sender = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="sent_messages", on_delete=models.CASCADE)
sent_at = models.DateTimeField(default=timezone.now)
What I would like is to check if there is a thread which has 2 of the following users (user1 and user2):
thread = Thread.objects.get(Q(UserThread__user==user1) & Q(UserThread__user==user2))
This should return all the threads with 2 of the following users:
Thread.objects.filter(Q(userthread__user=user1), Q(userthread__user=user2))
And if you want to check if there are any threads with 2 of the following users you can do it with exists.
Thread.objects.filter(Q(userthread__user=user1), Q(userthread__user=user2)).exists()
for complex queryset I suggest you use filter queryset instead of get because filter will return zero or more results but get must return exactly one result and by any chance if you have multiple entries you need to handle MultipleObjectsReturned and DoesNotExist if no result found
Thread.objects.filter(Q(userthread__user=user1) & Q(userthread__user=user2))
Note: I have used userthread instead of UserThread because table in your database will be created by name userthread

In Django, how do I get all the instances of a model that have other instances of a related model attached to it with a ForeignKey field?

I am trying to write a query that retrieves all the categories that have at least one post attached to it. In other words, I want to 'exclude' any category that doesn't have any post.
These are my models for Category and Post:
class Category(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique=True)
class Post(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique=True)
body = models.TextField()
category = models.ForeignKey(Category, blank=True, default="")
This is the code I am using in my query, currently it fetches all the categories, even if no Post is 'attached' to it:
categories = Category.objects.all()
What I want is something like this:
categories = Category.objects.filter(
# Only ones that have at least one Post that has it's 'category' field set to it.
)
I've searched the docs and everywhere else, but I can't figure out a solution.
Please let me know how this can be done.
You can use following query:
categories = Category.objects.filter(post__isnull=False).distinct()
This will get all the categories where post is not null. Since, one category could have multiple posts, you will get duplicate instances with same id. Take a distinct to remove duplicate categories.
Note, that distinct(*fields) is postgresql specific. If you are using a different database, just use distinct().
Get all unique category ids by querying Post for distinct category and then filter Category by ids.
id_list = Post.objects.values_list('category_id').distinct()
catgories = Category.objects.filter(id__in=id_list)

Categories