how to get results of query in another query in django - django

I have the following models:
class Activity(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class CustomerActivity(models.Model):
customer = models.ForeignKey(Customer)
activity = models.ForeignKey(Activity)
def __unicode__(self):
return self.activity.name
I have a filter that gets all the CustomerActivities for a customer:
customer_activities = CustomerActivity.objects.filter(customer=customer)
What I really need is all the Activity objects based on the results of the customer_activities?
Something like
activities = Activity.objects.filter(activity_in=customer_activities)???

Try this
activities = Activity.objects.filter(customeractivity__customer=customer)
Read more on lookups that span relationships

Related

Django | Queryset ManyToMany Relation through Instance

I would like to display the different dates for each course. A course can also have several dates. Unfortunately I can't find a solution.
Models:
class Course(models.Model):
course_number = models.CharField(max_length=24, blank=True)
course_location = models.ForeignKey(Course_location, on_delete=models.CASCADE)
course_dates = models.ManyToManyField('Course_dates', through="Course_Course_dates")
def __str__(self):
return self.course_number
class Course_Course_dates(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
course_dates = models.ForeignKey(Course_dates, on_delete=models.CASCADE)
def __str__(self):
return self.id
class Course_dates(models.Model):
date = models.DateField()
start = models.TimeField()
end = models.TimeField()
trainer = models.ManyToManyField('Trainer', through="Course_dates_trainer")
def __str__(self):
return self.date.strftime("%d.%m.%Y")
View:
def course_list(request):
courses = Course.objects.all()
course_list = []
for course in courses:
course_location = course.course_location.description
dates = course.course_dates.all()
course_list.append({'course': course, 'course_location': course_location, 'dates': dates,})
context = { 'course_list': course_list, }
return render(request, 'kursverwaltung_tenant/course.html', context)
Thanks for help!!!
Your courses queryset will already have access to your course dates through the foreign key so you don't need to run a second dates queryset in the view to access them.
When you loop through the courses, you'll then need to run a second loop through the dates of those courses within your template. Here's an example of that:
Display foreign key value in django template

Filter parent objects which have no children object using prefetch_related

I have three models as following, with Seller as the grandparent, Genre as the parent and Book as the chidlren:
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
If I use prefetch_related() to fetch the Seller objects along with their Genre and Book as following in one single databse query:
sellers = Seller.objects.prefetch_related('genre__book').filter()
However, I would like to filter out Seller objects that have no Book objects related to. What would be the syntax for the filter() in this case?
To filter genres that have no books in it you need the following condition:
genres = Genre.objects.exclude(pk__in=[x.genre.pk for x in Book.objects.all()]
To combine it with prefetch_related I think you need to use Prefetch object with a given queryset
from django.db.models import Prefetch
sellers = Seller.objects.prefetch_related(
Prefetch('genre_set',
queryset=Genre.objects.exclude(pk__in=[x.genre.pk for x in Book.objects.all()])
)

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

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.

Django prefetch_related with m2m through relationship

I have the following models
class Film(models.Model):
crew = models.ManyToManyField('Person', through='Role', blank=True)
class Role(models.Model):
person = models.ForeignKey('Person')
film = models.ForeignKey('Film')
person_role = models.ForeignKey(RoleType)
credit = models.CharField(max_length=200)
credited_as = models.CharField(max_length=100)
class RoleType(models.Model):
"""Actor, director, makeup artist..."""
name = models.CharField(max_length=50)
class Person(models.Model):
slug = models.SlugField(max_length=30, unique=True, null=True)
full_name = models.CharField(max_length=255)
A Film("Star Wars: The Clone Wars") has several Person("Christopher Lee"), each one of them can have one or more Role("Voice of Count Dooku") and every Role has a RoleType("Voice actor").
I'm using a DetailView to display the Film
class FilmDetail(DetailView):
model = Film
In my template i'm showing all the Persons, so each time I show a Film 609 queries are being executed. To reduce this I want to use prefetch_related so I changed the view to:
class FilmDetail(DetailView):
model = Film
def get_queryset(self):
return super(FilmDetail, self).get_queryset().prefetch_related('crew')
But this didn't reduce the number of queries(610), I tried the following parameters to prefetch related and it didn't work:
def get_queryset(self):
return super(FilmDetail, self).get_queryset().prefetch_related('crew__person_role')
I got an Cannot find 'person_role' on Person object, 'crew__person_role' is an invalid parameter to prefetch_related()error
What can I do to prefetch the Person.full_name and slug and all Role fields from Film.crew?
You can construct your queryset like this:
from django.db.models import Prefetch
def get_queryset(self):
return super(FilmDetail, self).get_queryset().prefetch_related(
Prefetch(
'crew',
queryset=Role.objects.select_related(
'person',
'person_role',
),
),
)
Only Film->Role is a backwards relation loadable with prefetch_related. Role->RoleType and Role->Person are forwards relations that you load with select_related.