Find annotated list of siblings in Django - django

I have a simple database with two models that define a parent-child relationship. In it, a child can have two possible gender, "Male" or "Female".
class Parent(models.Model):
id = models.UUIDField(primary_key=True, editable=False, unique=True, )
name = models.CharField(max_length=64)
MALE = "MALE"
FEMALE = "FEMALE"
class Child(models.Model):
id = models.UUIDField(primary_key=True, editable=False, unique=True, )
name = models.CharField(max_length=64)
parent = models.ForeignKey(
Parent,
null=True,
on_delete=models.SET_NULL)
GENDER = [
(MALE, 'Male'),
(FEMALE, 'Female'),
]
status = models.CharField(
max_length=8,
choices=GENDER
)
For the purposes of this question, a parent will only ever have zero or one male children, and zero or one female children. (Though this is not enforced in the database model definition.)
What I would like to achieve is an annoted query, that returns all Parent objects, annoted with their male child and female child. I can't quite figure out how to produce this: I can get a list of all parents, all male and all female children, but I don't know how to put them together so that the right children are with the right parent.
This is far as I get:
annotated_parent_set = Parent.objects.get_queryset()
brothers = Child.objects.filter(gender=MALE)
sisters = Child.objects.filter(gender=FEMALE)
annotated_parent_set = annotated_parent_set.annotate(
brother=F(???))
)
annotated_parent_set = annotated_parent_set.annotate(
sister=F(???))
)
How can I now merge these guys to get the annotation I want?

You don't need to annotate this, you can .prefetch_related(…) [Django-doc] this with:
annotated_parent_set = Parent.objects.prefetch_related('child_set')
or if you want to use .brothers and .sisters, then you can work with two Prefetch objects [Django-doc]:
from django.db.models import Prefetch
annotated_parent_set = Parent.objects.prefetch_related(
Prefetch('child_set', Child.objects.filter(status=MALE), to_attr='brothers'),
Prefetch('child_set', Child.objects.filter(status=FEMALE), to_attr='sisters')
)

Related

Should i create one model for multiple apps in a clothing project?

It's my first time creating a project with Django. and it's an e-commerce store for clothing. my confusion now is, most of the items are similar, like women's wears, men's wears, children's wears.Creating different models in different apps means i have to repeat a lot of code because most of the fields will be same and some operations would be more complicated to achieve like global search, etc.
So should i create a single database for all of the items and filter out what i need in different sections like menswear page, women's wear page, etc ?
#For men's model
from django.db import models
from django.urls import reverse
# Create your models here.
CLOTH_CATEGORY_OPTIONS = (
("top", "Top"),
("bottom", "Bottom"),
("complete", "Complete"),
)
CLOTH_GENDER_OPTIONS = (
("male", "Male"),
("female", "Female"),
("unisex", "Unisex"),
)
class Wear(models.Model):
cloth_name = models.CharField(max_length=50, unique=True)
cloth_image = models.CharField(max_length=300)
cloth_category = models.CharField(
max_length=8, choices=CLOTH_CATEGORY_OPTIONS, default='top')
cloth_gender = models.CharField(
max_length=8, choices=CLOTH_GENDER_OPTIONS, default='male')
cloth_price = models.FloatField()
cloth_description = models.TextField()
slug = models.SlugField(default='', editable=False,
max_length=200, null=False)
#For women's model
from django.urls import reverse
# Create your models here.
CLOTH_CATEGORY_OPTIONS = (
("top", "Top"),
("bottom", "Bottom"),
("complete", "Complete"),
)
CLOTH_GENDER_OPTIONS = (
("male", "Male"),
("female", "Female"),
("unisex", "Unisex"),
)
class WomensWear(models.Model):
cloth_name = models.CharField(max_length=50, unique=True)
cloth_image = models.CharField(max_length=300)
cloth_category = models.CharField(
max_length=8, choices=CLOTH_CATEGORY_OPTIONS, default='top')
cloth_gender = models.CharField(
max_length=8, choices=CLOTH_GENDER_OPTIONS, default='male')
cloth_price = models.FloatField()
cloth_description = models.TextField()
slug = models.SlugField(default='', editable=False,
max_length=200, null=False)
As you can see, this is repetitive, so i want to create a global database so i can import it in each app and filter out for men, women, children etc.
You didn't need to repeat all this code for each gender..
Make one model with a field Gender and specify all the genders.
You can filter the clothes in the views with:
Wear.objects.all().filter(Gender=**Male or Women**)
That will filter your products with the gender you give.
Creating 2 models will work for you. A Cloth Model and a Gender Model
One cloth can be of a male or female or both so will work with one to many
class Cloth(models.Model):
gender = models.ForiegnKey(Gender)
....
You will be filtering using:
Cloth.objects.filter(gender__type="male")

