Django model with Charfield Count and Zero values - python

I have a Django database model that has some attributes, one of them is a Charfield 'category' with Choices.
I now want to annotate a queryset of this model with the count of the rows of each category. The thing is, the way i know to do it, only categories present in the queryset are getting counted, but i want a queryset with all categories annotated with the count (0 if no rows with this category).
This is what im doing at the moment:
Model.objects.all().values('category').annotate(total=Count('category'))
Is there a way to display all categories, including such with count 0?

You can not count categories that do not exist, since, well... these do not exist. The choices are not even transferred to the database.
Using a CharField with choices is not the ideal modeling for this. Typically it is better to make a model Category and then another MyModel with ForeignKey [Django-doc] to link a MyModel object to a Category, so:
class Category(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class MyModel(models.Model):
category = models.ForeignKey(Category, on_delete=models.PROTECT)
then we can create categories like:
Category.objects.bulk_create(
Category(name='technology'),
Category(name='art'),
Category(name='science')
)
if we then link MyModel objects to these Categorys, we can annotate the Category with the number of MyModels with:
from django.db.models import Count
Category.objects.annotate(
num_mymodel=Count('mymodel')
)
Here the Categorys that arise from this queryset will have an extra attribute .num_mymodel with the number of linked MyModel objects. Since a LEFT OUTER JOIN is performed, for Categorys without any MyModels, it will use 0.

Related

How to edit many to many relation different ways in Django admin

Models.py
class Movie(models.Model):
categories = ManyToManyField('Category', blank=True)
class Category(models.Model):
grouping = CharField(choices=CategoryGroupings)
where CategoryGroupings is one of 'genre', 'holiday', or 'custom'
Question
In the Movie Django admin, I would like to have three autocomplete_fields, one for each of the individual category types. I can't add 'categories' three times to the autocomplete_fields array. Without altering the model field definitions (ie without needing a migration), how would I manage this?

Aggregate for multiple instances with a ManyToOne relation

I am new to Django and I want to build a Website to track boardgames.
What I want: For each round played a Player will get points and I want to create a table which shows the sum of all Scores for each Player.
My model is as follows:
class Player(models.Model):
name = models.CharField(max_length=150)
class Score(models.Model):
player = models.ForeignKey(Player, blank=False, null=False, on_delete=models.PROTECT)
scorevalue = models.IntegerField(blank=False, null=False)
I would like to get a queryset with all players where an additional field with the sum of his scores is added. In SQL something like
Select distinct playername, sum(scorevalue) over (partition by playername)
from Players
Join Scores
My main problem is to understand the connection between "aggregate" and "annotate" functions in combination with instances and querysets.
With an instance I can get
Player.objects.get(pk=1).score_set.aggregate(score_sum=Sum('scorevalue'))
but is it possible to do this for every instance in a queryset?
Thanks for the help.
Yes, in that case you annotate the objects, so with:
from django.db.models import Sum
Player.objects.annotate(
score_sum=Sum('score__scorevalue')
)
The Player objects that arise from this queryset will have an extra attribute .score_sum which is the sum of the related Score records.
One can make use of two consecutive underscores (__) to look "through" relations, and thus access data of related model records.

Form to show unique values from Model Django

Learning Django.. I am trying to setup the below and need your expert advise to make it better..
I created a model, and form on top of it to show the data.. and I have two questions after the code where I need your advise :)
Model:
class profilestable(models.Model):
choices = [
('Active','Active'),
('Inactive','Inactive')
]
Category = models.CharField(max_length=100)
SubCategory = models.CharField(max_length=100)
product_name = models.CharField(max_length=100)
Status = models.ChoiceField(max_length=20,choices=choices)
def __str__(self):
return self.Category
class Userlist(models.Model):
User = models.CharField(max_length=100)
Categorygroup = models.ForeignKey(profilestable,null=true,on_delete=models.SET_NULL)
def __str__(self):
return self.User
Form:
class userprofileform(forms.ModelForm):
model = Userlist
Fields = ('User','CategoryGroup')
def __init__(self,*args,**kwargs):
super(userprofileform,self).__init__(*args,**kwargs)
Sample data in the profilestable Model:
Queries:
I want to add the category, subcategory and product name as drop downs to the form however I am not sure how to access each element to show on the form. I was able to pull only category since I am returning that value.
The list currently has lots of duplicate values, is it possible to show only unique values in the drop down.
Also, is it possible to make it a multi-select and dependent cascading drop downs
Request you to please help advise/direct to implement this type of form.
Thank you so much.
The structure needs some changes, for example category should be a parent of sub-category, and then product lives below sub-category, so it would be better to create a separates models for Category, Sub-category and Product in this relation:
Category > Sub-category > Product Since sub-category and products are not unique relation to its parent, use the ForeignKey Field to connect them.
Also I see in your sample data and many products are shinked in 1 row, that is not good in any terms of scaling, performance or order.
Yet I cannot see the usecase of your Userlist model.
Once done the above please refer this answer to create your drop down menu, althought the distinct at the end is not needed as creating separate model for Category will avoid the need to duplicate Category names. Then on form submition, you Query for the correct Category and Sub-Category instance and assign it to the ForeignKey field of your form.

Ordering Model based on a max Children Attribute (with potential ties) - Django

