Django Query filltering on ManyToManyField - django

I have a table which contains a list of tasks to do involving Sim cards. A task can only be done if all sims card used in the task are available at the same time
Example tasks in the table:
Task1 - IMEI1 & IMEI2
Task2 - IMEI1
If I have a list of IMEI with only IMEI1, I only want to have Task2. If I have a list with IMEI1 AND IMEI2 I want to have Task1 & Task2.
Please note I have a random number of sims in this List.
Here is my code:
class Sim(models.Model):
msisdn = models.CharField(max_length=20, blank=False, null=False)
imei = models.CharField(max_length=40, blank=False, null=False, default='IMEI')
class taskInQueue(models.Model):
simInvolved = models.ManyToManyField(Sim)
So in a taskInQueue I have one or more Sim involved in the task. In a function, I try to get all task which involve a list of sims:
sim = getSimInvolved(_imeiList) #_imeiList is a list of IMEI -> Sim is a list of SIm Objects
First I was doing the following thing:
tasks = taskInQueue.objects.filter(simInvolved__in=sim, testsStatus='W').distinct().order_by('pk')
The problem is that, with this query, I will have all tasks which involved at least one of the sims. So if I can my previous example, with _imeiList=['IMEI1'], I will get Task1 & Task2 whereas I must only get Task2.
So how can I filter taskInQueue which have all their Involved Sims in the list _imeiList?

Using chain filters?
tasks = taskInQueue.objects.all()
for sim in sims:
tasks = tasks.filter(simInvolved=sim)
# in the end tasks will only contains those tasks which required all sims

Related

Django how to perform a query to get all occourences where object 1 has a foreign key on object 2 and a certain object 2 has a property

Okay, so I've got a question about performing queries. So, I've got one object called Job. A Job as a foreign key on StatusUpdate, meaning a single job can have many StatusUpdates. Basically, I need to get all Jobs with a LAST StatusUpdate with a certain property. I know that I can easily get all Jobs that have any StatusUpdate with a certain property like this:
Job.objects.all().filter(statusupdate__status="Certain Property")
But this will get jobs that have any StatusUpdate with status of certain property. I want to get only jobs with a last StatusUpdate with a status of certain property. Is it possible to do this with a single query? I read the through the Django documentation and couldn't find anything.
Thank you!
Diego
Edit:
Let me clarify a little more exactly what I want to do. So I have a task assignment system. Each job has status updates as it progresses. When the job reaches a certain phase, say phase A, it gets a status update of "Phase A". I need to get all jobs where the status update was "Phase A". I would rather not do it with a bunch of python for loops because that's slow and inefficient. I also would prefer not to have to do it in raw SQL.
Edit 2:
Here some of my code is:
Job:
class Job(models.Model):
jobtype = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published', default=timezone.now)
Job Status:
class JobStatus(models.Model):
creation_time = models.DateTimeField('creation time', default=timezone.now)
status = models.CharField(max_length=200)
job = models.ForeignKey(Job, on_delete=models.CASCADE)
A job can have any number of JobStatuses. So I don't know the index of the last JobStatus, and I need to get all jobs with a certain last JobStatus.

Django Query - Get list that isnt in FK of another model

