Given a model
class Foo(models.Model):
bar = models.DateTimeField(auto_now_add=True)
When I do
my_foo = Foo.objects.create(bar=yesterday)
Then my_bar.foo is not yesterday but now. I have to do
my_foo = Foo.objects.create()
my_foo.bar = yesterday
my_foo.save()
This didn't use to be the case, but is true for Django 1.8.17
From the docs:
The auto_now and auto_now_add options will always use the date in the default timezone at the moment of creation or update. If you need something different, you may want to consider simply using your own callable default or overriding save() instead of using auto_now or auto_now_add; or using a DateTimeField instead of a DateField and deciding how to handle the conversion from datetime to date at display time.
So you should do that instead
bar = models.DateTimeField(default=date.today)
Related
I'm quite new to Python and Django. I'm setting up a new model class and I'm able to add appointments on the admin page, but here's the strange thing:
I used to have a DateTimeFiled, which I changed to a separate DateField and a TimeField. But now I see neither my DateField nor my TimeField. Why is that, I don't understand it. I've done the migration, everything looks right.
This is my model class:
class Appointment(models.Model):
patient = models.ForeignKey(User, related_name="appointment_patient", on_delete=False)
date = models.DateField(auto_now=True)
start_time = models.TimeField(auto_now=True)
duration = models.DurationField(default=timedelta(minutes=30))
Before I made this change every property came out right, but now this happens:
auto_now automatically updated with timezone.now() whenever the model object is saved also its not editable. So its not necessary to display them in the template. That is why adminsite omits this field or does not show it. Please see the documentation for more details. If you want to display this field then add it readonly_fields. For example:
class YourModelAdmin(admin.ModelAdmin):
readonly_fields=('start_time',)
Update
If you want to add default value to DateField, try like this:
import datetime
# in models
state_date = models.DateField(default=datetime.date.today) # without parenthesis
In Django, we can use these 2 parameters when making a date column:
DateField.auto_now Automatically set the field to now every time the
object is saved. Useful for “last-modified” timestamps. Note that the
current date is always used; it’s not just a default value that you
can override.
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.
How to do this in SQLAlchemy?
Finally, after checking the SQLAlchemy doc, this should be the way:
Column('created_on', DateTime, default=datetime.datetime.now)
Column('last_updated', DateTime, onupdate=datetime.datetime.now)
doc here:
http://docs.sqlalchemy.org/en/latest/core/defaults.html#python-executed-functions
It's still possible to use the following:
enter_date = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
On update also sqlalchemy set the current date at the time the data updates.
I want to have some kind of timestsamp for updating of models. The problem is that mysql timestamp is only in 1 sec resolution, so if I use DateTime with auto_add_now this is not fine enough for me.
I thought of using float field and to assign it to time.time() on every update. This is a model where I use update using QuerySet.update()
model MyModel:
last_update = models.FloatField(default=time.time)
I then take care of updating last_update before any save (all my calls goes through central location, so I can do this explicitly in the creation), e.g something like:
m = MyModel(..,last_update=time.time())
or when I do bulk update,
m = MyModel.objects.filter(....).update(last_update_time=time.time())
Are there any issues with this approach of saving float and order by it?
Just to clarify, I'm aware of DateTimeField option with auto_now=True, the problem is that this gives me 1 second resolution since it is mapped to date time field in MYSQL which is 1 sec resolution (I'm using MYSQL 5.5)
I think you can use DateField.auto_now, and the field will be updated each time the object gets saved. For example last_update = models.DateTimeField(auto_now = True).
You can read the documentation here, as you can see that Field option is intended to archive exactly what you want.
Also you can override the save method as you can see there and update the last_update field as you prefer.
Personally I recommend the first approach because of simplicity, there is also a third option using signals but I guess that can get so confusing.
from datetime import datetime
class Model(models.Model):
date_created = models.DateTimeField()
date_modified = models.DateTimeField()
def save(self):
if self.date_created == None:
self.date_created = datetime.now()
self.date_modified = datetime.now()
super(Model, self).save()
I have the below db model:
from datetime import datetime
class TermPayment(models.Model):
# I have excluded fields that are irrelevant to the question
date = models.DateTimeField(default=datetime.now(), blank=True)
I add a new instance by using the below:
tp = TermPayment.objects.create(**kwargs)
My issue: all records in database have the same value in date field, which is the date of the first payment. After the server restarts, one record has the new date and the other records have the same as the first. It looks as if some data is cached, but I can't find where.
database: mysql 5.1.25
django v1.1.1
it looks like datetime.now() is being evaluated when the model is defined, and not each time you add a record.
Django has a feature to accomplish what you are trying to do already:
date = models.DateTimeField(auto_now_add=True, blank=True)
or
date = models.DateTimeField(default=datetime.now, blank=True)
The difference between the second example and what you currently have is the lack of parentheses. By passing datetime.now without the parentheses, you are passing the actual function, which will be called each time a record is added. If you pass it datetime.now(), then you are just evaluating the function and passing it the return value.
More information is available at Django's model field reference
Instead of using datetime.now you should be really using from django.utils.timezone import now
Reference:
Documentation for django.utils.timezone.now
so go for something like this:
from django.utils.timezone import now
created_date = models.DateTimeField(default=now, editable=False)
From the documentation on the django model default field:
The default value for the field. This can be a value or a callable object. If callable it will be called every time a new object is created.
Therefore following should work:
date = models.DateTimeField(default=datetime.now,blank=True)
David had the right answer. The parenthesis () makes it so that the callable timezone.now() is called every time the model is evaluated. If you remove the () from timezone.now() (or datetime.now(), if using the naive datetime object) to make it just this:
default=timezone.now
Then it will work as you expect:
New objects will receive the current date when they are created, but the date won't be overridden every time you do manage.py makemigrations/migrate.
I just encountered this. Much thanks to David.
The datetime.now() is evaluated when the class is created, not when new record is being added to the database.
To achieve what you want define this field as:
date = models.DateTimeField(auto_now_add=True)
This way the date field will be set to current date for each new record.
datetime.now() is being evaluated once, when your class is instantiated. Try removing the parenthesis so that the function datetime.now is returned and THEN evaluated. I had the same issue with setting default values for my DateTimeFields and wrote up my solution here.
From the Python language reference, under Function definitions:
Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that that same “pre-computed” value is used for each call.
Fortunately, Django has a way to do what you want, if you use the auto_now argument for the DateTimeField:
date = models.DateTimeField(auto_now=True)
See the Django docs for DateTimeField.
The answer to this one is actually wrong.
Auto filling in the value (auto_now/auto_now_add isn't the same as default). The default value will actually be what the user sees if its a brand new object. What I typically do is:
date = models.DateTimeField(default=datetime.now, editable=False,)
Make sure, if your trying to represent this in an Admin page, that you list it as 'read_only' and reference the field name
read_only = 'date'
Again, I do this since my default value isn't typically editable, and Admin pages ignore non-editables unless specified otherwise. There is certainly a difference however between setting a default value and implementing the auto_add which is key here. Test it out!
In Django 3.0 auto_now_add seems to work with auto_now
reg_date=models.DateField(auto_now=True,blank=True)
if you need only DateField try this
date = models.DateField(auto_now=False, auto_now_add=False, null=True, blank=True)
if you need Both Date and Time try this
date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
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)
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)
Your mistake is using the datetime module instead of the date module. 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.
date = models.DateTimeField(default=datetime.now, blank=True)
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.
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)
You could also use lambda. Useful if you're using django.utils.timezone.now
date = models.DateField(_("Date"), default=lambda: now().date())
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