Django: Hierarchy model query

Imagine there is a model:
class OrgUnit(models.Model):
parent = models.ForeignKey(
'self',
on_delete=models.CASCADE,
verbose_name=_('parent'),
related_name='children',
blank=True,
null=True,
)
name = models.CharField(_('name'), max_length=255)
type = models.CharField(_('type'), max_length=55, null=True, blank=True, db_index=True)
And hierarchy sample:
It is easy find all stores if one knows cluster id (cluster_id=1):
stores = OrgUnit.objects.filter(
type='store',
parent__parent_id=cluster_id
)
It is also easy find cluster by sales department id (sales_department_id=5):
cluster = OrgUnit.objects.select_related('parent__parent').get(pk=sales_department_id).parent.parent
And finally find stores for sales department:
cluster_id = OrgUnit.objects.select_related('parent').get(pk=sales_department_id).parent.parent_id
stores = OrgUnit.objects.filter(type='store', parent__parent_id=cluster_id)
Getting stores by sales department id will make 2 queries to database. I wonder to know whether it possible to fetch stores by sales department id in one query? If yes how?
You can move the hierarchy down again with the children, so querying the ForeignKey relation in reverse:
stores = OrgUnit.objects.filter(
type='store',
parent__parent__children__children__pk=sales_department_id
)
Here we thus query for OrgItems that have a parent that has a parent for which there is a child for which there is a child with as primary key the sales_department_id.

How to relate multiple same models related_name in django