I am working on a django web app that manages payroll based on reports completed, and then payroll generated. 3 models as follows. (ive tried to limit to data needed for question).
class PayRecord(models.Model):
rate = models.FloatField()
user = models.ForeignKey(User)
class Payroll(models.Model):
company = models.ForeignKey(Company)
name = models.CharField()
class PayrollItem(models.Model):
payroll = models.ForeignKey(Payroll)
record = models.OneToOneField(PayRecord, unique=True)
What is the most efficient way to get all the PayRecords that aren't also in PayrollItem. So i can select them to create a payroll item.
There are 100k records, and my initial attempt takes minutes. Attempt tried below (this is far from feasible).
records_completed_in_payrolls = [
p.report.id for p in PayrollItem.objects.select_related(
'record',
'payroll'
)
]
Because you have the related field record in PayrollItem you can reach into that model while you filter PayRecord. Using the __isnull should give you what you want.
PayRecord.objects.filter(payrollitem__isnull=True)
Translates to a sql statement like:
SELECT payroll_payrecord.id,
payroll_payrecord.rate,
payroll_payrecord.user_id
FROM payroll_payrecord
LEFT OUTER JOIN payroll_payrollitem
ON payroll_payrecord.id = payroll_payrollitem.record_id
WHERE payroll_payrollitem.id IS NULL
Depending on your intentions, you may want to chain on a .select_related (https://docs.djangoproject.com/en/3.1/ref/models/querysets/#select-related)
PayRecord.objects.filter(payrollitem__isnull=True).select_related('user')
which translates to something like:
SELECT payroll_payrecord.id,
payroll_payrecord.rate,
payroll_payrecord.user_id,
payroll_user.id,
payroll_user.name
FROM payroll_payrecord
LEFT OUTER JOIN payroll_payrollitem
ON (payroll_payrecord.id = payroll_payrollitem.record_id)
INNER JOIN payroll_user
ON (payroll_payrecord.user_id = payroll_user.id)
WHERE payroll_payrollitem.id IS NULL

djanjo get values from related models

I have 2 models-
class POWStage(Content):
time_slot = models.OneToOneField(
TaskTime,
on_delete=models.CASCADE,
help_text='Link to time slot describing the stage timescale',
verbose_name='Time slot link',
null=True,
blank=True
class TaskTime(Content):
schedule_finish = models.DateTimeField(
help_text='Scheduled finish date',
verbose_name='Scheduled finish',
blank=True,
null=True,
I would like to get the latest end date for a list of POwStages.... e.g. If I have 8 POWStages will have 8 corresponding schedule finish dates.
I have tried the following with no success:
pow_stage_list = POWStage.objects.get_stage_by_pow(pow_detail)
task_time_list = TaskTime.objects.get_task_time_by_id(getattr(pow_stage_list,'time_slot'))
and also:
time_list = []
time_slot=[]
time_finish[]
for time_slot in pow_stage_list:
time_list.append(time_slot)
for entry in time_list:
time_entry.append(entry.id)
for finish_date in time_entry:
time_finish.append(TaskTime.objects.get_task_time_by_id(finish_date))
to try and at least get the values of the finish dates in order to process them further (neither of which are working)
Im thinking of getting the
POWStages - using a filter - no problems
2)FOr each of the POWStages - loop through them to get the id of TaskTime
I can do this ok -ish ( I manage to get the id which is returned as
UUID() object. which I
cannot then pass to get the TaskTime
For each of the TaskTime get the value of schedule finish
Iterate through the values to find the latest finish date.
Im thinking there must be a simpler way that I'm missing or at least something that works!!!
2 mins after posting - I managed to work it out:
pow_stage_list = POWStage.objects.get_stage_by_pow(pow_detail)
time_list = TaskTime.objects.filter(powstage__in=pow_stage_list, schedule_finish__isnull=False).latest('schedule_finish')

Django - creating and saving multiple object in a loop, with ForeignKeys

I am having trouble creating and saving objects in Django. I am very new to Django so I'm sure I'm missing something very obvious!
I am building a price comparison app, and I have a Search model:
Search - all searches carried out, recording best price, worst price, product searched for, time of search etc. I have successfully managed to save these searches to a DB and am happy with this model.
The two new models I am working with are:
Result - this is intended to record all search results returned, for each search carried out. I.e. Seller 1 £100, Seller 2 £200, Seller 3, £300. (One search has many search results).
'Agent' - a simple table of Agents that I compare prices at. (One Agent can have many search Results).
class Agent(models.Model):
agent_id = models.AutoField(primary_key=True)
agent_name = models.CharField(max_length=30)
class Result(models.Model):
search_id = models.ForeignKey(Search, on_delete=models.CASCADE) # Foreign Key of Search table
agent_id = models.ForeignKey(Agent, on_delete=models.CASCADE) # Foreign Key of Agent table
price = models.FloatField()
search_position = models.IntegerField().
My code that is creating and saving the objects is here:
def update_search_table(listed, product):
if len(listed) > 0:
search = Search(product=product,
no_of_agents=len(listed),
valid_search=1,
best_price=listed[0]['cost'],
worst_price=listed[-1]['cost'])
search.save()
for i in range(len(listed)):
agent = Agent.objects.get(agent_name = listed[i]['company'])
# print(agent.agent_id) # Prints expected value
# print(search.search_id) # Prints expected value
# print(listed[i]['cost']) # Prints expected value
# print(i + 1) # Prints expected value
result = Result(search_id = search,
agent_id = agent,
price = listed[i]['cost'],
position = i + 1)
search.result_set.add(result)
agent.result_set.add(result)
result.save()
Up to search.save() is working as expected.
The first line of the for loop is also correctly retrieving the relevant Agent.
The rest of it is going wrong (i.e. not saving any Result objects to the Result table). What I want to achieve is, if there are 10 different agent results returned, create 10 Result objects and save each one. Link each of those 10 objects to the Search that triggered the results, and link each of those 10 objects to the relevant Agent.
Have tried quite a few iterations but not sure where I'm going wrong.
Thanks

Django SUM from INNER JOIN

I have a DB like this:
class MyCPU(models.Model):
cpu_name = models.CharField(max_length=100)
cpu_count = models.IntegerField()
class MyMachine(models.Model):
hostname = models.CharField(max_length=50)
ip = models.CharField(max_length=50)
cpu = models.ForeignKey(CPU, on_delete=models.CASCADE)
How can I achieve the result of following raw SQL command in Django ?
select sum(cpu_count) as sum_cpu from my_machine inner join my_cpu on my_machine.cpu_id=my_cpu.id
I basically want to sum how many CPU in all of machines.
I have tried this solution but it did not work
Machine.objects.annotate(total_cpu=Sum('cpu__cpu_count'))
Since you are using foreign key, You can do
MyMachine.objects.values('hostname', 'ip', 'cpu__cpu_count')
This will get each Machine how many cpu`s.
If you need total number of cpu`s
MyCPU.objects.aggregate(total_cpu=Sum('cpu_count'))['total_cpu']
If there are unconnected CPU objects, you can do following to get sum from all machines,
MyMachine.objects.aggregate(total_cpu=Sum('cpu__cpu_count'))['total_cpu']
I think the last one is you are searching for since there is chance of same CPU object in different machines.