Change query in Django based on day of week - python

First of all thank you for looking at my question.
I am looking for a way to store the day of week in a model, I have established that having a boolean for each day of the week in the model is likely the most simple approach. I had looked at using bitflags but was unsure again how to query this.
My model looks like the following
class CallForwardingRule(models.Model):
forward_to = models.CharField(max_length=255,null=False,blank=False)
start_time = models.TimeField(default=time(0,0))
end_time = models.TimeField(default=time(0,0))
active = models.BooleanField(default=True)
monday = models.BooleanField(default=False)
tuesday = models.BooleanField(default=False)
wednesday = models.BooleanField(default=False)
thursday = models.BooleanField(default=False)
friday = models.BooleanField(default=False)
saturday = models.BooleanField(default=False)
sunday = models.BooleanField(default=False)
My query is then like the following
CallForwardingRule.objects.filter(start_time__lte=time,end_time__gte=time)
What I need to do is alter the query depending on the current day, if the day is monday the query should look for a rule where boolean value monday=True
I hope I have been clear in my question, I am quite new to Django and Python.
Kind Regards

You can use a custom manager. Say
class TodayManager(models.Manager):
def get_queryset(self, *args, **kwargs):
today = self.weekday_as_string()
return super(TodayManager, self).get_queryset(*args, **kwargs).filter(
**{today: true})
def weekday_as_string(self):
# TODO
class CallForwardingRule(models.Model):
# your fields
of_today = TodayManager()
And query like this:
CallForwardingRule.of_today.filter(
start_time__lte=time,end_time__gte=time)
Read more about object managers here https://docs.djangoproject.com/en/1.8/topics/db/managers/
NOTE: If you don't intend for the user to be able to mix days in the same model instance, you should use an integer field with choices instead, as suggested in the comments.

