Using tastypie to retrieve data from foreign key - python

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.

Related

django modeltranslation doesn't work with such queryset

I'm new to programming.
In my blog I want to show a list of categories.
If I create a queryset like this:
Category.objects.all()
my django-modeltranslation works perfectly.
But I want to get categories of only published posts. Then my queryset is:
Post.objects.values('category__name').filter(is_published=True)
However, django-modeltranslation doesn't work. I get values from 'name' field instead 'name_en' or 'name_ru' fields.
What is wrong?
Here's my models.py :
class Category(models.Model):
name = models.TextField(max_length=100)
url = models.SlugField(max_length=160, unique=True)
class Post(models.Model):
title = models.TextField('title', max_length=150)
category = models.ManyToManyField(Category, related_name='posts', blank=True)
I think you better query in reverse: with .values(…) you select a specific database column, so this will omit the model logic.
You can retrieve the categories with:
Category.objects.filter(posts__is_published=True).distinct()

Django Rest Framework creating child objects in parent serializer using child serializer

Supposing some standard Django relational setup like this:
models.py
class Book(models.Model):
title = models.CharField(max_length=30)
class Page(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
text = models.CharField(max_length=100)
I'd like to create a book and all its pages with one request. If we start with serializers like this:
serializers.py
class PageSerializer(serializers.ModelSerializer):
class Meta:
model = Page
fields = '__all__'
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('title', 'pages')
pages = PageSerializer(many=True)
Then the problem is that the PageSerializer now requires a book foreign key. But I don't know the key of the book until I've created the book, which is only after I've sent the POST request. So I cannot include the book pk in the POST data that the client sends.
An obvious solution is to override the create function on the Book serializer. But then I am still faced with the problem that the validators will say that the book field is required and the POST data will fail to validate.
I could make book a not-required field on the PageSerialzer. But this seems very bad. The book field IS required. And the BookSerializer create method will be able to supply it. It's just the client that doesn't know it.
So my suspicion is that the best way to do this is to leave book as required on the PageSerializer, but somehow make it so that the validators on the BookSerializer don't check for whether that is in the POST data when I post to BookSerializer.
Is this the correct way to achieve what I want? And if so, how do I do it? Thank you.
Why not try handling it in the create viewset. You can validate the data for the Book object first, before creating it. Then validate the data for the Page object using the created Book object and the other data sent from the request to the page.
I'd link your ViewSet to a BookCreateSerializer, and from this specific serializer I'd then add a function to not only verify the received data but make sure you link the parent's id to the child's one during creation.
IMPORTANT NOTE
This works if a parent only has one child, not sure about when passing multiple children.
Here is what is could look like.
BookCreateSerializer:
class BookCreateSerializer(serializers.ModelSerializer):
"""
Serializer to create a new Book model in DB
"""
pages = PageCreateSerializer()
class Meta:
model = Book
fields = [
'title',
'pages'
]
def create(self, validated_data):
page_data = validated_data.pop('page')
book = Book.objects.create(**validated_data)
Page.objects.create(book=book, **page_data)
return book
PageCreateSerializer
class PageCreateSerializer(serializers.ModelSerializer):
"""
Serializer to create a new Page model in DB
"""
class Meta:
model = Page
fields = [
'book',
'text'
]
To make sure that your Book instance understands what a page field is in the serializer, you have to define a related_name in its child's Model (Page). The name you choose is up to you. It could look like:
class Page(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='page')
text = models.CharField(max_length=100)

django 2 - Nested query based off multiple models

Update: See bottom.
I'm trying to wrap my head around how to achieve a nested/chained query based on my needs. There might be a better way to get the results I need so please let me know.
Trying to get the authenticated user and get a list of friends, which I have working and I get a queryset object of friends. I would like to pass the queryset object of friends into another query that searches the Post model, matches the username found Friend.users to the Post.creator so I get back another queryset which will have all the Posts of all my friends which I can display in the template.
class Friend(models.Model):
users = models.ManyToManyField(User, blank=True)
owner = models.ForeignKey(User, related_name='owner_friend', on_delete=models.CASCADE, null=True, blank=True)
class Post(models.Model):
creator = models.ForeignKey(User, on_delete=None, null=True)
EDIT:
I'm trying to do this with my code
f = Friend.objects.all().filter(owner__username='admin').filter(users__username='jeff')
output
<QuerySet [<Friend: Friend object (1)>]>
p = Post.objects.all().filter(creator__username__in=f)
ValueError: Cannot use QuerySet for "Friend": Use a QuerySet for "User".
Thanks for the help.
Update 1:
I've changed my models to use ForeignKeys instead. I've been using the shell to test and I'm getting an unexpected result, see below.
class Friend(models.Model):
users = models.ForeignKey(User, related_name='user_friend', on_delete=models.CASCADE, null=True, blank=True)
owner = models.ForeignKey(User, related_name='owner_friend', on_delete=models.CASCADE, null=True, blank=True)
f = Friend.objects.filter(owner__username='admin').values_list('users__username', flat=True)
Output
<QuerySet ['jeff', 'sam']>
Post.objects.filter(creator__username__in=list(f))
Output
<QuerySet []>
If I put in the list manually
Post.objects.filter(creator__username__in=['admin', 'jeff'])
Output
<QuerySet [<Post: Post Title 1>]>
I think if I can get the __in=list(f) to work this should fix the issue.
Update 2
list(f) is actually working, I didn't have a Post linked for the user accounts for the friends being pulled through. Once I created the post for the friends, I'm now getting a queryset.
I'm not sure what I'm doing is the best way but it's working.
For future readers I hope this helps.
The Friend model is a bit strange and is causing you some difficulty. Really, Friend should be the through table in the many-to-many relationship between User and itself. Presumably you are using the built-in User model, which is why you have used an external model; but you can still simulate a through table with two foreign keys:
class Friend(models.Model):
from_user = models.ForeignKey(User, related_name='users_from', on_delete=models.CASCADE)
to_user = models.ForeignKey(User, related_name='users_to', on_delete=models.CASCADE)
Now your query can be:
Post.objects.filter(creator__users_to__from_user__username='admin')
that is, give me all Posts whose creator is on the "to_user" side of the friend relationship where the from_user's username is "admin".

Django Models Relationship Confusions

I have the following models:
class UserPost(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
class User(AbstractUser):
MALE = 'M'
FEMALE = 'F'
GENDER_CHOICES = (
(MALE, 'Male'),
(FEMALE, 'Female')
)
posts = models.ManyToManyField(Post, through='UserPost')
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
content = models.TextField()
status = models.CharField(max_length=100)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
When I run python manage.py makemigrations, it raises the following error:
users.User.posts: (fields.E303) Reverse query name for 'User.posts' clashes with field name 'Post.user'.
HINT: Rename field 'Post.user', or add/change a related_name argument to the definition for field 'User.posts'.
There is a many-to-many relationship between User and Post models. Each user can like many posts and each post can be liked by many users.
There is also a many-to-one relationship between User and Post models. Each user can write many posts and each post can be written by only one user.
Shouldn't reverse query name for 'User.posts' be user_set by default. If so, why is this name clashing with field name 'Post.user'? Can someone explain the meaning of this error? Thanks.
Do you need the UserPost model? It looks to have all the same fields as Post, and if you're after efficient querying, Django automatically creates database indexes on foreign keys. Here's a simple setup that should work pretty well:
class User(AbstractUser):
# Your fields go here, but you might not need the posts field
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='posts')
This would let you do a user.posts.all() to get all of the Post instances that belong to that user.

Django count foreign key through relation

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()

Categories

Resources