Django order many to many relationship - django

I have been playing around with Django's many to many field with the following models:
class ProjectLanguage(models.Model):
title = models.CharField(max_length=15)
def __str__(self):
return self.title
class Project(models.Model):
title = models.CharField(max_length=30)
img = models.CharField(max_length=50)
main_text = models.TextField(default="main project description ...", null=True, blank=True)
languages = models.ManyToManyField(ProjectLanguage)
def __str__(self):
return self.title
I want to get a list of projects ordered by their ProjectLanguage title. How do I achieve this with Django ?
Thanks
Mark

You can define a method like this:
class Project(models.Model):
...
def ordered_languages(self):
return self.languages.all().order_by('title')
Or you may want to use a through table with ordering.

Related

Syntax to reverse-query a cached queryset

I have the following 3 models related by Foreign Key as following:
class Seller(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Genre(models.Model):
seller= models.ForeignKey(Seller, related_name="genre", on_delete=models.CASCADE)
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Book(models.Model):
genre= models.ForeignKey(Genre, related_name="book", on_delete=models.CASCADE)
name = models.CharField(max_length=20)
def __str__(self):
return self.name
And I want to retrieve the whole 3 tables in one database query, by querying the Seller objects, as following:
sellers = Seller.objects.select_related('genre', 'book').all().values('name')
seller_df = pd.DataFrame(list(sellers))
What is the syntax to filter for books carried by a particular seller, without hitting the database again (by utilizing either the Seller queryset or the pandas seller_df)
seller1 = seller_df ['name'].iloc[0]
seller1_books = Book.objects.filter(...)
seller_last = seller_df ['name'].iloc[-1]
seller_last_books = Book.objects.filter(...)
I dont know so mach about caching but I know something that you like:
We use select_related when the object is single like onetoone or fk.
.
for many to many or reverse fk like your example use prefetch_related

Count number of post in a category

I want to list all the categories in my news table plus add the number of post in each categories.
Here is my model :
class Blog(models.Model):
titre_article = models.CharField(max_length=255)
auteur_article = models.ForeignKey(User, on_delete=models.CASCADE)
date_article = models.DateTimeField(auto_now_add=True)
modif_article = models.DateTimeField(auto_now=True)
categorie_article = models.ForeignKey('BlogCat',
on_delete=models.CASCADE,
default='1')
contenu = RichTextField(null=False)
def __str__(self):
return self.titre_article
def get_absolute_url(self):
return f"/blog/{self.id}"
class BlogCat(models.Model):
nom_categorie = models.CharField(max_length=255)
def __str__(self):
return self.nom_categorie
def get_absolute_url(self):
return f"/blog/cat/{self.nom_categorie}"
From there I can't imagine what the code in the view.py should be.
Can someone help ?
Thx a lot :)
Jeff
You can annotate your BlogCat model with the number of Blogs:
from django.db.models import Count
BlogCat.objects.annotate(nblog=Count('blog'))
The BlogCat objects that arise from this queryset will have an extra attribute .nblog that contains the number of related Blog objects.
You have to use cout()
obj = YourObject.objects.all().count()

querysets in models with manytomany fields (Django)

My question is associated with making querysets on models that are interconnected across many to many fields.
context - an app that a student enters and has to rate his or her teachers. the questions the app shows the student have the following logic: each student must rate some teachers. Each teacher has different categories of questions associated with them ("intelligence", "respect", "empathy",etc.) and each of these categories has some questions associated with it.
The models are:
class Items(models.Model):
item = models.TextField()
def __str__(self):
return self.item
class Categories(models.Model):
category = models.CharField(max_length=50,null=True)
items_associated = models.ManyToManyField(Items)
def __str__(self):
return self.category
class Professors(models.Model):
professor = models.CharField(max_length=50,null=True)
categories_assigned = models.ManyToManyField(Categories)
def __str__(self):
return self.professor
class Students(models.Model):
student_logged = models.CharField(max_length=50,null=True)
professors_to_evaluate = models.ManyToManyField(Professors)
def __str__(self):
return self.student_logged
when a student enters the web has some associated teachers (model Students) these teachers in turn have some categories assigned (model Professors), these categories in turn have some questions associated (model Categories). I want to store in a dictionary these questions that are in the model Items. How can I do it?
I've tried to filter and __in but I can't get it.
Many thanks and thank you for the wisdom
I highly suggest you use the related_name attribute. I've added _x to the related names to make the query more obvious.
class Items(models.Model):
item = models.TextField()
def __str__(self):
return self.item
class Categories(models.Model):
category = models.CharField(max_length=50,null=True)
items_associated = models.ManyToManyField(Items, related_name='category_x')
def __str__(self):
return self.category
class Professors(models.Model):
professor = models.CharField(max_length=50,null=True)
categories_assigned = models.ManyToManyField(Categories, related_name='professor_x')
def __str__(self):
return self.professor
class Students(models.Model):
student_logged = models.CharField(max_length=50,null=True)
professors_to_evaluate = models.ManyToManyField(Professors, related_name='student_x')
def __str__(self):
return self.student_logged
items_for_student = Items.objects.filter(category_x__professor_x__student_x=student)
But also the naming conventions you are using for the fields are a bit quirky. I've used best practices below so you can see what that would look like.
Don't have a field with the same name as the model
Models should be singular (with rare exceptions)
ManyToMany or ForeignKey relations should share the name of the model to make querying self document.
With those rules here is what the best practice looks like.
class Item(models.Model):
name = models.TextField()
def __str__(self):
return self.name
class Category(models.Model):
name = models.CharField(max_length=50,null=True)
items = models.ManyToManyField(Item, related_name='categories')
def __str__(self):
return self.name
class Professor(models.Model):
name = models.CharField(max_length=50,null=True)
categories = models.ManyToManyField(Category, related_name='professors')
def __str__(self):
return self.name
class Student(models.Model):
name = models.CharField(max_length=50,null=True)
professors = models.ManyToManyField(Professor, related_names='students')
def __str__(self):
return self.name
And with that structure the query would look like:
items = Item.objects.filter(categories__professors__students=student)
Also note that the above query will be very expensive to run on a database as it would evaluate to 3 joins.

Search from two models with Haystack

How to have Haystack search from two models?
class People(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
def __unicode__(self):
return self.name
class Note(models.Model):
user = models.ForeignKey(CustomUser)
title = models.CharField(max_length=200)
body = models.TextField()
pub_date = models.DateTimeField()
def __unicode__(self):
return self.title
Implementing two indexes did not help.
If you have registered search index for all models you can specify which of it to search e.g.:
SearchQuerySet().filter(content='foo').models(People, Note)
if not specified it will search everywhere
Indexes should be like
class PeopleIndex(indexes.SearchIndex, indexes.Indexable):
....
class NoteIndex(indexes.SearchIndex, indexes.Indexable):
....
in appropriate search_indexes.py in apps
P.S. make sure all models is indexed by doing direct queries to search engine you using (if possible)

Django models - before save/create

I have two Models:
class Category(MPTTModel):
name = models.CharField(max_length=50,unique=True)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children')
def __unicode__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=50)
categories = models.ManyToManyField(Category,related_name='products')
def __unicode__(self):
return self.name
The categories follow a tree like structure and I want to add products only to 'leaf categories'.
When I call my_category.products.create(...) or similar and my_category.is_leaf_node() == False then it should fail.
The same for my_category.children.create(...) if my_category has products already then it should fail.
Those checks go in the save method? in a custom manager? or some where else? I would the verification to be at model level.
The proper location for model-level validation is in the clean() function. You can raise a django.core.exceptions.ValidationError here to describe your error. Have a look at the documentation for clean()