Thursday, September 24, 2015

Re: different behaviour of datetime.datetime object before vs after save


> I'm baffled by the fact that the __str__ method of an instance fails
> before the instance is saved but works fine afterwards.
>
> The relevant snippet from my models.py file:
> class Journal(models.Model):
>     date = models.DateTimeField(default=timezone.now)

Check the docs on the use of 'default'. The value or callable in this case is used when the object is created by saving the object instance to the database. Granted, the wording should probably be more specific since there is an overlap of meanings for creating the object.

https://docs.djangoproject.com/en/1.8/ref/models/fields/#default

>     user = models.CharField(max_length=24)
>     description = models.CharField(max_length=256)
>     def __str__(self):
>         ret = ["  #{:0>3} on {:<12} by {}."
>                 .format(self.id,
>                         self.date.strftime('%Y-%m-%d %H:%M'),
>                         self.user)]
>         for line in self.description.split('\n'):
>             ret.append("    {}".format(line))
>         return '\n'.join(ret)
>
> Here's the result of some experimentation using the shell:
> (venv)alex@x301:~/Py/debk$ ./manage.py shell
> Python 3.4.0 (default, Jun 19 2015, 14:18:46)
> [GCC 4.8.2] on linux
> Type "help", "copyright", "credits" or "license" for more information.
> (InteractiveConsole)
>>>>
>>>> from journal.models import Journal
>>>> j = Journal(user='Alex', description='Test entry')
>>>> j
>
> Traceback (most recent call last):
>   File "<console>", line 1, in <module>
>   File
> "/home/alex/Py/venv/lib/python3.4/site-packages/django/db/models/base.py",
> line 496, in __repr__
>     u = six.text_type(self)
>   File "/home/alex/Py/debk/journal/models.py", line 22, in __str__
>     self.user)]
> TypeError: non-empty format string passed to object.__format__
>>>>
>>>> j.save()
>>>> j
>
> <Journal:   #005 on 2015-09-24 06:11 by Alex.
>     Test entry>
>>>>
>>>>
>
> I don't understand why saving would change the behavior of an instance.
> I'd like my code to be able to display such an instance before a
> decision is made whether or not to save it.
> I'd be grateful if anyone could explain what's happening and perhaps
> suggest a way to use the __str__ method before saving.

It doesn't particularly make sense to do what you are doing in the first place. You are attributing a time stamp to a volatile piece of data in memory, and in reality it is already gone from memory by the time the user sees it since the response cycle has ended, and is likely being dynamically rebuilt upon the next request cycle in response to form data. What if the user takes 30 minutes to decide to click the submit button and finalize saving the object to the database?

Which moment of time would you want to capture: a) the time the object is created in memory and displayed to the user or b) the moment the object is saved to a non-volatile location like the DB? Most times you'll want the latter since that's when an actual change occurred.

However, if you truly want to catch the moment that the object instance was created in memory, you'll need to add date=timezone.now to your Journal() call instead of relying on the default value of the model field, which only is populated at the point where save() is called and no previous value exists. Obviously if this is part of a confirmation form, you'll need to pass the original timestamp along through the form as well, or you'll wind up with option b) above anyway.

-James

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CA%2Be%2BciXyAMdu8gfrOdx_a-V98ZhLmv9fXPji%3DZdng2-q5WJUMw%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment