I have the following (simplified) model and factory:
models.py
class Event():
duration = FloatField()
start_time = TimeField()
finish_time = DateTimeField()
def save(self, *args, **kwargs):
self.finish_time = self.start_time + timedelta(hours=self.duration)
event_factory.py
from factory import Faker
class EventFactory:
date = Faker(
"date_time_this_month",
before_now=False,
after_now=True,
tzinfo=timezone.get_current_timezone(),
)
start_time = Faker("time_object")
duration = Faker("random_int")
However, my save method raises Warning: DateTimeField Event.finish_time received a naive datetime (2022-03-28 12:43:38) while time zone support is active.
date is aware due to tzinfo argument, but start_time is naive (I checked with django's timezone.is_aware()), because time providers in Faker do not seem to allow any timezone parameters.
Any suggestion in getting a fake aware time object in factory-boy/Faker?
Try to use FuzzyDateTime objects, they return a timezone aware object: https://factoryboy.readthedocs.io/en/stable/fuzzy.html?highlight=timezone
Related
I have to write a serializer that returns datetime in the following formats:
2012-01-01T13:00:00+00:00 (utc_with_timezone) 2020-01-01T09:00:00 (must be in localtime without timezone info)
class SomeResponse(serializers.Serializer):
modified = serializers.DateTimeField() # AutoLastModifiedField(_('modified'))
local_time = serializers.DateTimeField()
but the response for modified field contains miliseconds: 2022-01-01T18:14:05.378897+05:00the response for local_time field contains timezone info and I have to convert it to local time
How can I manipulate the output format without changing the settings for the whole project?
I solved the problem by overriding to_representation of serializers.DateTimeField:
class SomeResponse(serializers.Serializer):
modified = TimeZoneWithUTCField()
local_time = TimeZoneWithUTCField()
class TimeZoneWithUTCField(serializers.DateTimeField):
def to_representation(self, value):
if not value:
return None
value = value.strftime("%Y-%m-%dT%H:%M:%S%z")
if value.endswith('+0000'):
value = value[:-5] + '+00:00'
return value
I have a dateTime field in a model. The dateTime field named breakfast_start_time takes an input.
I have to save another variable or timefield(whichever is better) named breakfast_attendence_start_time whose value should be automatically saved 15 minutes less than the breakfast_start_time.
For this we use
def save(self, *args, **kwargs):
#do something
super().save(*args, *kwargs)
I am trying to do
breakfast_attendence_start_time = breakfast_start_time - time(15,0)
but it is giving error that
class TimeField does not define '_sub_', so the '-' operator cannot be used on its instances
Edited:
Here is the full code
class Hostel(models.Model):
name = models.CharField(max_length=15)
breakfast_start_time = models.TimeField()
lunch_start_time = models.TimeField()
snacks_start_time = models.TimeField()
dinner_start_time = models.TimeField()
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
I am taking start time from admin panel and I want to add 4 more variable/field like breakfast_attendence_start_time whose value should be saved automatically 15 minutes earlier than breakfast_start_time how can I achive that.
You should use timedelta to sub specific time with DateTime field. Such as
import datetime
time_before_15_minute = datetime.datetime.now() - datetime.timedelta(minutes=15)
Use DateTimeField instead of TimeField and use timedelta to make substractions
from datetime import datetime, timedelta
n = datetime(2019, 10, 4, 12, 30)
m = n - timedelta(minutes = 15) # m is now datetime(2019, 10, 4, 12, 15)
You can play with the DateTimeField but this will return time of when this function was called or used. Hope it helps
from django.utils import timezone
class AKA(models.Model):
create_time = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.create_time
Take the example model as follows:
import datetime
class Calendar(models.Model)
def now():
return datetime.date.today()
def 24hrslater():
return datetime.date.today() + datetime.timedelta(days=1)
now = models.DateTimeField(default=now)
24hrslater = models.DateTimeField(default=24hrslater)
Is there a way to extract just the date from these date time fields? I have tried the following (as suggested on another thread):
todaysdate = now.date()
But had no success with it. The error that comes up on the command line when running "python manage.py check" is:
AttributeError: 'DateTimeField' object has no attribute 'date'
Is there a way to do this?
def now():
return datetime.today().date()
this will return the current date
Calendar.objects.filter(datetimefield__date='your_date')
I'm not sure that I understand your question correctly, but you can get the date from DateTimeFields like this.
from django.db import models
from django.utils import timezone
class Calendar(models.Model):
now = models.DateTimeField(default=timezone.now)
twenty_four_hours_later = models.DateTimeField(
default=lambda: timezone.now() + timezone.timedelta(hours=24))
c = Calendar()
print(c.now.date())
print(c.twenty_four_hours_later.date())
I've defined a model as follows (Shortened it for the question)
from datetime import datetime, date, timedelta
class Case(models.Model):
received_email_sent = models.DateTimeField(null=True, blank=True, default=None)
def send_received_email(self):
message = settings.EMAIL_HEADER + self.case_received_email() + settings.EMAIL_FOOTER
send_mail('Subject here', message, settings.EMAIL_HOST_USER, ['xxx#xxx.com'], fail_silently=False)
self.received_email_sent = datetime.now()
and in the view I call send_received_email on an existing object. I know that the send_received_email block is being entered because I'm receiving the emails every time I test this out, but the self.received_email_sent = datetime.now() part is leaving that field as its default value (None) every time. Here's the relevant part of the view:
from logbook.models import Case
def job_email(request, case_id):
case = get_object_or_404(Case,pk=case_id)
case.send_received_email()
return HttpResponseRedirect('/jobs/'+str(case.case_id))
I have also tried an alternative method, where saving the field is done in the view instead of the model, like so:
models:
class Case(models.Model):
received_email_sent = models.DateTimeField(null=True, blank=True, default=None)
def send_received_email(self):
message = settings.EMAIL_HEADER + self.case_received_email() + settings.EMAIL_FOOTER
send_mail('Subject here', message, settings.EMAIL_HOST_USER, ['xxx#xxx.com'], fail_silently=False)
#self.received_email_sent = datetime.now()
views:
from datetime import datetime
from logbook.models import Case
def job_email(request, case_id):
case = get_object_or_404(Case,pk=case_id)
case.send_received_email()
case.received_email_sent = datetime.now()
return HttpResponseRedirect('/jobs/'+str(case.case_id))
I have also tried both of the above routes with various tweaks like removing the brackets on now() and changing from datetime import datetime to just import datetime. No joy. Thanks for having a look at this.
You need to call self.save() at the end of send_received_email().
I want to disable django fields for 6 months after the date of update. I have saved update_time to a table.
updated_time = a.update_time
disabled_time = a.update_time + timedelta(180)
I want to diable field that updated:
self.fields['first_name'].widget.attrs['readonly'] = True
How can I disable self.fields['first_name'].widget.attrs['readonly'] = True for disabled_time?
Thanks in advance
You can compare, and substract basic datetime objects and make some check at form initialization time:
from datetime import timedelta, datetime
...
class FooForm(ModelForm):
def __init__(self, *args, **kwargs):
super(FooForm, self).__init__(*args, **kwargs)
# check if we already have a saved object and it's not older than 180 days
if self.instance.pk and
(datetime.now() - self.instance.update_time) < timedelta(180):
self.fields['first_name'].widget.attrs['readonly'] = True
class Meta:
model = Foo
(Not really tested but should work as it is.)
Also note, that it is often convenient to keep update_time with auto_now set to True.