Formatting DateTimeField in Django - python

When saving timestamp in Django's DateTimeField using auto_now_add this way:
creation_timestamp = models.DateTimeField(auto_now_add=True)
the field is saved with miliseconds:
2018-11-20T15:58:44.767594-06:00
I want to format this to be displayed without miliseconds:
2018-11-20T15:58:44-06:00
But the only option I could come up with does not exactly show what I need:
format="%Y.%m.%dT%H:%M:%S%z" gives me 2018.11.20T15:58:44-0600
How do I format this field the way I need?
Alternatively I'd rather save DateTimeField without milliseconds at all but does auto_now_add allow to do this sort of thing?

If you want to format it on when displaying it, you can use: creation_timestamp.strftime("%Y-%m-%d%H:%M:%S")
You can also make DateTimeField to save it in that format, but this would request a set of changes which will apply system wide:
In your settings file set the follwing:
DATETIME_FORMAT="%Y-%m-%d%H:%M:%S"
L10N=False to make sore localization data doesn't take precedent when it comes to dates format.
USE_TZ=False
But, consider the fact that this changes will apply by default to all date time objects from your project.

You can override DateTimeField's value_to_string method and add the changes there. For example:
class CustomDateTimeField(models.DateTimeField):
def value_to_string(self, obj):
val = self.value_from_object(obj)
if val:
val.replace(microsecond=0)
return val.isoformat()
return ''
And use it in model:
created = CustomDateTimeField(auto_now_add=True)

I think you will have to use isoformat. Look at that answer:
Show the : character in the timezone offset using datetime.strftime

I use pandas to_datetime() function to convert the time to string format.
import pandas as pd
record_list = myModel.objects.all()
for idx, record in enumerate(record_list ):
st = str(pd.to_datetime(record.start_time))
record_list[idx].start_time = st

Related

use __gte for string date django

Date is in string format in database
class A(models.Model):
date = models.CharField(max_length=50, blank=True, null=True)
Yah i know it should be date type.
but now we have many records and we will soon change it to date type.
For current status i want get the objects greater than particular date.
So how can i use date__gte
example
objs = A.objects.filter(date__gte=datetime.now())
Is there any way to achieve this without converting date to datetime field.
I am not sure if that works. What you can try is a custom manager. So you can create a manager for your model, add something like date_gte and then convert the string to a datetime. Then you can user those operators as usual. That's a quick fix for now, but the best solution is to use a DateTimeField, which you want to do as far as I understood.
Example Manager:
from django.db import models
class MyManager(models.Manager):
def date_gte(self, date=datetime.now()):
items = []
for obj in self.all():
if datetime(obj.date) < date:
items.append(obj)
return items
Then you could call it like MyModel.objects.date_gte(date=datetime.now()).
Note: This is an expensive query and you may need to convert the simple list into QuerySet object. I haven't tested it, so this example should only help you get started.
There is no way to do this without a conversion (either in Django or the database during the query) to a proper DateTime type. You're trying to compare a datetime.datetime to a str. That won't work in normal Python and it won't work here.
What kind of string? if it is formatted to %Y%m%d, you can use .extra() method to do the query.
A.objects.extra(where=['date >= date_of_today'])

How to get django queryset results with formatted datetime field

I've Django model which has foreign keys associated with other models. Each model is having same field names(attributes) created_at and updated_at
In every django queryset results I'll be getting datetime values.
Model.objects.all().values('created_at')
But I want to format the datetime field to "DD-MM-YYYY HH:MM:SS" and trim down the milliseconds in the django query results.
If I use "extra" and and date_trunc_sql like the following command
dt = connection.ops.date_trunc_sql('day','created_date')
objects.extra({'date':dt}).values('date')
Which works fine. But If I query like the following, its raising ambiguous statement error.
objects.extra({'date':dt}).values('date', 'x', 'y', 'z')
How to overcome this problem?
Solved it via #Yannics answer at: https://stackoverflow.com/a/60924664/5804947
This also avoids using extra which should be "a last resort" due to Django docs.
from django.db.models import F, Func, Value, CharField
qs.annotate(
formatted_date=Func(
F('created_at'),
Value('DD-MM-YYYY HH:MM:SS'),
function='to_char',
output_field=CharField()
)
)
Got the solution.
data = list(Model.objects.extra(select={'date':"to_char(<DATABASENAME>_<TableName>.created_at, 'YYYY-MM-DD hh:mi AM')"}).values_list('date', flat='true')
It's not just tablename.attribute, it should be dbname_tablename.attribute when we have multiple databases(ambiguous)
which will result list of created_at datetime values trimmed to 'YYYY-MM-DD HH:MM' format.
I don't think values() function would anything related to formatting datetime result. But why does that bother you? Can't you convert them to proper format when you try to display them? If you try to render them in the template, django has template filter date for formatting your datetime value: https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#date

Modifying display format of DateTimes in django-tables2

I'm currently using django-tables2 to display a queryset of my model. One of the attributes of this model is a DateTimeField accurate to the millisecond which is being truncated to the minute in my table.
I had previously manually implemented a simple table in HTML and had no issues. My DateTimeFields were following true to the DATETIME_FORMAT applied in my settings:
settings.py
DATETIME_FORMAT = 'Y N j, H:i:s.u'
The problem has arisen since I began using django-tables2. Is there some way to modify the way it displays DateTimeFields or make it follow my specified DATETIME_FORMAT? I need to retain the sorting functionality so converting to a string is not an option.
I'm using render_table to display my table. The following is my table class:
class ModelTable(tables.Table):
class Meta:
model = Measurement
sequence = ('date_time', 'latitude', 'longitude',
'depth', 'soundvel', 'instrument')
Problem solved.
django-table2's DateTimeColumn class seems to be looking for a SHORT_DATETIME_FORMAT rather than the DATETIME_FORMAT in my settings.py. Updated the value in my settings file and everything is in working order.
This confused me for a while as I tried to use the Python datetime formatting options. The formatting options for Django templates apply in django-tables2, and are fully enumerated at the Django docs:
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#std:templatefilter-date
From that, if you have a model with one datetime column, and you want their birthday to be formatted as Month Day Year, Hour:Minute AM/PM, then you would enter the following:
class MyTable(tables.Table):
birthday = tables.DateTimeColumn(format ='M d Y, h:i A')
class Meta:
model = Person
attrs = {'class': 'table'}
fields = ['birthday']
You can add 'format' as argument to DateTimeColumn.
https://django-tables2.readthedocs.io/en/latest/_modules/django_tables2/columns/datetimecolumn.html
class DateTimeColumn(TemplateColumn):
"""
A column that renders `datetime` instances in the local timezone.
Arguments:
format (str): format string for datetime (optional).
Note that *format* uses Django's `date` template tag syntax.
short (bool): if `format` is not specified, use Django's
``SHORT_DATETIME_FORMAT``, else ``DATETIME_FORMAT``

How do I get each distinct 'year' value out of a Django model with a datetime field?

I can successfully filter by a given year in my Django model, but I'm having trouble finding a way to list valid years so a user can access them.
I have a django model with a defined 'datetime' field, oh-so-originally named 'date'. In my templates, I can successfully access the 'bar.date.date.year' field, so I know it exists, but when I try the following function...
blog_years=[]
for entry in blog_entries:
if entry.date.date.year not in blog_years:
blog_years.append(entry.date.date.year)
I'm told that "'builtin_function_or_method' object has no attribute 'year'"
I can only assume I"m tripping over some aspect of Python I'm not familiar with, but I can't figure out what it is. I'm quite certain it has to be syntactical, but past that...
Django has an elegant and efficient way of doing this. You can check from their docs https://docs.djangoproject.com/en/3.0/ref/models/querysets/#dates
But to go over it
Entry.objects.dates('pub_date', 'year')
This will bring out distinct year values in the query.
if you are using postgres, you can do
BlogEntry.objects.extra(select={"year": "EXTRACT(YEAR FROM date)"}).distinct().values_list("year", flat=True)
A Python set does not allow duplicates, so if you wanted a list of distinct years:
blog_years = list(set([entry.date.year for entry in blog_entries]))
Or, you could use distinct():
blog_years = blog_entries.distinct(entry__date__year).values(entry__date__year)
Of course, adjust the above based on your model.
The first .date accesses a datetime object.
The second .date is accessing a method on datetime objects that returns a date object but not calling it (this step is unneccessary).
The last part (the way you wrote it) is trying to access the year attribute of the date method, instead of accessing the year attribute of the result of the date method call.
Correcting the code to see the difference, it would look like this...
blog_years=[]
for entry in blog_entries:
if entry.date.date().year not in blog_years:
blog_years.append(entry.date.date().year)
But what you should do is more like this...
blog_years=[]
for entry in blog_entries:
if entry.date.year not in blog_years:
blog_years.append(entry.date.year)
since datetime objects have the date attribute as well.
date() is a method of datetime, use
blog_years=[]
for entry in blog_entries:
if entry.date.date().year not in blog_years:
blog_years.append(entry.date.date().year)
from django 1.10 it has become very simple
from django.db.models.functions import ExtractYear
blog_years= blog_entries.annotate(
year=ExtractYear('created_on')
).values_list('year', flat=True)
blog_years = sorted(set(blog_years), reverse=True)
It might not be what you exactly expects (it can return years without blog posts):
from datetime import date
from django.db.models import Min
def blog_years():
current_year = date.today().year
queryset = Entry.objects.annotate(Min('date')).order_by('date')
if queryset:
oldest_year = queryset[0].date.date().year
else:
oldest_year = current_year
return range(oldest_year, current_year + 1)
ModelName.objects.dates('column_name', 'year')

django's DateField model field and acceptable values

I'm having a bit of trouble with django's DateField model field. Shouldn't it be able to accept fiveDaysLater as a valid date object? When I try to add fiveDaysLater into the database, I get an error saying cannot add null value to date. However, the second I change the date field to a regular CharField, the fiveDaysLater value is added to the database with no problem. fyi if I print fiveDaysLater, I get 2011-09-28
My view:
def myView():
now = datetime.date.today()
fiveDaysLater = now + datetime.timedelta(days=5)
newDate = Speech(date = fiveDaysLater)
newDate.save()
My model
class Speech(models.Model):
date = models.DateField()
"However, the second I change the date field to a regular CharField..." Just a suspicion but if you made this change in your code, make sure to delete and recreated the Speech table using syncdb, otherwise, sqlite will not be aware of this change. (or you could change the datatype using sqlite exporer for firefox or something like that...)

Categories

Resources