damon
damon

Reputation: 15128

Django DateField default options

I have a model which has a date time field:

date = models.DateField(_("Date"), default=datetime.now())

When I check the app in the built in django admin, the DateField also has the time appended to it, so that if you try to save it an error is returned. How do I make the default just the date? (datetime.today() isn't working either)

Upvotes: 106

Views: 228032

Answers (9)

Israel Z. DelaMora
Israel Z. DelaMora

Reputation: 27

tl:dr: Don't declare an explicit default value if you don't need one for DateField or DateTimeField. This applies even if you use auto_now or auto_now_add.

First, DateField and DateTimeField store different things. The first will store a date with a timezone (naive TZ) and the second will store a date, time and custom timezone (if not specified, the TZ will be naive). According to Django's model reference:

For DateField: default=date.today - from datetime.date.today()

For DateTimeField: default=timezone.now - from django.utils.timezone.now()

So there is no need no add an explicit default unless you need a custom date or time delta. But if you need it, then declare it with a custom callable.

Using datetime.now()) as the default value will yield a datetime.datetime object type (i.e. 024-05-30 11:22:33.672548) and saving this object into a DateField will cause an error (AssertError) as the model in DateField uses naively the timezone from the server and providing an explicit timezone will cause losing the server's TZ.

Upvotes: 1

Eric Palakovich Carr
Eric Palakovich Carr

Reputation: 23338

Your mistake is using the datetime class instead of the date class. You meant to do this:

from datetime import date
date = models.DateField(_("Date"), default=date.today)

If you only want to capture the current date the proper way to handle this is to use the auto_now_add parameter:

date = models.DateField(_("Date"), auto_now_add=True)

However, the modelfield docs clearly state that auto_now_add and auto_now will always use the current date and are not a default value that you can override.

Upvotes: 56

IAMSSKD
IAMSSKD

Reputation: 9

I tried the below on Django version 4.1.7 and worked perfectly!

from datetime import datetime, date

class Example(models.Model):
    purchase_date = models.DateField(auto_now_add=False, auto_now=False, blank=True)

    def __str__(self):
        return f"{self.str(purchase_date)}"

Returning this is entirely optional. Working perfectly either you return the string or not.

Upvotes: 0

mikemka
mikemka

Reputation: 1

django hint:

HINT: It seems you set a fixed date / time / datetime value as default for this field. This may not be what you want. If you want to have the current date as default, use django.utils.timezone.now

Upvotes: 0

btk
btk

Reputation: 3225

DateField/DateTimeField.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.
Source: Django doc

This should do the trick:

models.DateTimeField(_("Date"), auto_now_add = True)

Upvotes: 6

perepm
perepm

Reputation: 988

I think a better way to solve this would be to use the datetime callable:

from datetime import datetime

date = models.DateField(default=datetime.now)

Note that no parenthesis were used. If you used parenthesis you would invoke the now() function just once (when the model is created). Instead, you pass the callable as an argument, thus being invoked everytime an instance of the model is created.

Credit to Django Musings. I've used it and works fine.

Upvotes: 6

Daniel Roseman
Daniel Roseman

Reputation: 599876

This is why you should always import the base datetime module: import datetime, rather than the datetime class within that module: from datetime import datetime.

The other mistake you have made is to actually call the function in the default, with the (). This means that all models will get the date at the time the class is first defined - so if your server stays up for days or weeks without restarting Apache, all elements will get same the initial date.

So the field should be:

import datetime
date = models.DateField(_("Date"), default=datetime.date.today)

Upvotes: 174

andyshi
andyshi

Reputation: 157

date = models.DateTimeField(default=datetime.now, blank=True)

Upvotes: 7

Neil
Neil

Reputation: 9453

You could also use lambda. Useful if you're using django.utils.timezone.now

date = models.DateField(_("Date"), default=lambda: now().date())

Upvotes: 4

Related Questions