query set in django - django

i really need help with this:
I have 3 models say User,Item and Comment where User is a foreign key in Item and Item is a foreign key in Comment.
i want to get all comment belonging to a particular user in my view, how do i achieve it. bellow is are my model
class User(models.Model):
name= models.CharField(max_length=200,null=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Item(models.Model):
user = models.ForeignKey(User, on_delete=CASCADE)
name= models.CharField(max_length=200,null=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Comment(models.Model):
user = models.ForeignKey(Item, on_delete=CASCADE)
name= models.CharField(max_length=200,null=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name

there is a problem of design model in your code.
here is how you can do it.
class Comment(models.Model):
item = models.ForeignKey(Item, on_delete=CASCADE) # the related item
author = models.ForeignKey(User,on_delete=CASCADE) #new ( the author of the comment)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
now in your views.py you can do something like this.
Comment.objects.filter(author=request.user)

UPDATED 2
You should consider changing model, like amadou-sow said, that is right way to do such things
UPDATED
def get_user_comments(request):
qs = Comment.objects.filter(user__user=request.user)
You could access yours related objects with "__" (double _) read more in official docs
And you really should rename "user" field to "item" in Comment model if it is foreign key to Item model, like this:
class User(models.Model):
name= models.CharField(max_length=200,null=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Item(models.Model):
user = models.ForeignKey(User, on_delete=CASCADE)
name= models.CharField(max_length=200,null=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Comment(models.Model):
item = models.ForeignKey(Item, on_delete=CASCADE)
name = models.CharField(max_length=200,null=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
#view.py
def get_user_comments(request):
return Comment.objects.filter(item__user=request.user)

Related

Reduce the time consumed by api in Django Rest Framework

These are the models that I created i.e. Video, Tag, Category, Exercise and Package_Exercise respectively. and i want to fetch data based on the object in package exercise and fetch all the data from the Exercise i.e. video url, tag and category of each exercise. I wrote the code but its taking too much time how do I reduce the time taken by the code? What should be the best approach to handle these kind of situations? What would be the best approach based on the time complexity.
class Video(models.Model):
video = models.FileField(upload_to='videos_uploaded',null=False,validators=[FileExtensionValidator(allowed_extensions=['MOV','avi','mp4','webm','mkv'])])
name = models.CharField(max_length=100)
thumbnail = models.ImageField(upload_to="video_thumbnails",null=False)
description = models.TextField(max_length=200)
created_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE, related_name='videos_created_by')
updated_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE, related_name='videos_updated_by')
def __str__(self):
return self.name
class Tag(models.Model):
name=models.CharField(max_length=100)
def __str__(self):
return self.name
class Category(models.Model):
title=models.CharField(max_length=200)
created_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='catagoery_created_by')
updated_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='catagoery_exercise_updated_by')
def __str__(self):
return self.title
class Exercise(models.Model):
name=models.CharField(max_length=100,null=False)
description=models.TextField(max_length=300,null=False)
video=models.ForeignKey(Video,on_delete=models.CASCADE,null=False)
category=models.ForeignKey(Category,on_delete=models.CASCADE,null=False)
tag=models.ManyToManyField(Tag,null=False)
created_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='exercise_created_by', null=False)
updated_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='exercise_updated_by', null=False)
def __str__(self):
return self.name
class Package_Exercise(models.Model):
package = models.ForeignKey(Package,on_delete=models.CASCADE,related_name='package')
exercise = models.ForeignKey(Exercise,on_delete=models.CASCADE)
repetition = models.IntegerField()
number_of_sets = models.IntegerField()
rest_time = models.IntegerField()
created_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='packages_exercise_created_by')
updated_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='packages_exercise_updated_by')
Here is the serializer takes 2.3s for ~30 objects of data in the models.
class PackageSerializer(serializers.ModelSerializer):
exercises = serializers.SerializerMethodField()
class Meta:
model=Package
fields= ['id','package_name','description','amount','is_public','public_doctor','thumbnail','exercises']
def get_exercises(self, obj):
pkg_exercies = Package_Exercise.objects.filter(package = obj.id)
sam = []
for each in pkg_exercies:
sam.append(
{
"name":each.exercise.name,
"url":each.exercise.video.video.url,
"description":each.exercise.description,
"category":each.exercise.category.title,
"tag":each.exercise.tag.name
}
)
return sam
What are the ways to tackle these kind of situations in both POST and GET APIs
Make a new serializer for the package_excercise model and use it in PackageSerializer's method like this:
def get_exercises(self, obj):
pkg_exercies = Package_Exercise.objects.filter(package = obj.id)
serializer = ExcerciseSerializer(data=pkg_exercies, many=True)
serializer.is_valid()
return serializer.data
In this way, you will be using the best way possible for fetching desired data moreover you will not have to repeat the same code in the future.

Django post primary key as slug? How do I reference the primary key in models.py?

