Group by in Django? - python

I have the next structure in my django app:
class Telefono(models.Model):
tipo = models.CharField(max_length=200)
lada = models.IntegerField()
numero = models.CharField(max_length=12)
def __unicode__(self):
return (self.tipo +" - (" +str(self.lada)+")"+str(self.numero))
class Persona(models.Model):
nombre = models.CharField(max_length=200)
apellidoPaterno = models.CharField(max_length=200)
apellidoMaterno = models.CharField(max_length=200)
rfc = models.CharField(max_length=10)
ubicacion = models.OneToOneField(Ubicacion)
telefonos = models.ManyToManyField(Telefono)
The problem is: I need a single "telefono" to show in my datagrid.. so I built the next query in MYSQL:
select p.nombre,tf.numero from persona as p join persona_telefonos AS t ON t.persona_id=p.id join telefono As tf ON t.telefono_id=tf.id group by p.id
And actually gives this result:
"nombre" "numero"
"MiKchorro123213" "5345234523"
But in django I have this query:
Cliente.objects.filter().values("id","nombre","telefonos__numero", "ubicacion__direccion")
And I get two results.. one for each ("telefono") object in the many to many relationship..
How can I do a group by function in django?

Please refer documentation : Raw Query, Filterings, Group_by
example:
query = Cliente.objects.all().query
query.group_by = ['field_name']
results = QuerySet(query=query, model=Model_name)

Related

Django Models create a task for all users