I have two models Movie and Actor:
class Actor(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
name = models.CharField(name="name", max_length=2000, blank=True, null=True)
class Movie(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
name = models.CharField(name="name", max_length=2000, blank=True, null=True)
actors = models.ManyToManyField(Actor, related_name='movie_actor')
Now I would like to let the users to add their favourite actors like:
class MyUser(AbstractUser):
actors = models.ManyToManyField(Actor, related_name='user_actor')
Now, I would like to make the response for each movie so that the movie can tell that this movie has one/more of their favourite actors or not.
To tell if a movie has one or more favorite actors of a given user:
has_favorite_actors = movie.actors.filter(user_actor=user).exists()
You can simply filter the Actor objects by the two parameters to get all actors in your_movie that are favored by your_user.
Actor.objects.filter(movie_actor = your_movie, user_actor = your_user)
If you just want to check if favored actors exist, add the exists() method.
Actor.objects.filter(movie_actor = your_movie, user_actor = your_user).exists()

Django : pre selection or tags. model relations

Django Version is 2.1.7
Hello, i have a OneToMany Relation and i ask my self if there is a possibility to make some kind of pre-selection (Tags or so?) for my Farmers?
Because not every Farmer has or wants Chickens or he is specialist in Cows only.
Means, right now, whenever i want to assign an individual Animal to a Farmer, i see all Farmers displayed in my Django Admin. With a growing Number of Farmers it gets confusing. So i thought to insert some Kind of Model Field in my Farmers Model... like chickens = true or not true and cows = true or not true or to introduce a new model for every species.
My Goal is, to assign a set of species to a every farmer. So that the Next time i want to add a chicken django shows only Farmers that will work with Chickens on their Farmland, it makes no sense to Display all Farmers, when some Farmers know that they handel only a specific set of species.
As a Newbie i would guess i have to make some new models for every Species with a ManyToMany Relation? So Farmers >< Species X, Y, Z < Indiviual Anmial.
Thanks
class Farmers(models.Model):
name = models.CharField(max_length=100)
farm_img = models.ImageField(upload_to='farm/', max_length=255, null=True, blank=True)
slug_farm = models.SlugField(blank=True)
<...>
class Chickens(models.Model):
farmer = models.ForeignKey(Farmers, on_delete=models.CASCADE, null=True)
chickenname = models.CharField(max_length=100)
<...>
class Cows(models.Model):
farmer = models.ForeignKey(Farmers, on_delete=models.CASCADE, null=True)
cowname = models.CharField(max_length=100)
<...>
class Rabbits(models.Model):
farmer = models.ForeignKey(Farmers, on_delete=models.CASCADE, null=True)
cowname = models.CharField(max_length=100)
<...>
If we are using postgres as DB then arrayFieldlink
can be a good option for doing this job.
from django.contrib.postgres.fields import ArrayField
class Farmers(models.Model):
.... necessary fields
SAMPLE_CHOICES = (
('CHICKEN', 'CHICKEN'),
('COW, 'COW'),
('No Species', 'No Species')
.....
)
choices = ArrayField(
models.CharField(choices=SAMPLE_CHOICES, max_length=10, blank=True, default='No Species'),
)
Now whenever we need to filter on Farmer model based on choices we can do this like following
Farmer.objects.filter(choices__contains=['cow'])
Update
As you are using django-mysql database, following thing by django-mysql link here we can have field feature like ListField link and can easily achieve this.
class ChickenFarmers(models.Model):
name = models.CharField(max_length=100)
farm_img = models.ImageField(upload_to='farm/', max_length=255, null=True, blank=True)
slug_farm = models.SlugField(blank=True)
class CowFarmers(models.Model):
name = models.CharField(max_length=100)
farm_img = models.ImageField(upload_to='farm/', max_length=255, null=True, blank=True)
slug_farm = models.SlugField(blank=True)
class RabbitsFarmers(models.Model):
name = models.CharField(max_length=100)
farm_img = models.ImageField(upload_to='farm/', max_length=255, null=True, blank=True)
slug_farm = models.SlugField(blank=True)
class Chickens(models.Model):
farmer = models.ForeignKey(ChickenFarmers, on_delete=models.CASCADE, null=True)
chickenname = models.CharField(max_length=100)
class Cows(models.Model):
farmer = models.ForeignKey(CowFarmers, on_delete=models.CASCADE, null=True)
cowname = models.CharField(max_length=100)
class Rabbits(models.Model):
farmer = models.ForeignKey(RabbitsFarmers, on_delete=models.CASCADE, null=True)
cowname = models.CharField(max_length=100)
'''
I think at this point this will give you best relief
'''

Django getting field names from different models

Guys,
Is there an easy way to return different fields names from different models by chaining joins?
My model:
Class Item(models.Model):
item_code = models.CharField(max_length=10)
name = models.CharField(max_length=255)
...
Class Stock(models.Model):
item_code = models.ForeignKey( Item )
userid = models.ForeignKey( User )
qty = models.IntegerField()
...
I want to select " Item.Item_code, Item.name, Stock.qty where Stock.userid=2 and Item.item_code = Stock.Item_Code"
How do i do this in Django?
Gath
I want to select " Item.Item_code, Item.name, Stock.qty where Stock.userid=2 and Item.item_code = Stock.Item_Code"
You can pick these specific fields only using one SQL, provided you start from the Stock model. For instance
q = Stock.objects.select_related('userid', 'item_code').filter(
userid__id = 2).values('item_code__item_code', 'item_code__name', 'qty')
This will help if you want to limit the data and then number of queries. If you are not concerned with this then do:
q = Stock.objects.filter(userid__id = 2)
for stock in q:
print stock.item_code.item_code
print stock.item_code.name
print stock.qty
This will return a queryset with only those fields you have chose using values. You can then iterate through it.
PS: Re: your models.
Class Stock(models.Model):
item_code = models.ForeignKey( Item )
userid = models.ForeignKey( User )
qty = models.IntegerField()
...
It is a good idea to use the model name in lower case for FK relationships. For e.g. you ought to write:
Class Stock(models.Model):
item = models.ForeignKey( Item ) # Changed
user = models.ForeignKey( User ) # Changed
qty = models.IntegerField()
...
You can also use this:
Stock.objects.filter(user=2).values('item__item_code', 'item__name')
First of all change fileds names
Read this very carefuly http://docs.djangoproject.com/en/dev/ref/models/querysets/
Class Item(models.Model):
item_code = models.CharField(max_length=10)
name = models.CharField(max_length=255)
...
Class Stock(models.Model):
item = models.ForeignKey( Item )
user = models.ForeignKey( User )
qty = models.IntegerField()
...
#view
stocks = Stock.objects.filter(user=2)
for stock in stocks:
print stock.item.item_code, stock.item.name
#one query version