When creating the slug for my post model, I want to use the object's primary key as the slug. However when I create a new post, instance.id is NoneType and not an integer like I'd imagine.
Here is my model:
class Post(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=50, null=False, blank=False)
body = models.TextField(max_length=5000, null=False, blank=False)
image = models.ImageField(upload_to=upload_location, null=False, blank=False)
date_published = models.DateTimeField(auto_now_add=True, verbose_name="date published")
date_updated = models.DateTimeField(auto_now=True, verbose_name="date updated")
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(blank=True, unique=True)
def __str__(self):
return self.title
#receiver(post_delete, sender=Post)
def submission_delete(sender, instance, **kwargs):
instance.image.delete(False)
def pre_save_blog_post_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = slugify(instance.id)
pre_save.connect(pre_save_blog_post_receiver, sender=Post)
As you can see in pre_save_blog_post_receiver, instance.id returns as None. How do I correctly reference the primary key in this situation?
You need to use post_save in case you create a Post object, since before it is committed to the database, there is no primary key. The database "distributes" primary keys.
Slugifying with an id is however a bit "odd". The idea of a slug is to make a visually pleasant variant of the title or some other text-related attribute.
It might also be more convenient to make use of a AutoSlugField [readthedocs.io] of the django-autoslug [readthedocs.io] package:
from autoslug import AutoSlugField
class Post(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=50)
body = models.TextField(max_length=5000)
image = models.ImageField(upload_to=upload_location)
date_published = models.DateTimeField(auto_now_add=True, verbose_name='date published')
date_updated = models.DateTimeField(auto_now=True, verbose_name='date updated')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(populate_from='title')
def __str__(self):
return self.title

How to Nested Categories in django admin

I want to create muti category in my ecommerce website where sub category will be dependent on main category.
Please help me with this
class MainCategory(models.Model):
# name = models.CharField(max_length=50)
# date_created = models.DateTimeField(auto_now_add=True)
# def __str__(self):
# return self.name
# class SubCategory(models.Model):
# perentcategory = models.OneToOneField(MainCategory, on_delete=models.CASCADE, primary_key=True)
# name = models.CharField(max_length=50)
# date_created = models.DateTimeField(auto_now_add=True)
# def __str__(self):
# return self.name
# class Items(models.Model):
# main = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
# name = models.CharField(max_length=255)
Posting this question 4th time
Change models.OneToOneField to models.ForeignKey so you can have multiple subcategories assigned to a main category:
class MainCategory(models.Model):
name = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class SubCategory(models.Model):
main_category = models.ForeignKey(MainCategory, on_delete=models.CASCADE, primary_key=True)
name = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Items(models.Model):
main = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
You can use single model to accommodate both Category and Sub-categories. Something like this.
class Category(models.Model):
name = models.CharField(blank=False, max_length=200)
slug = models.SlugField(null=False)
parent = models.ForeignKey('self',blank=True, null=True ,related_name='children', on_delete=models.SET_NULL)
Then add following function to the above model
def get_categories(self):
if self.parent is None:
return self.name
else:
return self.parent.get_categories() + ' -> ' + self.name
def __str__(self):
return self.get_categories()
This will return structure similar to this image

Ranking Model A by Model B

I have a Game Model and a Subscription Model:
class Game(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
cover = models.ImageField(upload_to='cover_images')
def __str__(self):
return self.title
class Meta:
ordering = ['title']
class Subscription(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
game = models.ForeignKey(Game, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return str(self.id)
Now I'm trying to figure out how to sort Games by the number of subscribers.
You can do this in Django >= 2.0:
class Game(models.Model):
# Previous code
class Meta:
ordering = [Count('subscription').desc(nulls_last=True)]
In older versions you can do this:
Game.objects.all().annotate(num_subscribers=Count('subscription')
.order_by('-num_subscribers')

Reference to another field in model.py // Django

I would like to return in str method of the Chapter, title of the Chapter and title of the Book (from book model). I need it for better display at the admin pages. How to do that?
Should I create some new method in Book or use Model instance reference https://docs.djangoproject.com/en/1.11/ref/models/instances/#model-instance-methods ?
Or maybe I should use Retrieving specific objects with filters?
https://docs.djangoproject.com/en/1.11/topics/db/queries/#retrieving-objects
I am new to the django, thank you in advance for the solutions.
class Book(models.Model):
author = models.CharField(max_length=200)
title = models.TextField()
created_date = models.DateTimeField(
default=timezone.now)
def __str__(self):
return self.title+" ("+self.author+")"
def book_author(self):
return self.author
class Chapter(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
title = models.TextField()
created_date = models.DateTimeField(
default=timezone.now)
body = models.TextField()
hierarchy = models.IntegerField()
sort = models.IntegerField(unique=True)
def __str__(self):
print(repr(Book))
print(repr(Book.author))
# print(repr(Book.objects.all().filter(id==1)))
# print(repr(Book.objects.get(id=1)))
print(repr(Book.book_author(self)))
return self.title+"(book: "+")"
def __str__(self):
return '%s (%s)' % (self.title, self.book.title,)
To print your object data in admin panel more nicely you should overide __str__ method for your models.
For example your code should look like:
class Book(models.Model):
author = models.CharField(max_length=200)
title = models.TextField()
created_date = models.DateTimeField(
default=timezone.now)
def __str__(self):
return 'Book with title: {} writen by {}'.format(self.title, self.author)
`