djanjo get values from related models - django

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')

Related

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

How to sum two columns in query on Django

I have the following model on my postgresql database:
class UrlXML(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, editable=False, db_index=True)
url = models.TextField()
is_active = models.BooleanField(default=True, db_index=True)
run_last_time = models.DateTimeField(blank=True, null=True)
run_frequency = models.IntegerField(default=24)
Every hour I need to get from database url that need to be downloaded based when on my current time and if the last time it ran was higher then the frequency.
I manage to create the raw query, but I can't manage to create it in Django Queryset.
Here is the following query:
select (run_last_time + INTERVAL '1 hours' * run_frequency), run_frequency, NOW(), run_last_time from urlxml where is_active=True and (run_last_time + INTERVAL '1 hours' * run_frequency) <= NOW();
Example:
Current time is 2017-04-03 11:00:00
I have two url in database:
Url A: Ran last time 2017-04-03 08:00:00 and its frequency is 6 hours
Url B: Ran last time 2017-04-02 11:00:00 and its frequency is 24 hours
When I execute the function at 2017-04-03 11:00:00 (within the margin of + and - 30 minutes), it must bring me the Url B only, 'cause the last time it ran was 24 hours ago.
I managed to find a solution using the extra in the Queryset.
Here it is:
UrlXML.objects.filter(is_active=True).extra(
where={"run_last_time + INTERVAL '1 hours' * run_frequency <= NOW()"}
)
I don't know if this is the best way to do this, but is the only one I manage to find.
If there are better ways to do it, I'm open to suggestions.
If you were to change your model slightly, you could use Query Expressions.
# models.py
class UrlXML(models.Model):
...
run_frequency = models.DurationField(default=timedelta(hours=24))
UrlXML.objects \
.annotate(expires=ExpressionWrapper(
F('run_last_time') + F('run_frequency'),
output_field=DateTimeField())) \
.filter(expires__lte=datetime.now())
This solutions is also a bit more robust, as you can use datetime.timedelta instead of hours only.

Can i update in many to many field django

I want to update manytomany field, the others answers say than first remove and later add, but I need to know if is possible only update, may model:
class CtlgTypeExercise(models.Model):
type_exercise = models.CharField(max_length=50)
class CtlgExercise(models.Model):
exercise = models.CharField(max_length=250)
time = models.IntegerField()
ctlg_type_exercise = models.ForeignKey('CtlgTypeExercise')
class UsrExercisePlan(models.Model):
user = models.ManyToManyField(User)
date = models.DateField()
ctlg_exercise = models.ManyToManyField('CtlgExercise')
In CtlgTypeExercise has: Run, Swim, Bicycle .....
In CtlgExercise has: "Run 20 minutes in the street" and type is "Run", or "Run 10 minutes in the mountain", type "Run", or "Swim 30 minutes" type "Swim".....
In UsrExercisePlan save the user and exercise, for example user:"Peter", date:"Today", ctlg_exercise:"Run 20 minutes in the street" well the id. Now I want to replace or update ctlg_exercise per "Swim 30 minutes".
What is the best way to update, I dont want to remove and add, Thanks.
Ok, if you write:
usrExe = UsrExercisePlan.objects.get(user__id=idUser)
usrExe.ctlg_exercise = [newExercise]
automatically remove and add new Object, but I don't know with the id field, because it is increasing. Somebody know what happen with Django and longs id fields autoincrement, maybe django reset id field?

Django Query filltering on ManyToManyField

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

Date range headache

#model
class Promotion(models.Model):
name = models.CharField(max_length=200)
start_date = models.DateTimeField()
end_date = models.DateTimeField()
#view
def promo_search(request):
...
results = Promotion.objects.filter(start_date__gte=start_date).filter(end_date__lte=end_date)
...
(The code above obviously isn't going to work I'm just using it to
help illustrate my problem.)
I want to show all active promotions between the start date and end
date.
So if a promotion starts on 01/01/09 and ends 30/01/09 and a person
searches from 01/12/08 to 01/02/09 it will still return a result. Also
if they search from inside the date range e.g. 02/01/09 - 03/01/09
they would get the same result.
Is there some magical django way of achieving this without looping
over each day?
You have four dates to consider: start_search, end_search, start_promo and end_promo. You are looking for promotions where start_promo <= end_search and end_promo >= start_search:
results = Promotion.objects.\
filter(start_date__lte=end_date).\
filter(end_date__gte=start_date)