DISTINCT Django Query - django

I want to use distinct() in Django but want to return the QuerySet not ValueSet.
Since I want to distinct on a particular column and get all the other columns as well, I cannot use a ValueSet.
Currently I'm using:-
daily_count = ShipmentSubSortScanMapping.objects.all().values('shipment_id').distinct()
This return only shipment_id, but I want all the fields.
Here's my model:-
class ShipmentSubSortScanMapping(models.Model):
received_arm_id = models.CharField(max_length = 255)
actual_arm_id = models.CharField(max_length = 255, default = 'None')
shipment_id = models.ForeignKey('Shipment',related_name ='subsortscans')
time = models.DateTimeField( auto_now_add = True)

distinct accepts an argument of what fields to operate on, so probably you want:
daily_count = ShipmentSubSortScanMapping.objects.all().distinct('shipment_id')

Related

Value Error:Cannot assign queryset to attribute it must be instance

I have models.py
class employees(models.Model):
emp_id=models.PositiveIntegerField()
emp_name = models.CharField(max_length = 100)
emp_lname = models.CharField(max_length = 100)
emp_loc=models.CharField(max_length=5,choices=LOCATION)
manager_id=models.ForeignKey('self',null=True,blank=True)
class leave(models.Model):
employee = models.ForeignKey(employees, on_delete=models.CASCADE, default='1')
start_date = models.DateField()
end_date = models.DateField()
status=models.CharField(max_length=1,choices=LEAVE_STATUS,default='P')
ltype=models.CharField(max_length=2,choices=LEAVE_TYPE)
message=models.CharField(max_length=500,blank=True)
class notify(models.Model):
sender_id=models.ForeignKey(leave, related_name='%(class)s_sendername')
receiver_id=models.ForeignKey(leave,related_name='%(class)s_receivername')
date_time=models.DateTimeField()
I have views.py
def accept(request):
approved_emp_id=leave.objects.filter(id=accept_id);
approving_emp_id=leave.objects.filter(employee__emp_id=request.user.username);
accept_notify=notify(sender_id=approving_emp_id, receiver_id=approved_emp_id,date_time=datetime.datetime.now(),viewed='N');
accept_notify.save()
When I want to save values to database I am getting error as ValueError: Cannot assign "<QuerySet [<leave: 121-geeta-2017-10-04-2017-10-06-C-V-2017-09-27 07:48:36.288873+00:00>]>": "notify.sender_id" must be a "leave" instance.
Where am I going wrong approving_emp_id and approved_emp_id are both leave instance only.
You are passing a QuerySet when the arguments should be an instance. A QuerySet is a list of instances. Pass only one instance. Use leave.objects.get() instead of leave.objects.filter().
objects.get() returns a single instance where objects.filter() returns a QuerySet.
def accept(request):
approved_emp_id = leave.objects.get(id = accept_id)
approving_emp_id = leave.objects.get(employee__emp_id = request.user.username)
accept_notify = notify(sender_id = approving_emp_id, receiver_id = approved_emp_id, date_time = datetime.datetime.now(), viewed = 'N')
accept_notify.save()
Another way is slicing the QuerySet.
def accept(request):
approved_emp_id = leave.objects.filter(id = accept_id)[0]
approving_emp_id = leave.objects.filter(employee__emp_id = request.user.username)[0]
accept_notify = notify(sender_id = approving_emp_id, receiver_id = approved_emp_id, date_time = datetime.datetime.now(), viewed = 'N')
accept_notify.save()

How would I properly write this query in django?

both team_signup and signedup have foreign keys from comp_name. I'm trying to list them all in one list so that I have the list of individuals that signed up as well as the teams. I'm thinking maybe some kind of join?
View:
session = request.session._session_key
cart = comp_name.objects.filter(Q team_signup__sessionid = session | Q signedup__sessionid = session)
template:
{{cart}}
models:
#for individual sign ups
class signedup(models.Model):
comp_name = models.ForeignKey(comp_name)
sessionid = models.CharField(max_length = 60, blank=True)
price = models.FloatField(max_length = 7, blank=True)
#dancer information
dancer_1_fname = models.CharField(max_length = 30)
dancer_1_lname = models.CharField(max_length = 30)
dancer_1_email = models.CharField(max_length = 30)
#for team sign ups
class team_signup(models.Model):
comp_name = models.ForeignKey(comp_name)
sessionid = models.CharField(max_length = 60, blank=True)
price = models.FloatField(max_length = 7, blank=True)
#dancer information
team_name = models.CharField(max_length = 30)
team_count = models.CharField(max_length = 30)
team_email = models.CharField(max_length = 30)
I'm probably not using the Q right but I don't quite get it, thanks
Use chain from itertools,
so first
from itertools import chain in the top of your views
Then create the queries that you want to combine
finally, call
somename = list(chain(query1, query2))
Then in you template, just treat it like you would any other queryset
Use backward relationship:
https://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward
Then You can call Your related fields like
comp = comp_name.objects.get(id=1)
comp.signedup_set.all()
comp.team_signup_set.all()

Django ORM JOIN query