You should either use an integer or a charfield for your dayofweek. Each of them may be used with choices (https://docs.djangoproject.com/en/1.8/ref/models/fields/#choices) which allows you to make it easier to translate the code of the day to its name.
Then, you just have to filter your queryset with this field.

Related

django in one queryset all and filter methods

I trying display in django app, in view last 5 item and also this items which has is_home set on True.
Please hint if this is 'nice' and correct way:
My model:
class Event(models.Model):
title = models.CharField(max_length=500)
date = models.DateField()
is_home = models.BooleanField(default=False)
My query in view:
context['event_list'] = Event.objects.filter(Q(Event.objects.all()) | Event.objects.filter(is_home=True))[:5]
context['event_list'] = Event.objects.filter(is_home=True).order_by(-id)[:5]
Simply use:
list(Event.objects.all().order_by('-id')[:5]) + list(Event.objects.filter(is_home=True))
Unfortunately, you cannot (as far as I can tell) combine queries after taking a slice, so conversion to lists is necessary.
If you really really want to have a QuerySet you can do:
Event.objects.filter(Q(id__in=Event.objects.all().order_by('-id')[:5].values_list('id', flat=True)) | Q(is_home=True))
Which is extremely ugly.

Django model history by date and datetime

Assume I have model like this:
class Account(models.Model):
balance = models.IntegerField()
debt = models.IntegerField()
history = HistoricalRecords()
I'm using django-simple-history to get instance of the model as it would have existed at the provided date and time:
inst = Account.history.as_of(datetime.datetime.now().date)
It's working fine, but I want to get instance where balance field is represented as it would have existed at the provided date and time, and then debt field will be most recent of that date. I don't know if this is possible, didn't find anything about that.
The history ORM will return back a model based off of the one you submitted, as it existed at that point in time.
account = Account.objects.create(balance=1, debt=1)
account.save()
history_obj = account.history.last()
print(history_obj.debt) # returns 1
account.debt = 222
account.save()
new_history_obj = account.history.last()
print(new_history_obj.debt) # returns 222
Assuming you're using the Account.history.as_of() method to return the history object that you intend to be reading from, you could do this:
yesterday = datetime.datetime.now() - datetime.timedelta(days=1)
history_obj = Account.history.as_of(yesterday)
print(history_obj.debt) # returns not the current debt, but the debt as-of yesterday
Unless I'm misunderstanding what you're hoping to accomplish, you could just do this with what you have in your question:
inst = Account.history.as_of(datetime.datetime.now().date)
print(inst.debt)

comparing the datefield to today and changing the integerfield automatically every day

I'm making a website using django.
class Member(models.Model):
...
end_date = models.DateField(blank=True, default=(datetime.now() + timedelta(days=30)))
Membership_status = models.IntegerField(blank=True, null=True, default=1) # 1 = active, 0=deactivate, 2=refund
What I want to do is comparing the end_date field to today.date every 1.a.m. and if today's day < end_date, Membership_status field is changed to 0 automatically.
I heard I should use django-kronos(https://github.com/jgorset/django-kronos).
But I can't understand the using method.
Is there anyone can tell me details how I implement what I want?
Any help will be very helpful to me, thanks!
First of all, this is not an answer to your original query, but merely a suggestion for your future,
Never pass a function call into your field defaults. If you did, the function would be evaluated at the time of your migrations. If you look into the migration files you can see for sure. Instead wrap it in a function and pass that as a callable.
Eg:
from django.utils import timezone
def TODAY():
return timezone.now().date()
def NEXT_MONTH_DAY():
return TODAY() + timedelta(days=30)
Now, in your models,
class Member(models.Model):
...
end_date = models.DateField(blank=True, default=NEXT_MONTH_DAY)
This way the function NEXT_MONTH_DAY is called whenever an instance of Member is created.
EDIT:
For your original query, I haven't tested the code, but I suppose you are looking for maybe something like this,
import kronos
#kronos.register('0 1 * * *')
def the_task():
for member in Member.objects.all():
if TODAY() == member.end_date:
member.Membership_status = 0
member.save()

Array of foreign keys in Django Model

I'm not sure this is the best title, but I'm having trouble phrasing it simply. Basically, I'm creating a model that represents a business. This includes and address, operating hours, etc. It's the operating hours that are tripping me up. I have my address
class Address(models.Model):
--snip--
Business = models.ForeignKey(BusinessInfo)
So each business has one or more location addresses. I'm looking to do similar with Hours
class HoursOnDay(models.Model):
open = isOpen = models.BooleanField()
open = models.TimeField(null=True)
closed = models.TimeField(null=True)
What I want to enforce is that each business has to have an array of 7 HoursOnDay - one for each day of the week. I can't seem to stumble on the obvious, elegant way to do this. Is there a good way to model this in django?
use ManyToManyField:
class HoursOnDay(models.Model):
is_open = models.BooleanField()
open = models.TimeField(null=True)
closed = models.TimeField(null=True)
class Day(models.Model):
hours = models.ManyToManyField(HoursOnDay)
class Business(models.Model):
days = models.ManyToManyField(Day)
if you want to have limit for 7hours and 7days you can check
Limit number of model instances to be created
I have come across a similar problem (needed a bunch of fields for every hour of the day) and reached the following conclusion:
The most djangoish way to do this, is to not try and do anything smart. If you need a bunch of fields seven times, just copy paste the fields and give them different postfix or prefix. E.g.:
class Business(models.Model):
--snip--
monday_is_open = models.BooleanField()
monday_opens_at = models.TimeField(null=True)
monday_closes_at = models.TimeField(null=True)
tuesday_is_open = models.BooleanField()
tuesday_opens_at = models.TimeField(null=True)
tuesday_closes_at = models.TimeField(null=True)
wednesday_is_open = models.BooleanField()
wednesday_opens_at = models.TimeField(null=True)
wednesday_closes_at = models.TimeField(null=True)
...
sunday_is_open = models.BooleanField()
sunday_opens_at = models.TimeField(null=True)
sunday_closes_at = models.TimeField(null=True)
Of course Americans (and others?) would start with sunday, but you get the idea.
Following this approach greatly simplifies updating opening hours. This approach (and what you requested) fail to model changing opening hours from week to week, but that is probably not your need either.
Also, if you are concerned with schema normalization, get rid of the is_open, and just use xxx_opens_at__isnull=True, xxx_closes_at__isnull=True where you would have used xxx_is_open=True.
You can still do smart stuff with iteration across the weekdays in Business.clean().

Django-date incrementation in a list with ManyToManyField

New to django/programming, any help is greatly appreciated. I need help moving through a history of doctor appointments and selecting what immunizations were performed at each appointment, then creating a date when the immunization is due in the future (based on an immunization information table, which has the proper interval of immunizations and will increment from the visit date)
models.py
class Immunizations(models.Model):
immunization = models.CharField(max_length=100, null=True)
interval = models.CharField(max_length=5, null=True)**This should probably be an integer field, will change later
class Visit(models.Model):
patient = models.ForeignKey(Patients)
date_of_visit = models.DateField(null=True)
weight = models.CharField(max_length=5, null=True)
immunization = models.ManyToManyField(Immunizations)
timestamp = models.DateTimeField(auto_now_add=True, default=datetime.datetime.now())
active = models.BooleanField(default=True)
I have been reading the documentation and questions on SO all weekend, but am still very conflicted about what way to go through this.
What I want is:
Visit.date_of_visit1
Visit.immunization1, Visit.date_of_visit1 + Immunization.interval1
Visit.immunization2, Visit.date_of_visit1 + Immunization.interval2
Visit.date_of_visit2
Visit.immunization1, Visit.date_of_visit2 + Immunization.interval1
ETC
This could go on for years with each visit having different immunizations performed. I want to maintain a record of which immunization was performed and record the due date, even if that due date has passed.
views.py
def visit_profile(request, slug):
patient = Patients.objects.get(slug=slug)
try:
visit = Visit.objects.filter(patient_id=patient.id)
except:
return HttpResponseRedirect('/')
#Immunization Due Dates
visitdate = Visit.objects.get(patient_id=patient.id, active=1).date_of_visit
imm = Immunizations.objects.all()
visitimm = []
for immunization in imm:
due = Immunizations.objects.get(id= immunization.pk)
duedate = visitdate + timedelta(days=int(due.interval))
visitimm.append((due, duedate))
return render_to_response('patient.html',locals(), context_instance=RequestContext(request))
Need help with my views.py. The above works, but only at showing the active=1 visit information. I can't figure out how to modify/re-do to achieve what I want and be able to access the data in my template file. I've experimented with __in method, itertools, looping, etc. Can anyone provide the proper method/direction for doing this? I will go back and properly setup error catching once I can get the code to work. Thanks!
Yep, make interval an IntegerField or maybe rather a PositiveSmallIntegerField since it will never get a negative value nor a very huge number.
Careful, better don't mix plural and singular in model names, they affect the related names when you traverse your foreign keys which makes it a pain to debug, see here. I prefer to use only singulars.
Instead of:
visit = Visit.objects.filter(patient_id=patient.id)
You can simply type:
visit = Visit.objects.filter(patient=patient)
Try something like this
def visit_profile(request, slug):
patient = Patients.objects.get(slug=slug)
visitimm = []
# Looping over all active visit records of the patient in date order
for v in patient.visit_set
.filter(active=True).order_by('date_of_visit'):
# Looping over each visit's immunizations
for i in v.immunizations_set.all():
duedate = v.date_of_visit + timedelta(days=int(i.interval))
visitimm.append((i, duedate))
...

Categories

Resources