TimeField format in Django template - django

I'm writing an application in Django and using several TimeFields in a model. I only want to work with the time format hh:mm (not hh:mm:ss or hh p.m./a.m. or other things).
I have set the django setting TIME_FORMAT = 'H:i' and USE_L10N = False according to the documentation,
USE_L10N overrides TIME_FORMAT if set to True
In my template I'm using input boxes automatically created by Django like:
{{formName.timeField}}
The problem is that as long as I introduce something like "10:00" and do a POST, when the POST is done Django (or whatever) turns it into "10:00:00" (so it adds the seconds).
Is there a way to specify the format in which datetime fields display saved dates? If I could just use something like |date:"H:i" in the value of the input box that would do the trick.
On the other side I know I could do the input box manually (not directly using {{formName.timeField}}), but I've had some problems in the past with that so I would like to avoid that (at least for the moment).
There is also this similar question in Django TimeField Model without seconds, but the solution does not work (it gives me 'NoneType' object has no attribute 'strptime')

I had exactly this problem in my app, and solved it by passing a format parameter to Django's TimeInput widget:
from django import forms
class SettingsForm(forms.Form):
delivery_time = forms.TimeField(widget=forms.TimeInput(format='%H:%M'))

Assuming you have a format you want all TimeFields to use, you can add the TIME_INPUT_FORMATS to your settings file. For example, TIME_INPUT_FORMATS = ('%I:%M %p',) will format your times as "5:30 PM".
The docs: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TIME_INPUT_FORMATS

Related

DJANGO datetime wrong on template even after timezone setup

I have a DJANGO application, and I am completely lost about times.
I am located in Budapest, Hungary, my current time for these test is: 09:26
I have my timezone correctly set in settings.py
...
TIME_ZONE = 'Europe/Budapest'
USE_I18N = True
USE_L10N = True
USE_TZ = True
...
Lets say I store a datetime object in my SQLite database, the admin page will show the correct time:
If I query that data in a view the date is suddenly wrong.
2020-10-06 07:26:41.040463+00:00
I have read solutions that I need to activate timezone in my view, but it does not work:
tzname = pytz.timezone("Europe/Budapest")
timezone.activate(tzname)
for i in MyObject.objects.all():
print(i.date)
returns
2020-10-06 07:26:41.040463+00:00
I usually fill my templates with Ajax JS calls, so I was not able to try template filters like this:
{{ value|timezone:"Europe/Budapest" }}
How can I change the time so that my JsonResponse sends the correct time to my templates?
Consider carefully the first sentence in the timezone documentation:
When support for time zones is enabled, Django stores datetime information in UTC in the database, uses time-zone-aware datetime objects internally, and translates them to the end user’s time zone in templates and forms.
Note that translation to local time zones only happens in templates and forms—not database queries, views, or other functions. There are many good reasons for that, one of which is that converting to a different timezone can lose information. Let's say that the datetime you got back from the database was 2:30am on October 25, 2019, Budapest time. What moment in time does that represent? You can't know, because that time occurred twice due to daylight savings time.
So the behavior you're seeing is entirely correct. If you want to convert a datetime to the local time in code use localtime():
from django.utils.timezone import localtime
local = localtime(myobject.timestamp)
When you create your models, you could set the datetime to your local timezone.
from django.utils import timezone
date = models.DateTimeField(
default=timezone.localtime(timezone.now()),
blank=True
)
timezone.localtime(timezone.now()) will give you the time based on the TIME_ZONE given in the settings.
Moment JS:
https://momentjs.com/timezone/docs/#/using-timezones/converting-to-zone/

Django Model DateField and input fixture

