Behaviour of django order_by - django

I have 3 models:
class Parent(models.Model):
name = models.CharField()
class StudentDriver(models.Model):
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
class Car(models.Model):
student_driver = models.ForeignKey(StudentDriver, on_delete=models.CASCADE)
Why is it, that if I do the following, the order_by is not honoured (my qs will not be ordered by the student_driver.parent_id)? And is there a way I can get it ordered? I need it for a groupby.
for car in Car.objects.order_by('student_driver__parent'):
print(car.student_driver.parent)
If I do:
for car in Car.objects.order_by('student_driver'):
print(car.student_driver)
it works no problem (the qs is ordered by student_driver_id). Seems to be the ForeignKey link, but I can't figure it out.

I think it works:
for car in Car.objects.all().order_by('student_driver__parent__id'):
print(car.student_driver.parent.id)

Related

How to call a a field of one model A into another model B so that b can work as a view

I have created a model called Department, Course. Models are as follow
This is the model for departments and course
class Departments(models.Model):
Department_Id = models.IntegerField(primary_key=True)
Department_Name = models.CharField(max_length=200)
Department_Code = models.CharField(max_length=200)
class Course(models.Model):
Course_Id = models.IntegerField(primary_key=True)
Department_Id = models.ForeignKey(Departments, on_delete=models.CASCADE)
Course_Name = models.CharField(max_length=200)
Course_Code = models.CharField(max_length=200)
I want to create a model called view which can be later on called for search. I want a view model in a such a way that it consit of the data in concat form i.e. name= Department_name+ Course_Name
class View (models.model):
view_id= models.IntegerField(primary_key=True)
Name= Department_name(I want this from Departments table)
+ Course_Name(I want this from Course table)
I try using one to one relation . I would really appricate the help
It's not clear why you'd want to do that. It's never a good idea to duplicate data from one model into another one, as it can lead to inconsistencies.
You can add a ForeignKey in View to your Course model and then when you do f"{view.course.name} {view.course.department.name}" you already have your string:
class View(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
def name(self):
return f"{self.course.name} {self.course.department.name}"
Notes:
Don't call your foreign key Department_id because it's not referring to the id but to the object itself in the Django ORM: department = models.ForeignKey(Department, on_delete=models.CASCADE). As you can see, this makes reading the code much simpler: self.course.Department_id is a Department object not an integer, so self.course.department makes more sense.
Don't prefix your field names with the class, it just makes the code so much less readable: Do you prefer department.name or department.Department_name?
The View model is still a mystery to me, as you can search without it. You can search for example for courses with a matching department name like this:
Course.objects.filter(department__name__icontains="maths")
which will return all courses with "maths" in their department name.
Remove all the ids from your models, they are created automatically by Django anyway (and called id). Again, department.id is much easier to read than department.Department_id. Also in your code, you have to generate the ids yourself since you don't set them to auto-populate.

Reverse lookup in django

I have two models as follows
class IntakeDetails(models.Model):
intake = models.ForeignKey(intake, on_delete=models.CASCADE)
lecturer = models.ForeignKey(Lecturer, on_delete=models.CASCADE)
module= models.ForeignKey(Module, on_delete=models.CASCADE)
class AssignAssignment(models.Model):
title=models.CharField(max_length=30)
duedate=models.DateField()
intakedetails=models.OneToOneField(IntakeDetails, on_delete=models.CASCADE,related_name='details'
I have a queryset
queryset = IntakeDetails.objects.filter(lecturer=self.request.user.id)
it filters all the intakedetails that belong to that lecturer in that table. but i want it to filter that intakedetails that doesnt exist in assign assignment model.
anyone can help ?
Try the following based on the related_name details:
IntakeDetails.objects.filter(lecturer=lecturer_id,details__isnull=True)

Django OrderBy using ManyToMany table

I have the models:
class Category(models.Model):
description = models.CharField(unique=True, max_length=200)
class Car(models.Model):
categorys = models.ManyToManyField(Category)
Constantly new cars are added.
I'd like to get the last 20 categories that had a car of her type added.
I got to set up a filter, but when I got to order by I could not get it anymore.
Since I can not close any logic I will not put what I have tried here.
Updating
I add 3 cars:
Car 1 have 2 categories (cat1 and cat2)
Car 2 have 3 categories (cat2, cat20, cat3)
Car 3 have 2 categories (cat4, cat1, cat90)
I need to get:
cat1, cat2, cat3, cat4, cat20, cat90 and others...
So you have this models:
class Category(models.Model):
description = models.CharField(unique=True, max_length=200)
class Car(models.Model):
categorys = models.ManyToManyField(Category)
According to this phrase:
I'd like to get the last 20 categories that had a car of her type
added.
at first we have to find the car:
car = Car.objects.get("""your parameters""")
Then we have to find categories:
category = car.category_set.all()[:20]
Try this
UPD
When you get all Cars and Category that you need, you can get to any of category object.
categories = Cars.objects.filter("""your filter""").select_related('categorys')
for category in categories.categorys_set():
print(category.description)
I use extra() function to solve the problem.
See code blow:
class School(models.Model):
...
tag = models.ManyToManyField(Tag)
def tags(self):
meta = self.tag.through._meta
db_table = meta.db_table
primary_key = meta.pk.name
order_by = [db_table + '.' + primary_key]
return list(self.tag.extra(order_by=order_by).values_list('name', flat=True))
By adding order by to sql statement to make results order by pk of through (if not specified django will create a table for you automaticly) table.
Hope this will be helpful.

django custom model field

If I have 2 interlinked models:
class Person(models.Model)
name = models.CharField()
class Project(models.Model):
person = models.ForeignKey(Person)
title = models.CharField()
I frequently find myself trying to find the number of Projects associated with each Person:
person = Person.objects.get(id=1)
no_projects = Project.objects.filter(person=person).count()
Is there a way of adding this as a custom field to the Person model, such that I may just call person.no_projects?
This can be done by adding a property to the Person class.
class Person(models.Model)
name = models.CharField()
#property
def no_projects(self):
return Project.objects.filter(person=self).count()
This can be called now like this
person = Person.objects.get(id=1)
person.no_projects
In fact, that functionality is (almost) built-in. Instead of querying Projects, you can just do person.project_set.count() to get that person's count of projects (and .all() to get the actual list).
You can use the property() to generate the dynamical field.
class Project(models.Model):
person = models.ForeignKey(Person)
title = models.CharField()
def _get_no_projects(self):
return Projects.objects.filter(person=self).count()
no_projects = property(_get_no_projects)
But the dynamical fields can not be used in querying, because the they don't really store data into the database.
FYI: http://www.b-list.org/weblog/2006/aug/18/django-tips-using-properties-models-and-managers/

Sorting Related objects in Django

I have 2 models Category and Item. An Item has a reference to a Category.
class Category(models.Model):
name = models.CharField(max_length=32)
class Item(model.Models):
name = models.CharField(max_length=32)
category = models.ForeignKey(Category)
sequence = models.IntegerField()
The sequence field is supposed to capture the sequence of the Item within a category.
My question is:
What Meta Options do i need to set on category and/or item such that when i do:
category.item_set.all()
that I get the Items sorted by their sequence number.
PS: I am now aware of a meta option called ordering_with_respect_to .. but it is still unclear how it works, and also i have legacy data in the sequence columns. I am open to data migration, if the right approach requires that.
What you're looking for is:
class Item(model.Models):
name = models.CharField(max_length=32)
category = models.ForeignKey(Category)
sequence = models.IntegerField()
class Meta:
ordering = ['sequence',]
That will ensure that Items are always ordered by sequence.
category.item_set.all().order_by('sequence')
Kinda late, and the previous answers don't solve my specific question, but they led me to an answer, so I'm gonna throw this in:
I need to sort my prefetch_related objects specifically for only one view, so changing the default ordering is no good (maybe a model_manager would do it, idk). But I found this in the docs.
I have the following models:
class Event(models.Model):
foo = models.CharField(max_length=256)
....
class Session(models.Model):
bar = models.CharField(max_length=256)
event = models.ForeignKey(Event)
start = models.DateTimeField()
....
class Meta:
ordering = ['start']
Now in a particular view, I want to see all the Events, but I want their Sessions in reverse order, i.e., ordering = ['-start']
So I'm doing this in the view's get_queryset():
from django.db.models import Prefetch
session_sort = Session.objects.all().order_by('-start')
prefetch = Prefetch('sessions', queryset=session_sort)
events = Event.objects.all().prefetch_related(prefetch)
Hope it helps somebody!
*BTW, this is just a simplified version, there are a bunch of filters and other prefetch_related parameters in my actual use case.