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

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

Related

Django: Get a list of all related objects in models.py

it's a stupid question but i'm new to django and I didn't find a answer so far.
I'm trying to get a list of all related Years in the get_savings function.
Don't look at the attributes of Year and Plan. They all exist.
The focus is on the For loop. I also tried for year in self.year_set.all: but it didn't work either.
models.py
class Plan(models.Model):
title = models.CharField(max_length=50)
...
#property
def get_saving(self):
delta: timedelta = now() - self.date_created
months_gone = delta.days / 30
saving = 0
for year in Year.objects.all():
if months_gone > year.months:
saving = saving + year.savings_year
else:
saving = saving + months_gone * year.income_month
return saving
class Year(models.Model):
title = models.IntegerField()
plan = models.ForeignKey(Plan, on_delete=models.CASCADE)
self.year_set.all() is what you need.
all is a function so you need to call it rather than just reference it.

Django view objects filter with timezone.now().date or timezone.now().time-> expected string or bytes-like object

Hi i have some Django 11 project, my model look like
class Event(models.Model):
name = models.CharField(max_length=100, unique=True)
title = models.CharField(max_length=100)
info = models.CharField(max_length=100)
image = models.ImageField(upload_to='events/%Y/%m/%d')
start_date = models.DateField(default=timezone.now)
start_time = models.TimeField(default=timezone.now)
stop_date = models.DateField(default=timezone.now)
stop_time = models.TimeField(default=timezone.now)
place = models.ForeignKey('places.Place', on_delete=models.CASCADE)
company = models.ForeignKey('companies.Company', on_delete=models.CASCADE)
and my view look like
def place_website(request, place_id):
place_template = get_template('room.html')
place_obj = Place.objects.filter(id=place_id)
# filter for event obejts only for requested place, filtered for now and next events
place_event_now = Event.objects.filter(place=place_id, start_date=timezone.now().date, stop_date__gte=timezone.now().date)
place_events_next = Event.objects.filter(place=place_id, start_date=timezone.now(), stop_date__gte=timezone.now()).order_by('start_time')
place_context = {
'place_obj': place_obj,
'place_event_now': place_event_now,
'place_events_next': place_events_next,
}
return HttpResponse(place_template.render(place_context))
the thing i want to manage is to pass to template the list of filtered Event objects based on time.
Lets pick this line
place_event_now = Event.objects.filter(place=place_id, start_date=timezone.now().date, stop_date__gte=timezone.now().date)
it couse error "expected string or bytes-like object" but when i remove ".date" from "timezone.now()" error disappear (then filter do nothing) but i want to compare date to date and time to time.
How to do this properly ?
This approach to filter objects in view rather than in template is proper?
###### UPDATE ########
Its werid because after correction now i have no error but queryset is not filtered properly, look like only two first parameter is filtering ok and the another two is causing empty queryset.
place_event_now = Event.objects.filter(place=place_id, start_date=timezone.now().strftime('%Y-%m-%d'), start_time__lte=timezone.now().strftime('%H:%M:%S'), stop_time__gte=timezone.now().strftime('%H:%M:%S'))
I my database time is saved in format H:M:S and timezone.now().time() has different format so i modified filter with .strftime this didnt help, what i wont is to limit "place_event_now" queryset to particular object/objects that come true with condition start_time < currenttime < stop_time.
Another case is with place_event_next
place_events_next = Event.objects.filter(place=place_id, start_date=timezone.now().strftime('%Y-%m-%d'), stop_date__gte=timezone.now().strftime('%Y-%m-%d'), start_time__gt=timezone.now().strftime('%H:%M:%S')).order_by('start_time')
Event when i filter objects that start_time is greater than timezone.now() they still are in queryset.
Am I doing something wrong ?
I figured it out that timezone.now() return time not in my current timezone, i change it to timezone.localtime() and everything working perfect !!!
May be you need call date to date()
replace
filter(place=place_id, start_date=timezone.now().date, stop_date__gte=timezone.now().date)
# ^^^ ^^^
to
filter(place=place_id, start_date=timezone.now().date(), stop_date__gte=timezone.now().date())
# ^^^ ^^^

How to automatically change model fields in django

I have a model and I want to know if it is possible to set a condition that triggers a change in the model field. For example, I have a model
class BillboardTracker(models.Model):
client_name = models.CharField(max_length=400)
entry_date = models.DateTimeField(default=datetime.now)
duration = models.PositiveIntegerField()
expiry_date = models.DateField()
is_expired = models.BooleanField(default=False)
I want to know if it is possible to have a function in the model that makes is_expired equals to True when the expiry date is up. I tried this
def expire(self):
if datetime.now == self.expiry_date:
self.is_expired = True
but it's not working. Is it possible to implement this?
Use a #property
The simplest thing here is not to have an is expired field at all! It's not needed. What you need is a property.
class BillboardTracker(models.Model):
client_name = models.CharField(max_length=400)
entry_date = models.DateTimeField(default=datetime.now)
duration = models.PositiveIntegerField()
expiry_date = models.DateField()
#property
def is_expired(self):
if datetime.now > self.expiry_date:
return True
return False
Remember, you don't have a field in a database, if that field is the same as another field with a simple calculation. This automatically eliminates your head ache of having to flag items as expired.
If you want to find out if an object has expired.
if instance.is_expired == True:
print 'yes, that ones gone'
Filtering
If you wanted to retrieve a whole set of objects that have expired
BillboardTracker.objects.filter(expiry_date__le=datetime.now())
This is why I mentioned that you don't need to store a field that can be easily calculated.
Index advantage
In most RDBMS a boolean field (such as your is_expired column) cannot be indexed effectively. So that actually means the above query will be faster than a query on that boolean field provided you create an index on the expiry_date field.
You need to make two changes in this function,
Firstly use datetime.now() and secondly,
You might want to update your logic like this :
def expire(self):
if datetime.now() >= self.expiry_date:
self.is_expired = True
return True
else:
return False
Because sometimes both the values might not be exactly same but still BillboardTracker need is_expired = True for all previous dates.
And in your views :
def your_view(request):
instance = BillboardTracker.objects.get(id=some_id)
if instance.is_expired() == True:
print 'expired'
else:
print 'fresh'

Change query in Django based on day of week

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.

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