I've 2 models
class ShipmentBagSealMapping(models.Model):
bag_seal = models.CharField(max_length = 255)
status = models.CharField(max_length = 255, default = 'open')
time = models.DateTimeField( auto_now_add = True, db_index = True)
shipment_id = models.ForeignKey('Shipment', related_name = 'bags')
class Shipment(models.Model):
job_id = models.CharField(max_length = 255)
time = models.DateTimeField( auto_now_add = True, db_index = True)
I want to write a JOIN query which tells me the count of records in ShipmentBagSealMapping with status = close and time of Shipment is in range [start_time and end_time].
Here' what I tried:
total_bags = ShipmentBagSealMapping.objects.filter(shipments__time__range = [start_time,end_time],status='close').values('bag_seal').distinct().count()
But it throws an error saying :-
Cannot resolve keyword 'shipments' into field. Choices are: bag_seal, id, shipment_id, status, time
How do I do it?
This should do it:
total_bags = ShipmentBagSealMapping.objects.filter(shipment_id__time__range = [start_time,end_time],status='close').values('bag_seal').distinct().count()
See you have defined the field as shipment_id not shipments
Django will automatically add _id in your ForeignKey, so make some change like this may help
class ShipmentBagSealMapping(model.Model):
bag_seal = models.CharField(max_length = 255)
status = models.CharField(max_length = 255 )
time = models.DateTimeField( auto_now_add = True)
shipments = models.ForeignKey('Shipment', related_name = 'bags')

Back Referencing Django models

I've 3 models.
class ShipmentWeightMapping(models.Model):
id = models.IntegerField(primary_key = True)
weight = models.CharField(max_length = 255)
status = models.CharField(max_length = 255)
time = models.DateTimeField(auto_now = True, auto_now_add = True)
shipment_id = models.ForeignKey('Shipment')
class ShipmentDimensionMapping(models.Model):
id = models.IntegerField(primary_key = True)
status = models.CharField(max_length = 255)
time = models.DateTimeField(auto_now = True, auto_now_add = True)
length = models.IntegerField()
breadth = models.IntegerField()
height = models.IntegerField()
shipment_id = models.ForeignKey('Shipment')
class Shipment(models.Model):
id = models.IntegerField(primary_key = True)
job_id = models.CharField(max_length = 255)
weights = models.ForeignKey('ShipmentWeightMapping')#backref
dimensions = models.ForeignKey('ShipmentDimensionMapping')#backref
time = models.DateTimeField(auto_now = True, auto_now_add = True, db_index = True)
I want to backref weights and dimensions to their respective classes, so that when I query Shipment model for id=1, I should get length, breadth and height from ShipmentDimensionMapping and weight from ShipmentWeightMapping without querying ShipmentDimensionMapping and ShipmentWeightMapping separately.
For eg:- Currently I do like this.
To get Shipment Details for id = 1, I do the following.
dimension_obj = ShipmentDimensionMapping.objects.filter(shipment_id = 1)[0]
length = dimension_obj.length
#similarly for other details in ShipmentDimensionMapping
weight_obj = ShipmentWeightMapping.objects.filter(shipment_id = 1)[0]
weight = weight_obj.weight
#similarly for other details in ShipmentWeightMapping
shipment_obj = Shipment.objects.filter(shipment_id = 1)[0]
job_id = shipment_obj.job_id
#similarly for other details in Shipment
Is there any way in which I only query shipment_obj and I get details of ShipmentWeightMapping and ShipmentDimensionMapping?
Also, I always use the result at zeroth index [0] to get the result. Although the result returned always contains only 1 item, still I need to do [0]. How can I avoid this as well?
Since weight and dimension data are on other tables, you can't get them without querying these two tables.
For the second question, if you know there's only one entry, you can do:
shipment_obj = Shipment.objects.get(id=1)
BTW; you don't have to add ID values explicitly since they are called id in your code as well which is by default in Django.

Ordering on a field in the 'through' Model of recursive ManyToMany relation in Django

Assuming the following model:
class Category(models.Model):
related = models.ManyToManyField('self', symmetrical = False, through = 'CategoryRelation', null = True, blank = True)
Assuming the following intermediate 'through' relation:
class CategoryRelation(models.Model):
source = models.ForeignKey('Category', null = False, blank = False, verbose_name = _('source'), related_name = 'relation_source')
target = models.ForeignKey('Category', null = False, blank = False, verbose_name = _('target'), related_name = 'relation_target')
order = models.PositiveIntegerField(_('order'), null = False, blank = True, default = 0)
class Meta:
ordering = ( 'order', )
How can I obtain the Category objects related to a given Category while preserving the ordering? The following code will produce the correct Category objects, not in the correct order, and include duplicate entries in the Query Set even when using .distinct():
relations = CategoryRelation.objects.filter(source = self)
Category.objects.filter(relation_target__in = relations).order_by('related')
The following works for ordering correctly, but does not leave out duplicate entries:
relations = CategoryRelation.objects.filter(source = self)
Category.objects.filter(relation_target__in = relations).order_by('relation_target')
Calling .distinct() will not make a difference, because the .order_by() logic is applied afterwards. However, it is possible - in this case - to exploit the fact that the order is a positive integer field, and annotate each Category with the Min value of the order field of the relation_target field, and use this new annotation field for ordering:
return Category.objects.filter(relation_target__in = relations).annotate(relation_target_order = models.Min('relation_target__order')).order_by('relation_target_order')
This is almost complete, but since the semantics of this query essentially make it unique, it would be wise to call .distinct() just to make sure the distinct flag is True so that later combination with other distinct queries can take place:
return Category.objects.filter(relation_target__in = relations).annotate(relation_target_order = models.Min('relation_target__order')).order_by('relation_target_order').distinct()
In this case .distinct() does not affect the query in the slightest, but ensures that db/models/sql/query.py method combine(self, rhs, connector) passes its assertion:
assert self.distinct == rhs.distinct, \ ...