I would like to sort my Docket object based on the most recent Document (a child object). There are typically several documents with the same date_filed. Based on the tutorial, I tried sorting on -documents__date_filed and it sort of works. Because there are multiple Documents with the exact same date, my ListView shows 2-3 repeated rows (one for each date tie). How do I avoid getting the duplicated results and just have one row for each Docket in the output?
class Docket(models.Model):
name = models.CharField(max_length=200)
class Meta:
ordering = ['-documents__date_filed', Func(F('name'), function='LOWER')]
class Document(models.Model):
docket = models.ForeignKey(Docket, on_delete=models.CASCADE, related_name="documents")
date_filed = models.DateTimeField(default=timezone.now)
It might be better to do the ordering in the ListView itself if it includes a related model, since now nearly all Docker.objects.all() querysets will have duplicates.
You can make use of .distinct() [Django-doc] to retrieve a queryset of Docket objects where the same one only occurs once:
from django.views.generic import ListView
from django.db.models.functions import Lower
class DocketListView(ListView):
model = Docket
queryset = Docket.objects.order_by(
'-documents__date_filed',
Lower('name')
).distinct()

What's the use of Intermediate models in Django?

Why do we use an intermediate model?
Can't we just use Many to many relationship without intermediate model?
M2M relationships require intermediate tables. You can read more about what M2M relationships are and why they require an intermediate table (referred to as a junction table in the article) here:
Django abstracts this away by automagically creating this intermediate table for you, unless you need to add custom fields on it. If you do, then you can define it by overriding the through parameter as shown here
Here's a quick picture of why the table is required
Source: https://www.geeksforgeeks.org/intermediate-fields-in-django-python/
Let's say you have two models which have a Many-to-Many relationship, like Customer and Product. One customer can buy many products and a product can be bought by many customers.
But you can have some data that doesn't belong to neither of them, but are important to the transaction, like: quantity or date.
Quantity and date are the intermediary data which are stored in intermediary models.
from django.db import models
class Item(models.Model):
name = models.CharField(max_length = 128)
price = models.DecimalField(max_digits = 5, decimal_places = 2)
def __str__(self):
return self.name
class Customer(models.Model):
name = models.CharField(max_length = 128)
age = models.IntegerField()
items_purchased = models.ManyToManyField(Item, through = 'Purchase')
def __str__(self):
return self.name
class Purchase(models.Model):
item = models.ForeignKey(Item, on_delete = models.CASCADE)
customer = models.ForeignKey(Customer, on_delete = models.CASCADE)
date_purchased = models.DateField()
quantity_purchased = models.IntegerField()
When you buy a product, you do it through the Purchase model: the client customer buys quantity_purchased quantity of items item in date_purchased.
The Purchase model is the Intermediate model.
Django documentation says:
...if you want to manually specify the intermediary table, you can use
the through option to specify the Django model that represents the
intermediate table that you want to use.
In this case we have this line in the Customer model, which defines the intermediary model in through = 'Purchase'
items_purchased = models.ManyToManyField(Item, through = 'Purchase')
Let's now use the example from the Django Documentation.
You have a database of musicians with a Many-to-Many relationship with the bands the belong to: a musician can belong can be part of many bands, and the bands can have many musicians.
What data do you want to keep?
For musicians (person): name and instrument they play
For the bands: name and style.
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
age = models.IntegerField()
class Group(models.Model):
name = models.CharField(max_length=128)
style = models.CharField(max_length=128)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
But, wouldn't you think that knowing when the person joined the band is important? What model would be the natural place to add a date_joined field? It makes no sense to add it to Person or Group, because it's not an intrinsic field for each of them, but it's related to an action: joining the band.
So you make a small, but important adjustment. You create an intermediate model that will relate the Person, the Group with the Membership status (which includes the date_joined).
The new version is like this:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
age = models.IntegerField()
class Group(models.Model):
name = models.CharField(max_length=128)
style = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
The changes are:
You added a new class called Membership which reflects the membership status.
In the Group model you added members = models.ManyToManyField(Person, through='Membership'). With this you relate Person and Group with Membership, thanks to through.
Something important to clarify.
An intermediate model, or in relational database terms, an associative entity, are always needed in a Many-to-Many (M2M) relationship.
A relational database requires the implementation of a base relation
(or base table) to resolve many-to-many relationships. A base relation
representing this kind of entity is called, informally, an associative
table... that can contain references to columns from the same or different database tables within the same database.
An associative (or junction) table maps two or more tables together by
referencing the primary keys of each data table. In effect, it
contains a number of foreign keys, each in a many-to-one relationship
from the junction table to the individual data tables. The PK of the
associative table is typically composed of the FK columns themselves. (source)
Django will create the intermediate model, even when you don't explicitly define it with through.
Behind the scenes, Django creates an intermediary join table to
represent the many-to-many relationship. By default, this table name
is generated using the name of the many-to-many field and the name of
the table for the model that contains it.
Django will automatically generate a table to manage many-to-many
relationships. However, if you want to manually specify the
intermediary table, you can use the through option to specify the
Django model that represents the intermediate table that you want to
use.
The most common use for this option is when you want to associate extra data with a many-to-many relationship.(source)

Categories

Resources