Firstly, this question has already been asked here, however the answer does not work, and is also for Django 1.3. Having done extensive research on similar questions on SO, the Django Docs, and general Googling, I still can't find a working answer. Not really a major detail, but it's annoying both when trying to use the form I'm creating, and because I can't solve it.
When using the SelectDateWidget in a ModelForm, I want to be able to set the default on the widget to today's date.
forms.py
from django import forms
from .models import Article
from django.utils import timezone
class ArticleForm(forms.ModelForm):
publish=forms.DateField(widget=forms.SelectDateWidget(), initial = timezone.now)
class Meta:
model = Article
fields = [
'title',
...
'publish',
]
models.py
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from django.utils import timezone
from Blog.models import Category
class Article(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length = 120, unique=True)
...
publish = models.DateField(default=timezone.now)
I'm assuming I have some syntax error somewhere, but have had no joy in finding it.
Looks like there's a subtle difference when setting the the default time for DateTimeField and DateField.
DateField.auto_now_add Automatically set the field to now when the
object is first created. Useful for creation of timestamps. Note that
the current date is always used; it’s not just a default value that
you can override. So even if you set a value for this field when
creating the object, it will be ignored. If you want to be able to
modify this field, set the following instead of auto_now_add=True:
For DateField: default=date.today - from datetime.date.today()
For DateTimeField: default=timezone.now - from django.utils.timezone.now()
So, you'll want to use date.today rather than timezone.now.
Related
I created an admin view using the TabularInline class. With this view it is not possible to let the user order/sort the table to their liking, like within a standard ModelAdmin view. I would like to achieve this. I am using Django 2.2.1.
What I tried
I searched the Django docs, but besides hard coding 'ordering' within the admin.py file, I couldn't find anything on this topic. This is not what I want, I want the admin user to choose how to order.
I tried to use adminsortable2, however I ran into some issues I couldn't resolve. This got me thinking: is it really not possible with the standard Django package.
My code
My model consists of TimeFrames, which are made up by TimeSlots.
This is what my model.py looks like:
from django.db import models
class TimeFrame(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class TimeSlot(models.Model):
DAY_CHOICES = ('work', 'Work'), ('weekend', 'Weekend')
begin_time = models.TimeField()
end_time = models.TimeField()
reference = models.CharField(max_length=30)
day = models.CharField(max_length=30, choices=DAY_CHOICES)
timeframe = models.ForeignKey('TimeFrame', on_delete=models.CASCADE)
I don't want to register a separate TimeSlot admin view, since the TimeSlots are always part of a TimeFrame. They don't exist on their own.
from django.contrib import admin
from .models import *
class TimeSlotInline(admin.TabularInline):
model = TimeSlot
ordering = ("day", "begin_time") #hard-coded ordering
#admin.register(TimeFrame)
class TimeFrameAdmin(admin.ModelAdmin):
inlines = [TimeSlotInline]
Expected outcome
Enable the admin user to sort like in a standard ModelAdmin view.
I have a simple create view for a simple model with default-value fields. I want to test this setup by supplying only fields which don't have a default value.
The test fails, because no object was created in the database. Having played around with prints, I know the following:
The models clean() passes, and is supplied with the default values.
The response claims "This field is required." for maxVar and minVotes.
(And sending both values lets the tests pass.)
The failing test is:
from django.test import TestCase
from django.utils import timezone
from django.core.urlresolvers import reverse
import datetime
from testcase.models import Poll
class PollCreateTest(TestCase):
def test_create_with_description_only(self):
"""description should be sufficient to create a poll."""
self.assertEqual(Poll.objects.count(), 0)
x = self.client.post(reverse('rating:create'), {'description':'A Poll'})
#print x
self.assertEqual(Poll.objects.count(), 1)
With corresponding models.py:
from django.db import models
from django.core.urlresolvers import reverse
class Poll(models.Model):
description = models.TextField()
pub_date = models.DateTimeField('date published')
minVotes = models.IntegerField(default=5)
maxVar = models.FloatField(default = 0.0)
finished = models.BooleanField(default=False)
And views.py:
from django.shortcuts import render
from django.views import generic
from .models import Poll
class CreateView(generic.edit.CreateView):
model=Poll
fields=['description', 'maxVar', 'minVotes']
I am trying to get myself familiar with Django. The problem can probably be solved by writing a FormView with custom clean() methods. But I would like to understand WHY this doesn't work and, ideally, how to solve the problem.
I use Django 1.8 with Python 2.7.8.
The initial value is only used for two purposes: to render the initial value in the html form input, and to see if the submitted value has changed. It is not used to validate the form: not passing the actual data to the form is the same as explicitly changing the initial data to an empty value.
As your maxVar and minVotes fields are required (they don't have blank=True), deleting the initial values and passing no data to the form is not allowed. You have to pass both of them if you want the form to validate.
When I try to set my datetime field to today's date in two of my models via the admin I get the error "couldn't be interpreted in time zone America/Los_Angeles; it may be ambiguous or it may not exist". This only happens in these two models. If I try to set datetime to today's date in other models (most of which are not shown), there are no problems.
Here are the relevant models from model.py:
from django.db import models
# DateTimeField has no problem with today's date in this model
class Subject(models.Model):
title = models.CharField(max_length=200, unique=True)
date_created = models.DateTimeField('date created')
times_viewed = models.IntegerField()
# Both DateTimeFields give an error in this model
class Discussion(models.Model):
subject = models.ForeignKey(Subject)
title = models.CharField(max_length=200)
version = models.CharField(max_length=200)
created = models.DateTimeField('date created')
updated = models.DateTimeField('date updated')
creator = models.CharField(max_length=200)
# DateTimeField gives an error in this model too
class DiscussionPost(models.Model):
discussion = models.ForeignKey(Discussion)
poster = models.CharField(max_length=200)
text = models.TextField()
posted = models.DateTimeField('date posted')
Here is the relevant part of admin.py:
from django.contrib import admin
from my_app.models import Subject, Discussion, DiscussionPost # and other irrelevant models
class DiscussionPostInline(admin.StackedInline):
model = DiscussionPost
extra = 1
class DiscussionAdmin(admin.ModelAdmin):
fieldsets = [
('Title', {'fields': ['title']}),
('Creator', {'fields': ['creator']}),
('Date Created', {'fields': ['created']}),
('Date Updated', {'fields': ['updated']}),
]
inlines = [DiscussionPostInline]
list_display = ('title', 'creator', 'created', 'updated')
admin.site.register(Discussion, DiscussionAdmin)
DiscussionInline(admin.StackedInline):
model = Discussion
extra = 1
SubjectAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['title']}),
('Times Viewed', {'fields': ['times_viewed'], 'classes': ['collapse']}),
('Date Created', {'fields': ['date_created'], 'classes': ['collapse']}),
]
inlines = [DiscussionInline]
list_display = ('title', 'times_viewed', 'date_created')
list_filter = ['date_created']
search_fields = ['title']
date_hierarchy = 'date_created'
admin.site.register(Subject, SubjectAdmin)
If I manually change to a different day from the admin, I do not get the error. It is just when I use today's date (both manually and using now() ). Anybody know why this may be happening?
This admin structure is based on the second answer to this Django Admin nested inline.
UPDATE I changed the datetime within the admin and now it works. I didn't change anything in the models or admin so I am stumped as to why it wasn't working earlier this morning.
you've been mixing up naive datetime object while having USE_TZ = True. To create current time you need to use timezone.now() instead of datetime.now()
From pytz doc
The major problem we have to deal with is that certain datetimes may occur twice in a year. ... This means that if you try and create a time in the ‘US/Eastern’ timezone using the standard datetime syntax, there is no way to specify if you meant before of after the end-of-daylight-savings-time transition.
...
The best and simplest solution is to stick with using UTC. The pytz package encourages using UTC for internal timezone representation by including a special UTC implementation based on the standard Python reference implementation in the Python documentation.
...
If you pass None as the is_dst flag to localize(), pytz will refuse to guess and raise exceptions if you try to build ambiguous or non-existent times.
From django docs
Interpretation of naive datetime objects
When USE_TZ is True, Django still accepts naive datetime objects, in order to preserve backwards-compatibility. When the database layer receives one, it attempts to make it aware by interpreting it in the default time zone and raises a warning.
Unfortunately, during DST transitions, some datetimes don’t exist or are ambiguous. In such situations, pytz raises an exception. Other tzinfo implementations, such as the local time zone used as a fallback when pytz isn’t installed, may raise an exception or return inaccurate results. That’s why you should always create aware datetime objects when time zone support is enabled.
In practice, this is rarely an issue. Django gives you aware datetime objects in the models and forms, and most often, new datetime objects are created from existing ones through timedelta arithmetic. The only datetime that’s often created in application code is the current time, and timezone.now() automatically does the right thing.
In a Django project I installed django_taggit. I'm getting this error when I syncdb my project.
AttributeError: 'TaggableManager' object has no attribute 'related'
My models.py something like this...
from taggit.managers import TaggableManager
class Post(models.Model):
title = models.CharField(max_length=100)
tags = TaggableManager()
and admin.py something like this...
from django.contrib import admin
admin.site.register(Post)
Django admin is trying to use the TaggableManager to manage your post objects. You need to be careful when using custom managers; as the docs specify:
If you use custom Manager objects, take note that the first Manager Django encounters (in the order in which they’re defined in the model) has a special status. Django interprets the first Manager defined in a class as the “default” Manager, and several parts of Django (including dumpdata) will use that Manager exclusively for that model. As a result, it’s a good idea to be careful in your choice of default manager in order to avoid a situation where overriding get_query_set() results in an inability to retrieve objects you’d like to work with.
An easy way to get around this is to manually specify Post.objects first:
class Post(models.Model):
title = models.CharField(max_length=100)
objects = models.Manager()
tags = TaggableManager()
Is it possible to customize a django application to have accept localized date format (e.g dd/mm/yy) in a DateField on an admin form ?
I have a model class :
class MyModel(models.Model):
date = models.DateField("Date")
And associated admin class
class MyModelAdmin(admin.ModelAdmin):
pass
On django administration interface, I would like to be able to input a date in following format : dd/mm/yyyy. However, the date field in the admin form expects yyyy-mm-dd.
How can I customize things ? Nota bene : I have already specified my custom language code (fr-FR) in settings.py, but it seems to have no effect on this date input matter.
Thanks in advance for your answer
The admin system uses a default ModelForm for editing the objects. You'll need to provide a custom form so that you can begin overriding field behaviour.
Inside your modelform, override the field using a DateField, and use the input_formats option.
MY_DATE_FORMATS = ['%d/%m/%Y',]
class MyModelForm(forms.ModelForm):
date = forms.DateField(input_formats=MY_DATE_FORMATS)
class Meta:
model = MyModel
class MyModelAdmin(admin.ModelAdmin):
form = MyModelForm
The fix proposed by Ben is working but the calendar on the right is not shown anymore.
Here is an improvement. The calendar will still be shown and the date will be displayed with the %d%%M/%Y format.
from django.forms.models import ModelForm
from django.contrib.admin.widgets import AdminDateWidget
from django.forms.fields import DateField
class MyModelForm(ModelForm):
date = DateField(input_formats=['%d/%m/%Y',],widget=AdminDateWidget(format='%d/%m/%Y'))
class Meta:
model = MyModel
class MyModelAdmin(admin.ModelAdmin):
form = MyModelForm
When clicking on a day in the calendar, the value of the field has the %Y-%m-%d format but is is accepted as a valid date format.
PS: Thanks to Daniel Roseman for his answer to this question