I'm using a formset to update a single field of a large group of model instances. I'd like to display a time stamp showing the time since the field for that instance was last updated. Since this field will usually be updated once a week, I'd rather use a DateField than a DateTimeField for the time stamp. DateField doesn't seem to get updated on save though. When I change the model field to DateTimeField, however, it works as expected. Here's my code.
#Template
<div class = 'last-updated'> {{ form.instance.last_updated|timesince }} </div>
# Models.py
last_updated = models.DateField(auto_now=True)
# Models.py - This version works
last_updated = models.DateTimeField(auto_now=True)
I've found posts saying to override the model's save() method but this seems like a last resort, and the posts I've found saying this are dated from 2011 and earlier, so probably out of date.
Since the docs list DateField and DateTimeField as more or less the same, with the same optional arguments, I'm wondering why they don't seem to update auto_now in the same way.
Edit
It also looks as though when I change the field type to DateField, the value displayed is the time since creation, not the time since update, and it updates the value for every single item in the formset. To clarify, there is NO custom save method for this model.
Related
I would like to set a field in a Django model which should be updated everytime a record of the corresponding table is updated by a ModelForm (any field of the table).
I am wondering which of the following options is the best practices one:
Add the "auto_now" argument to the model field.
Include the 'type': 'hidden' attribute to the corresponding widget in the form where the records will be submitted. If this... how should be included the 'value' attribute for the widget?
I know the auto_now argument updates the field only when Model.save() is called. So the question could be rebuilt as... Is the Model.save() called when a ModelForm (linked to the model) is submitted?
Thank you very much.
auto_now Automatically set the field to now every time the object is saved.
So to save updated record time auto_now is the best option
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
https://docs.djangoproject.com/en/3.1/ref/models/fields/#datefield
I'm building a Django application, and in it I would like to track whenever a particular model was last accessed.
I'm opting for this in order to build a user activity history.
I know Django provides auto_now and auto_now_add, but these do not do what I want them to do. The latter tracks when a model was created, and the former tracks when it was last modified, which is different from when it was last accessed, mind you.
I've tried adding another datetime field to my model's specification:
accessed_on = models.DateTimeField()
Then I try to update the model's access manually by calling the following after each access:
model.accessed_on = datetime.utcnow()
model.save()
But it still won't work.
I've gone through the django documentation for an answer, but couldn't find one.
Help would be much appreciated.
What about creating a model with a field that contains the last save-date. Plus saving the object every time is translated from the DB representation to the python representation?
class YourModel(models.Model):
date_accessed = models.DateTimeField(auto_now=True)
#classmethod
def from_db(cls, db, field_names, values):
obj = super().from_db(db, field_names, values)
obj.save()
return obj
Django 1.9 / Python 2.7
Given this model:
class CoursePurchase(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
course = models.ForeignKey(Course)
date_purchased = models.DateField(default=date.today())
I would expect date_purchased to store the date I enter into Django admin, and it does, according to my database browser:
However, retrieving the object in the view has today's date instead of the stored date:
(Note the date_purchased field of __unicode__ returns today's date instead of the stored date.
Here is the code I'm using to retrieve the instance:
cp = CoursePurchase(course=page.course, user=request.user)
where course and user return the expected values.
What am I missing? This seems fairly straightforward, but I can't get past this.
To set the current date on save, django provides special arguments to the DateField type:
Django documentation:
class DateField(auto_now=False, auto_now_add=False, **options)
A date, represented in Python by a datetime.date instance. Has a few extra, optional arguments:
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.
The field is only automatically updated when calling Model.save(). The field isn’t updated when making updates to other fields in other ways such as QuerySet.update(), though you can specify a custom value for the field in an update like that.
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()
The default form widget for this field is a TextInput. The admin adds a JavaScript calendar, and a shortcut for “Today”. Includes an additional invalid_date error message key.
The options auto_now_add, auto_now, and default are mutually exclusive. Any combination of these options will result in an error.
But that's not the cause of the issue you see. When you do this:
cp = CoursePurchase(course=page.course, user=request.user)
You are not retrieving anything from the database, but rather creating a new instance (in-memory only, not saved anywhere yet). To retrieve instances, you need to query the database properly:
cp = CoursePurchase.objects.get(course=page.course, user=request.user)
You can try like this.
cp = CoursePurchase.objects.get(course=page.course, user=request.user)
having used cakephp in the past, one thing (perhaps the only thing?) i liked about it was that it had a "create" and "update" timestamp capability that was lovely - simply put, when you first added an item, the "create" date was set (assuming you named it right - create_date, i think)
Anytime thereafter, if an update was performed, the "update" field was set to the current time.
Does django have this as well? If so, what/how do i name the fields to get it to pick them up?
It is not added to your model built-in in every table. You must add it as field to your model.
class Message(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Message in this case your table's name.
Sure it has!
Check auto_now and auto_now_add in the doc
Greetings,
I am trying to implement a TimeField model which only consists of HH:MM (ie 16:46) format, I know it is possible to format a regular Python time object but I am lost about how to manage this with Django.
Cheers
Django widget can be used to achieve this easily.
from django import forms
class timeSlotForm(forms.Form):
from_time = forms.TimeField(widget=forms.TimeInput(format='%H:%M'))
DateTime fields will always store also seconds; however, you can easily tell the template to just show the hours and minute, with the time filter:
{{ value|time:"H:M" }}
where "value" is the variable containing the datetime field.
Of course, you can also resort to other tricks, like cutting out the seconds from the field while saving; it would require just a small change to the code in the view handling the form, to do something like this:
if form.is_valid():
instance = form.save(commit=False)
instance.nosecs = instance.nosecs.strptime(instance.nosecs.strftime("%H:%M"), "%H:%M")
instance.save()
(note: this is an ugly and untested code, just to give the idea!)
Finally, you should note that the admin will still display the seconds in the field.
It should not be a big concern, though, because admin should be only used by a kind of users that can be instructed not to use that part of the field.
In case you want to patch also the admin, you can still assign your own widget to the form, and thus having the admin using it. Of course, this would mean a significant additional effort.
So I think the proposed and accepted solution is not optimal because with:
datetime.widget = forms.SplitDateTimeWidget(time_format=('%H:%M'))
For a SplitDateTimeField in my case but for you only change it to TimeWidget.
Hope it helps other people too.
TimeField model
in Template
Is displayed
{{ value|time:"H:i" }}
Is not displayed
{{ value|time:"H:M" }}
Django 1.4.1
For a ModelForm, you can easily add a widget like this, to avoid the seconds being shown (just show hh:mm):
class MyCreateForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ('time_in', 'time_out', )
widgets = {
'time_in': forms.TimeInput(format='%H:%M'),
'time_out': forms.TimeInput(format='%H:%M'),
}
You can at least modify the output in the __str__ method on the model by using datetime.time.isoformat(timespec='minutes'), like this:
def __str__(self):
return self.value.isoformat(timespec='minutes')
Now the value is showing as HH:MM in admin pages.
On Django 1.9 the following format should work:
{{ yourData.value|time:"H:i" }}
Django has a whole set of template tags and filters.
Django 1.9 documentation on this is:
https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#time