I'm having a hard time trying to figure out how to use annotations in the Django ORM to achieve grouping through a model.
from django.db import models
class Customer(models.Model):
name = models.CharField(max_length=255)
class Store(models.Model):
name = models.CharField(max_length=255)
class Order(models.Model):
customer = models.ForeignKey(Customer)
store = models.ForeignKey(Store)
order_date = models.DateTimeField()
If my Stores are Los Angeles, Denver, Houston & Atlanta, how do I get a count of
Customers by store using the latest order date?
Los Angeles: 25
Denver: 210
Houston: 400
Atlanta: 6
Define a ManyToMany field on either Customer or Store, pointing to the other model, with Order as the through table. For example:
class Store(models.Model):
name = models.CharField(max_length=255)
orders = models.ManyToManyField(Customer, through=Order)
Now you can do:
from django.db.models import Count
Store.objects.annotate(Count("orders__customer"))
Related
Hey guys I am trying to add a m2m through field to have assistants to my 'Department' model to call like department.assistants.all(), but while doing so, I am getting this error AttributeError: 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache'.
This is my model:
class Department(models.Model):
id = models.BigAutoField(primary_key=True)
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
assistants = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Assistants', related_name='dep_assistants',
symmetrical=False)
class Assistants(models.Model):
id = models.BigAutoField(primary_key=True)
department = models.ForeignKey(Department, related_name='of_department', on_delete=models.CASCADE)
assistant = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='dt_assistant',
verbose_name="Department Assistant", on_delete=models.CASCADE)
added = models.DateTimeField(auto_now_add=True)
I am pretty new to this concept. Can someone tell me what I did wrong here?
Thanks
The way you have defined your models the queries seem too confusing. Try how models are defined below and then try the query.
You did not mention the through_field attribute in the many to many field definition. check the docs: https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ManyToManyField
class Department(models.Model):
# i think this is not needed. Also id is a protected keyword in python.
# id = models.BigAutoField(primary_key=True)
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
assistants = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Assistants',
related_name='departments', through_fields=("department", "assistant"))
# model name should never be prural. It is singluar becuase it is the name of the object.
class Assistant(models.Model):
# i think this is not needed. Also id is a protected keyword in python.
# id = models.BigAutoField(primary_key=True)
department = models.ForeignKey(Department, on_delete=models.CASCADE)
assistant = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name="Department Assistant", on_delete=models.CASCADE)
added = models.DateTimeField(auto_now_add=True)
# how to query assistants from departments
# you will get objects of User model
qs = department.assistants.all()
# how to query departments from assistants
# you will get objects of Department model
qs = user.departments.all()
# If you want to query the Assistant model
# from department object
qs = department.assistant_set.all()
# from assistant object
qs = user.assistant_set.all()
# in either case you will get the objects of Assistant model
for i in qs:
print(i.added, i.department, i.assistant)
Try this and let me know if you still get the error.
My suggestion is to name the assistant field on the Assistant model as user. This way you will not need to define through_field on the many to many field.
If one assistant relates to only one department - this is relation one-to-many. (One department has many assistants) In code would be:
class Assistant(models.Model):
...
department = models.ForeignKey(Department)
No need for a special reference on Department. To get all assistants:
assistants = models.Assistant.objects.filter(department=department)
Or create a property on a class Department:
#property
def assistants(self):
return models.Assistant.objects.filter(department=self)
If one assistant relates to many departments (and each department has many assistants), it is many-to-many relationship and there should be additional class between them:
class Assignment(models.Model):
assistant = models.ForeignKey(Assistant)
department = models.ForeignKey(Department)
class Department(models.Model):
...
assignment= models.ForeignKey(Assignment)
class Assistant(models.Model):
...
assignment = models.ForeignKey(Assignment)
So here to query assistants of the department:
assistants = models.Assistant.objects.filter(
assignment__in=models.Assignment.objects.filter(
department=department
)
)
am new to django so complex querying is becoming difficult.
I have a model Animal and Heat i would like to fetch an Animal
instance with farm=1 AND sex='female' AND an Animal
instance with Heat.is_active=True AND Heat.is_bred=False
Here is my models.
class Animal(models.Model):
farm = models.ForeignKey(Farm, related_name='farm_animals', on_delete=models.CASCADE)
name = models.CharField(max_length=25)
sex = models.CharField(max_length=7)
class Heat(models.Model):
animal = models.ForeignKey(Animal, related_name='heats', on_delete=models.CASCADE)
is_bred = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
So far i tried this query:
Animal.objects.filter(
farm=1, sex='female',
heats__is_active=True,
heats__is_bred=False
)
I can fetch a data if an animal instance HAS HEAT RECORD however i can't fetch any when there is NO HEAT RECORD.
You can use OR between the two pairs of conditions using the Q() object:
from django.db.models import Q
Animal.objects.filter(
(Q(farm=1) & Q(sex='female')) |
(Q(heats__is_active=True) & Q(heats__is_bred=False))
)
This will give you a queryset containing animals that don't even have a Heat record.
I have something like this:
class Car(models.Model):
model = models.CharField(max_length=200)
brand = models.CharField(max_length=100)
status = models.ManyToMany(Status)
class Status(models.Model):
name = models.CharField(max_length=40)
date = models.DateTimeField('Status creation date')
How can I query all the cars where their last status (most recent) is REPAIRED for instance? Is this achievable in just one query?
from django.db.models import Max
cars = Car.objects.annotate(Max('status__date')).filter(status__name='REPAIRED').distinct()
You may read the Django examples for Many to Many relationships.
I have one application and one model.
I want to separate the model on two applications, so that the user was managed from a separate application.
Is the transfer of this model will do the trick? What I have to do?
class User(AbstractUser):
country = models.CharField(max_length=2, choices=COUNTRY, default=RUSSIA)
Here is my models.py - must be separate
RUSSIA = 'RUS'
USA = 'USA'
GERMANY = 'GER'
COUNTRY = (
(RUSSIA, "Russia"),
(USA, "USA"),
(GERMANY, "Germany"),
)
class User(AbstractUser):
country = models.CharField(max_length=2, choices=COUNTRY, default=RUSSIA)
class Country(models.Model):
country = models.CharField(max_length=3, choices=COUNTRY, default=RUSSIA)
name_of_team = models.CharField(max_length=255, blank=True, null=True)
def __unicode__(self):
return self.name_of_team
You can create two applications, one for Users and one for Countries. Then put the User model in the Users app and the Country model in the Countries app.
Then in a third app you can import both as you need them:
from countries.models import Country
from users.models import User
Put this part of the code in the settings.py file:
RUSSIA = 'RUS'
USA = 'USA'
GERMANY = 'GER'
COUNTRY = (
(RUSSIA, "Russia"),
(USA, "USA"),
(GERMANY, "Germany"),
)
If you do this then you can access the constants from both apps like this:
from django.conf import settings
settings.COUNTRY
You can create two apps, one for users and one for countries, then you just import country model into user model.
Besides if you want to keep a relationship between countries and user you should use a ForeignKey. Sorry if it does not match with your logic but I'm not sure how your models have to looks like, it is a bit estrange for me.
Something like this:
country/models.py
RUSSIA = 'RUS'
USA = 'USA'
GERMANY = 'GER'
COUNTRY = (
(RUSSIA, "Russia"),
(USA, "USA"),
(GERMANY, "Germany"),
)
class Country(models.Model):
# I don't know why country attr in Country class
country = models.CharField(max_length=3, choices=COUNTRY, default=RUSSIA)
name_of_team = models.CharField(max_length=255, blank=True, null=True)
def __unicode__(self):
return self.name_of_team
user/models.py
from country.models import Country
class User(AbstractUser):
# ForeignKey, here you make the relation with country model
country = models.ForeignKey(Country)
The below is a database of colleges, and its ratings. The below is how I thought
Each Class (Batch, ex: Batch of 2009) belongs to a Department
Each Department (ex: department of pharmacy) belongs to a College
As I am particularly concerned about Ratings. I thought to Rate a Batch, there by using a Manager or some Model Method, I can calculate Total Department or College Ratings.
Each Class has Ratings
Note: There may be many ratings by different Users for a single Class. So, I guess Total or Average ratings should be done by a Method!
This is how I so far did
class Rating(models.Model):
positive = models.FloatField(default=0)
negative = models.FloatField(default=0)
class College(models.Model):
name = models.CharField(max_length=200)
website = models.URLField()
class Department(models.Model):
name = models.CharField(max_length=200)
college = models.ForeignKey(College)
class Batch(models.Model):
passout_year = models.IntegerField(max_length=4)
department = models.ForeignKey(Department)
rating = models.ForeignKey(Rating)
This schema has some issues!
Each Batch can only have single rating! However, I am looking for multiple ratings signed by many Users (Though Users model is not integrated yet)
Each Batch belongs to a Department, Each Department belongs to a College. However, we can also think of the relationships in another way
Each College has many Departments, Each Department has many Batches While.. Each Batch has Many Departments (ex: there may be many departments in 2009), and Each Department can be in Many colleges
So, should I use ManyToManyField instead of ForeignKey?
How should I schema should look like?
One of the most essential changes I think are
class Rating(models.Model):
..
..
user = models.ForeignKey(django.contrib.auth.models.User)
class College(models.Model):
..
..
departments = models.ManyToManyField(Department)
class Department(models.Model):
..
college = models.ForeignKey(College)
batches = models.ManyToManyField(Batch)
class Batch(models.Model):
..
department = models.ForeignKey(Department)
rating = models.ManyToMany(Rating)
Is this going to be right? How should it look if if not
Thanks
Here it goes:
from django.contrib.auth.models import User#First import user
lass Rating(models.Model):
..
..
user = models.ForeignKey(User)
class College(models.Model):
..
..
departments = models.ManyToManyField(Department)
class Department(models.Model):
..
college = models.ForeignKey(College)
batches = models.ManyToManyField(Batch)
class Batch(models.Model):
..
department = models.ForeignKey(Department)
rating = models.ManyToMany(Rating)
When you make many to many relationship a bridge entity is automatically created by Django.