I'm trying to build a webapp where the same task is given to all users, and when the users complete the task they can mark it as completed, to do so I added a 'status' bool that is set to true when the 'task' is not complete, and with a button the user can set it to false, the problem is that when I use a many-to-many field, if one user changes the 'status', it changes for everyone.
I also tried using a Foreignkey but when I use a Foreignkey I have to create a task for every user.
What I want is to create a task, assign it to all users, and then all the users can interact with the task without affecting what other users see.
These are the models that I created(it's in spanish):
class Usuario(AbstractUser):
pass
class Tps(models.Model):
users = models.ForeignKey(Usuario, on_delete=CASCADE)
titulo = models.CharField(max_length=100)
TECNOLOGIA_DE_LA_FABRICACION = 'TDF'
MANTENIMIENTO_Y_REPARACION_DE_EQUIPOS = 'MYRDE'
MAQUINAS_ELECTRICAS_Y_ENSAYOS = 'MEYE'
SEGURIDAD_E_HIGIENE_INDUSTRIAL = 'SEHI'
LABORATORIO_DE_ENSAYOS_INDUSTRIALES = 'LDEI'
INSTALACIONES_INDUSTRIALES = 'II'
RELACIONES_HUMANAS = 'RH'
TALLER_DE_ELECTROMECANICA = 'TE'
ORGANIZACION_INDUSTRIAL = 'OI'
INSTALACIONES_ELECTRICAS = 'IE'
EDUCACION_FISICA = 'EF'
EQUIPOS_Y_APARATOS_DE_MANIOBRA_Y_TRANSPORTE = 'EYADMYT'
MATERIAS_CHOICES = [
(TECNOLOGIA_DE_LA_FABRICACION, 'Tecnologia de la fabricación'),
(MANTENIMIENTO_Y_REPARACION_DE_EQUIPOS, 'Mantenimiento y R de equipos'),
(MAQUINAS_ELECTRICAS_Y_ENSAYOS, 'Máquinas eléctricas y ensayos'),
(SEGURIDAD_E_HIGIENE_INDUSTRIAL, 'Seguridad e higiene industrial'),
(LABORATORIO_DE_ENSAYOS_INDUSTRIALES,
'Laboratorio de ensayos industriales'),
(INSTALACIONES_INDUSTRIALES, 'Instalaciones industriales'),
(RELACIONES_HUMANAS, 'Relaciones humanas'),
(TALLER_DE_ELECTROMECANICA, 'Taller de electromecánica'),
(ORGANIZACION_INDUSTRIAL, 'Organización industrial'),
(INSTALACIONES_ELECTRICAS, 'Instalaciones eléctricas'),
(EDUCACION_FISICA, 'Educacion fisica'),
(EQUIPOS_Y_APARATOS_DE_MANIOBRA_Y_TRANSPORTE,
'Equipos y aparatos de maniobra y transporte')
]
materia = models.CharField(
max_length=8, choices=MATERIAS_CHOICES, default=None)
fecha_actual = models.DateField(default=timezone.now)
fecha_entrega = models.DateField(auto_now=False, auto_now_add=False)
material = models.URLField()
consignas = models.URLField()
status = models.BooleanField(default=True)
def __str__(self):
return self.titulo
I think you should use an intermediate table and make the relationship with the through attribute, so you could make a table like this:
class Tps(models.Model):
users = models.ForeignKey(Usuario, on_delete=CASCADE, through='TaskDone')
class TaskDone(models.Model):
user = models.ForeignKey(Usuario, on_delete=models.CASCADE)
tps = models.ForeignKey(Tps, on_delete=models.CASCADE)
status = models.BooleanField(default=True)

Django Cannot assign "'Pizza'": "Order.Food_Name" must be a "Foods" instance

Hello Guys I am working on a restaurant project which allow user to select food item and book an order but i am getting this error as i try to book an order
"Django Cannot assign "'Pizza'": "Order.Food_Name" must be a "Foods" instance."
I am using drop down menu to select food items i am using django version 2.1.5 . Please Help
views.py
def place_order(request):
name = request.POST["user"]
food_items = request.POST['food_item']
qty = request.POST['qty']
rating = request.POST['ratings']
price = Foods.Food_Price
order = Order(Date=datetime.date, Name_of_Person=name,Food_Name=food_items, Qty=qty, Total=price, Ratings=rating)
order.save()
return render(request, "index.html")
model.py
from django.db import models
class Foods(models.Model):
Food_Number = models.IntegerField(null=False,)
Food_Name = models.CharField(max_length=30, primary_key=True, null=False)
Food_Qty = models.CharField(max_length=10)
Food_Price = models.IntegerField()
def __str__(self):
return f"{self.Food_Number} - {self.Food_Name} {self.Food_Price}"
class Order(models.Model):
Order_id = models.AutoField(null=False, primary_key=True)
Date = models.DateField()
Name_of_Person = models.CharField(null=False, max_length=40)
Food_Name = models.ForeignKey(Foods, on_delete=models.CASCADE)
Qty = models.CharField(max_length=10)
Total = models.IntegerField()
Ratings = models.IntegerField()
def __str__(self):
return f"{self.Order_id} - {self.Name_of_Person} |{self.Food_Name} |{self.Total}"
What can i do solve this error
Problem is in your Order model Food_Name is foreign-key field. So you need to assign model-instance which is Food in this case to this field. But you are assigning food_items = request.POST['food_item'] which is suppose to be food_name string i guess. That is why this error raise. I don't think your model is properly design. Food_Name is not an unique id field in Food model rather in your Order table you would like to have Food not Food_name.

how to apply a condition to a queryset in django

I am new to programming, I have a doubt I formed the QuerySet with table data i want to know how to apply condition to the formed queryset and get the count.
Code :
final_set = TaskMaster.objects.filter(istaskactive=True)
I want something like
no_of_rebuild_task = final_set..objects.filter(tasktype.id=1).count
model.py
class TaskMaster(models.Model):
sid = models.CharField(max_length=3)
# Remember to change the default value in processor in production
processor = models.ForeignKey(User,null=True,on_delete=models.CASCADE,default=1)
tasktype = models.ForeignKey(TaskTypeTable, null=True,on_delete=models.CASCADE)
task_title = models.TextField(null=True)
task_description = models.TextField(null=True)
datacenter = models.ForeignKey(DatacenterTable,null=True,on_delete=models.CASCADE)
priority = models.ForeignKey(PriorityTable, null=True,on_delete=models.CASCADE)
status = models.ForeignKey(StatusTable, default=1,on_delete=models.CASCADE)
pid = models.IntegerField(null=True)
sourceincident = models.CharField(max_length=250,null=True)
errorincident = models.CharField(max_length=250,null=True)
processingteam =
models.ForeignKey(TeamTable,null=True,on_delete=models.CASCADE)
createddate = models.DateField(("Date"), default=datetime.date.today)
duedate = models.DateField(("Date"), default=datetime.date.today)
istaskactive = models.BooleanField(default=True)
In Django ORM you can use count() to count the number of records in the selected table.
So for your query it can be
no_of_rebuild_task = TaskMaster.objects.filter(istaskactive=True, tasktype_id=1).count()
See effective way of Django ORM
and count() here.
no_of_rebuild_task = final_set.filter(tasktype__id=1).count()

how to select data between 2 dates using sql queries in django?

models.py
My models.py
class Custom_user_model(User):
daily_target = models.IntegerField()
monthly_target = models.IntegerField()
yearly_target = models.IntegerField()
weekly_target = models.IntegerField()
call_target = models.IntegerField()
email_target = models.IntegerField()
meeting_target = models.IntegerField()
added_under = models.IntegerField()
profile_pic = models.TextField()
doj = models.DateTimeField(default='')
location_id = models.IntegerField()
locked = models.BooleanField()
default_currency = models.IntegerField()
date_change_permission = models.BooleanField()
deal_back_log = models.BooleanField()
created_date=models.DateTimeField(auto_now_add=True)
role_id=models.IntegerField()
profile_pic = models.FileField(upload_to='.')
objects = UserManager()
//This custom_user model is the extension of django's default user model.
class Deal(models.Model):
a_choices = ((0,'yes'),(1,'no'))
approved = models.IntegerField(choices=a_choices,default=1)
user_id = models.IntegerField()
company_id = models.IntegerField()
contact_id = models.IntegerField()
deal_title=models.CharField(max_length=200)
deal_value = models.CharField(max_length=20)
currency_id = models.IntegerField()
process_id = models.IntegerField()
expected_close_date = models.DateField(default='')
closed_date = models.DateField()
deal_milestone=models.IntegerField()
created=models.DateTimeField(auto_now_add=True)
last_modified=models.DateTimeField(auto_now_add=True)
s_choices = ((0,'active'),(1,'won'),(2,'junk'),(3,'lost'))
status = models.IntegerField(choices=a_choices,default=0)
type = models.CharField(max_length=50, default='deal')
source = models.CharField(max_length=50,default='O')
class user_Roles(models.Model):
code = models.CharField(max_length=20)
description = models.CharField(max_length=30)
permitted_menus = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
Using user_roles model, I have assigned permission for accessing data to the newly created user based on his/her role. I want to get the created deals which are added by the users having role_id = 2 and deals created date between the specified dates .
### views.py
st_date, end_date = week_magic(date.today())
cur = connection.cursor()
cur.execute("select *, CONCAT(au.first_name,' ',au.last_name) as full_name from myapp_custom_user_model mu left join auth_user au on mu.user_ptr_id = au.id INNER JOIN myapp_user_roles ml on ml.id= 2 and ml.id = mu.role_id LEFT JOIN (SELECT user_id,SUM( deal_value ) AS cnt FROM myapp_deal where status = 1 and DATE_FORMAT(closed_date,'%Y-%m-%d') BETWEEN " '%s' " and " '%s' " GROUP BY user_id)d ON mu.user_ptr_id = d.user_id where mu.locked !=1 and mu.role_id = 2 order by COALESCE( d.cnt, 0 ) DESC",(st_date,end_date))
users = dictfetchall(cur)
cur.close()
While executing the query it shows unsupported format error. So I used one more % symbol in the same query as follows:
cur.execute("select *, CONCAT(au.first_name,' ',au.last_name) as full_name from myapp_custom_user_model mu left join auth_user au on mu.user_ptr_id = au.id INNER JOIN myapp_user_roles ml on ml.id= 2 and ml.id = mu.role_id LEFT JOIN (SELECT user_id,SUM( deal_value ) AS cnt FROM myapp_deal where status = 1 and DATE_FORMAT(closed_date,'%%Y-%%m-%%d') BETWEEN " '%s' " and " '%s' " GROUP BY user_id)d ON mu.user_ptr_id = d.user_id where mu.locked !=1 and mu.role_id = 2 order by COALESCE( d.cnt, 0 ) DESC" %(st_date,end_date))
It doesn't give any error but the result is empty even though there is data because of this syntax: DATE_FORMAT(closed_date,'%%Y-%%m-%%d'). How to solve this?
First of all you should use ForeignKey fields for role_id in Custom_user_model and user_id in Deal. The same is probably true for some of the other _id fields in your models.
class Custom_user_model(User):
...
role = models.ForeignKey('Role')
...
class Deal(models.Model):
...
user = models.ForeignKey('Custom_user_model')
...
After that you can do your query like this:
# get deals from users with role_id=2
query = Deal.objects.filter(user__role_id=2)
# add filter for deals created by that user created between
start_date, end_date = week_magic(date.today())
query = query.filter(created__between=(start_date, end_date))

django queryset include more columns in select statement

I been trying to create a backward relation using queryset and the joining is working fine, accept that its not including the other joined table in the selected columns. Below is my models, queryset and query.str() print
class Main(models.Model):
slug = models.SlugField()
is_active = models.BooleanField(default=True)
site = models.ForeignKey(Site)
parent = models.ForeignKey('self', blank=True, null=True, limit_choices_to={'parent' : None})
class Meta:
unique_together = (("slug", "parent"))
def __unicode__(self):
return self.slug
class MainI18n(models.Model):
main = models.ForeignKey(Main)
language = models.CharField(max_length=2, choices=settings.LANGUAGES)
title = models.CharField(max_length=100)
label = models.CharField(max_length=200, blank=True, null=True)
description = models.TextField(blank=True, null=True)
disclaimer = models.TextField(blank=True, null=True)
class Meta:
unique_together = (("language", "main"))
def __unicode__(self):
return self.title
class List(models.Model):
main = models.ForeignKey(Main)
slug = models.SlugField(unique=True)
is_active = models.BooleanField(default=True)
parent = models.ForeignKey('self', blank=True, null=True)
def __unicode__(self):
return self.slug
class ListI18n(models.Model):
list = models.ForeignKey(List)
language = models.CharField(max_length=2, choices=settings.LANGUAGES)
title = models.CharField(max_length=50)
description = models.TextField()
class Meta:
unique_together = (("language", "list"))
def __unicode__(self):
return self.title
and my queryset is
Main.objects.select_related('main', 'parent').filter(list__is_active=True, maini18n__language='en', list__listi18n__language='en')
and this is what my query is printing
'SELECT `category_main`.`id`, `category_main`.`slug`, `category_main`.`is_active`, `category_main`.`site_id`, `category_main`.`parent_id`, T5.`id`, T5.`slug`, T5.`is_active`, T5.`site_id`, T5.`parent_id` FROM `category_main` INNER JOIN `category_maini18n` ON (`category_main`.`id` = `category_maini18n`.`main_id`) INNER JOIN `category_list` ON (`category_main`.`id` = `category_list`.`main_id`) INNER JOIN `category_listi18n` ON (`category_list`.`id` = `category_listi18n`.`list_id`) LEFT OUTER JOIN `category_main` T5 ON (`category_main`.`parent_id` = T5.`id`) WHERE (`category_maini18n`.`language` = en AND `category_list`.`is_active` = True AND `category_listi18n`.`language` = en )'
anyone can help show columns from list and listi18n? I tried extra but It doesn't allow me to pass things like category_list.*
thanks
UPDATE
Thanks for Daniel approach, I managed to get it to work but instead I had to start from ListI18n
ListI18n.objects.select_related('list', 'list__main', 'list__main__parent', 'list__main__i18nmain').filter(list__is_active=True, list__main__maini18n__language='en', language='en').query.__str__()
Its working perfectly now, but I couldn't include list_main_maini18n, below is the output query
'SELECT `category_listi18n`.`id`, `category_listi18n`.`list_id`, `category_listi18n`.`language`, `category_listi18n`.`title`, `category_listi18n`.`description`, `category_list`.`id`, `category_list`.`main_id`, `category_list`.`slug`, `category_list`.`is_active`, `category_list`.`parent_id`, `category_main`.`id`, `category_main`.`slug`, `category_main`.`is_active`, `category_main`.`site_id`, `category_main`.`parent_id`, T5.`id`, T5.`slug`, T5.`is_active`, T5.`site_id`, T5.`parent_id` FROM `category_listi18n` INNER JOIN `category_list` ON (`category_listi18n`.`list_id` = `category_list`.`id`) INNER JOIN `category_main` ON (`category_list`.`main_id` = `category_main`.`id`) INNER JOIN `category_maini18n` ON (`category_main`.`id` = `category_maini18n`.`main_id`) LEFT OUTER JOIN `category_main` T5 ON (`category_main`.`parent_id` = T5.`id`) WHERE (`category_list`.`is_active` = True AND `category_listi18n`.`language` = en AND `category_maini18n`.`language` = en )'
Any idea how can I include MainI18n in the query result? should I use extra and include the tables and do the relation in the where clause? or is there a better approach?
The relationship from Main to List is a backwards ForeignKey (ie the FK is on List pointing at Main), and select_related doesn't work that way. When you think about it, this is correct: there are many Lists for each Main, so it doesn't make sense to say "give me the one List for this Main", which is what select_related is all about.
If you started from List, it would work:
List.objects.select_related('main__parent').filter(is_active=True, main__maini18n__language='en', listi18n__language='en')
because that way you're only following forwards relationships. You may find you're able to reorder your views/templates to use the query this way round.
Looks to me it is actually working (T5 in your select statement). You can always access fields from related instances in django via something like my_obj.parent.is_active. If you used select_related before they are included in the first query. If you didn't specify it in select_related a call to my_obj.parent.is_active for example would perform an extra db query.

Categories