Model file includes :
class Foo(models.Model):
bar = models.DateTimeField()
Fixture file.json includes:
{
"model": "app.Foo",
"pk": "1",
"fields": {
"bar": "2018/4/20",
}
},
when I'm trying to add fixtures with "python manage.py loaddata" result is:
django.core.serializers.base.DeserializationError: Problem installing fixture
'C:\Projects\TestProject\app\fixtures\file.json': ['“2018/4/20” value has an
invalid format. It must be in Y
YYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format.']: (app.Foo:pk=1) field_value was '2018/4/20'
so my question is how can I add date format with "YYYY/MM/DD" to my Model files ?
your using DateTimeField() and your getting data is only date that's why it's getting the error instead of DateTimeField() use DateField()
for example:class Foo(models.Model):
bar = models.DateField()
The Django models.DateField and models.DateTimeField expect input either as python datetime objects or in ISO format (with "-" separators, not "/" separators). This is not something you can easily change because it is also what is used to save the values in the database. So what you want isn't possible.
The only option I see is that you write your own management command that first parses your json fixture, changing the dates format to ISO and saving to a new file, then calling the loaddata command from within your own handle() method.
Note: The corresponding form fields, forms.DateField, are flexible and accept various input formats and allow you to specify which input format you want to use. In fact, if you enable i18n then they will accept international input formats like 2020/03/12. But that doesn't really help you with loaddata which doesn't use a form at all.

Django File-based session doesn't expire

I just realized that my session doesn't expire when I use file-based session engine. Looking at Django code for file-based session, Django doesn't store any expiration information for a session, thus it's never expire unless the session file gets deleted manually.
This looks like a bug to me, as the database-backed session works fine, and I believe regardless of what session back-end developer chooses, they all should behave similarly.
Switching to database-backed session is not an option for me, as I need to store user's session in files.
Can anyone shed some lights?
Is this really a bug?
If yes, how do you suggest me to work around it?
Thanks!
So it looks like you're right. At least in django 1.4, using django.contrib.sessions.backends.file totally ignores SESSION_COOKIE_AGE. I'm not sure whether that's really a bug, or just undocumented.
If you really need this functionality, you can create your own session engine based on the file backend in contrib, but extend it with expiry functionality.
Open django/contrib/sessions/backends/file.py and add the following imports:
import datetime
from django.utils import timezone
Then, add two lines to the load method, so that it appears as below:
def load(self):
session_data = {}
try:
session_file = open(self._key_to_file(), "rb")
if (timezone.now() - datetime.datetime.fromtimestamp(os.path.getmtime(self._key_to_file()))).total_seconds() > settings.SESSION_COOKIE_AGE:
raise IOError
try:
file_data = session_file.read()
# Don't fail if there is no data in the session file.
....
This will actually compare the last modified date on the session file to expire it.
Save this file in your project somewhere and use it as your SESSION_ENGINE instead of 'django.contrib.sessions.backends.file'
You'll also need to enable SESSION_SAVE_EVERY_REQUEST in your settings if you want the session to timeout based on inactivity.
An option would be to use tmpwatch in the directory where you store the sessions
I hit similar issue on Django 3.1. In my case, my program calls the function set_expiry(value) with an integer argument (int data type) before checking session expiry.
Accoring to Django documentation, the data type of argument value to set_expiry() can be int , datetime or timedelta. However for file-based session, expiry check inside load() doesn't work properly only if int argument is passed to set_expiry() beforehand, and such problem doesn't happen to datetime and timedelta argument of set_expiry().
The simple solution (workaround?) is to avoid int argument to set_expiry(value), you can do so by subclassing django.contrib.sessions.backends.file.SessionStore and overriding set_expiry(value) (code sample below), and change parameter SESSION_ENGINE accordingly in settings.py
from datetime import timedelta
from django.contrib.sessions.backends.file import SessionStore as FileSessionStore
class SessionStore(FileSessionStore):
def set_expiry(self, value):
""" force to convert to timedelta format """
if value and isinstance(value, int):
value = timedelta(seconds=value)
super().set_expiry(value=value)
Note:
It's also OK to pass timedelta or datetime to set_expiry(value) , but you will need to handle serialization issue on datetime object.

How can I get access to a Django Model field verbose name dynamically?

I'd like to have access to one my model field verbose_name.
I can get it by the field indice like this
model._meta._fields()[2].verbose_name
but I need to get it dynamically. Ideally it would be something like this
model._meta._fields()['location_x'].verbose_name
I've looked at a few things but I just can't find it.
For Django < 1.10:
model._meta.get_field_by_name('location_x')[0].verbose_name
model._meta.get_field('location_x').verbose_name
For Django 1.11 and 2.0:
MyModel._meta.get_field('my_field_name').verbose_name
More info in the Django doc
The selected answer gives a proxy object which might look as below.
<django.utils.functional.__proxy__ object at 0x{SomeMemoryLocation}>
If anyone is seeing the same, you can find the string for the verbose name in the title() member function of the proxy object.
model._meta.get_field_by_name(header)[0].verbose_name.title()
A better way to write this would be:
model._meta.get_field(header).verbose_name.title()
where header will be the name of the field you are interested in. i.e., 'location-x' in OPs context.
NOTE: Developers of Django also feel that using get_field is better and thus have depreciated get_field_by_name in Django 1.10. Thus I would suggest using get_field no matter what version of Django you use.
model._meta.get_field_by_name('location_x')[0].verbose_name
You can also use:
Model.location_x.field.verbose_name
Model being the class name. I tested this on my Animal model:
Animal.sale_price.field.verbose_name
Animal.sale_price returns a DeferredAttribute, which has several meta data, like the verbose_name
Note: I'm using Django 3.1.5
If you want to iterate on all the fields you need to get the field:
for f in BotUser._meta.get_fields():
if hasattr(f, 'verbose_name'):
print(f.verbose_name)
# select fields for bulk_update : exclude primary key and relational
fieldsfields_to_update = []
for field_to_update in Model._meta.get_fields():
if not field_to_update.many_to_many and not field_to_update.many_to_one and not field_to_update.one_to_many and not field_to_update.one_to_one and not field_to_update.primary_key and not field_to_update.is_relation :
fields_to_update = fields_to_update + [field_to_update.name]
Model.objects.bulk_update(models_to_update , fields_to_update)

Django admin doesn't show translated enumerations in list view under Python 2.3

When using localized list of "choices" for a model field, the admin doesn't show the translated values in the list view.
Short example:
from django.utils.translation import ugettext_lazy as _
class OrderStates:
STATES = (
(STATE_NEW, _("New")),
(STATE_CANCELLED, _("Cancelled")), )
class Order(models.Model):
state = models.IntegerField(choices=OrderStates.STATES)
# ..
class OrderAdmin(admin.ModelAdmin):
list_display = [ 'id', 'state', 'address', 'user']
# ..
admin.site.register(Order, OrderAdmin)
The localized versions of "New" and "Cancelled" show up correctly in the front-end and in the admin form when editing an order. But in the admin list view I get blank fields - regardless of the language I switch to, including English. Column names are fine.
This only happens with Python 2.3 (talk about niche questions). The choices display correctly everywhere with Python 2.5. I don't get any errors or warnings in neither.
Tried using ugettext instead of ugettext_lazy for the options, which didn't work. ugettext_noop sort of works - it at least shows the original english versions instead of blank fields.
Am I doing something wrong or is this a bug?
This is probably a bug somewhere in Django, not calling force_unicode on the item correctly. The original code you pasted is correct. You don't mention what Django version you're using, so I'd reccomend trying the latest 1.0.3 or 1.1 release to see if that happens to fix it, else check the ticket tracker to see if it's already been reported (note that if it hasn't been fixed yet it probably won't be at all, since 1.1 is the last version to support 2.3).
try using:
import gettext as _
Though, that may break if some of your translations use non-ascii values. Actually, this should have been fixed some time ago, see Ticket #5287.
Hope this helps.