Django

Code

Ticket #1584 (closed: fixed)

Opened 2 years ago

Last modified 2 years ago

[patch] auto_now_add fields set to NULL on update

Reported by: Andy Dustman <farcepest@gmail.com> Assigned to: adrian
Component: Database wrapper Version: SVN
Keywords: Cc: farcepest@gmail.com, fawad@fawad.net, upadhyay@gmail.com
Triage Stage: Unreviewed Has patch: 1
Needs documentation: 0 Needs tests: 0
Patch needs improvement: 0

Description

When adding an object with a models.DateTimeField?(auto_now_add=True), the column is set to the current time as it should be. However, when doing an update, Django tries to set the column to NULL.

Example: These are SQL statements (and parameters) as they are executed. created is auto_now_add and updated is auto_now. First, adding the new objects in the admin interface:

INSERT INTO `dns_domain` (`name`) VALUES (%s) ['foo.com']
INSERT INTO `dns_nameserver` (`domain_id`,`name`,`ip`,`starts`,`expires`,`ttl`,`location_id`,`created`,`updated`) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s) [2L, 'a', '1.2.3.4', None, None, None, None, '2006-04-04 17:50:40', '2006-04-04 17:50:40']
INSERT INTO `dns_nameserver` (`domain_id`,`name`,`ip`,`starts`,`expires`,`ttl`,`location_id`,`created`,`updated`) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s) [2L, 'b', '1.2.3.5', None, None, None, None, '2006-04-04 17:50:40', '2006-04-04 17:50:40']

Then, updating the objects in the admin interface:

SELECT `dns_domain`.`id`,`dns_domain`.`name` FROM `dns_domain` WHERE (`dns_domain`.`name` = %s) ['foo.com']
SELECT 1 FROM `dns_domain` WHERE `id`=%s LIMIT 1 ['2']
UPDATE `dns_domain` SET `name`=%s WHERE `id`=%s ['foo.com', '2']
SELECT `dns_nameserver`.`id`,`dns_nameserver`.`domain_id`,`dns_nameserver`.`name`,`dns_nameserver`.`ip`,`dns_nameserver`.`starts`,`dns_nameserver`.`expires`,`dns_nameserver`.`ttl`,`dns_nameserver`.`location_id`,`dns_nameserver`.`created`,`dns_nameserver`.`updated` FROM `dns_nameserver` WHERE (`dns_nameserver`.`domain_id` = %s AND `dns_nameserver`.`id` = %s) [2L, '4']
SELECT 1 FROM `dns_nameserver` WHERE `id`=%s LIMIT 1 ['4']
UPDATE `dns_nameserver` SET `domain_id`=%s,`name`=%s,`ip`=%s,`starts`=%s,`expires`=%s,`ttl`=%s,`location_id`=%s,`created`=%s,`updated`=%s WHERE `id`=%s ['2', 'a', '1.2.3.4', None, None, None, None, None, '2006-04-04 17:55:02', '4']
SELECT `dns_domain`.`id`,`dns_domain`.`name` FROM `dns_domain` WHERE (`dns_domain`.`id` = %s) ['2']
SELECT `dns_nameserver`.`id`,`dns_nameserver`.`domain_id`,`dns_nameserver`.`name`,`dns_nameserver`.`ip`,`dns_nameserver`.`starts`,`dns_nameserver`.`expires`,`dns_nameserver`.`ttl`,`dns_nameserver`.`location_id`,`dns_nameserver`.`created`,`dns_nameserver`.`updated` FROM `dns_nameserver` WHERE (`dns_nameserver`.`domain_id` = %s AND `dns_nameserver`.`id` = %s) [2L, '5']
SELECT 1 FROM `dns_nameserver` WHERE `id`=%s LIMIT 1 ['5']
UPDATE `dns_nameserver` SET `domain_id`=%s,`name`=%s,`ip`=%s,`starts`=%s,`expires`=%s,`ttl`=%s,`location_id`=%s,`created`=%s,`updated`=%s WHERE `id`=%s ['2', 'b', '1.2.3.5', None, None, None, None, None, '2006-04-04 17:55:02', '5']
SELECT `dns_domain`.`id`,`dns_domain`.`name` FROM `dns_domain` WHERE (`dns_domain`.`id` = %s) ['2']

Note that created is being set to None/NULL.

Example done with mysql backend. The problem seems to lie in models itself and is not specific to the admin interface: I could update an object using the shell and it would do the same thing. I'm assuming "Database wrapper" encompasses django.db.models and not just the backends.

Attachments

auto_now_add_fix.diff (0.5 kB) - added by Andy Dustman <farcepest@gmail.com> on 04/06/06 20:29:58.
Bug fix (against magic-removal)
auto_now_add_fix.2.diff (0.5 kB) - added by Andy Dustman <farcepest@gmail.com> on 04/06/06 20:31:55.
Better bug fix (evaluation order matters)
auto_now_add_fix.patch (3.8 kB) - added by lukeplant on 05/29/06 12:04:43.
Patch involving reworked Field.pre_save()

Change History

04/04/06 13:53:19 changed by anonymous

  • cc set to mir@noris.de.

04/06/06 20:29:58 changed by Andy Dustman <farcepest@gmail.com>

  • attachment auto_now_add_fix.diff added.

Bug fix (against magic-removal)

04/06/06 20:31:55 changed by Andy Dustman <farcepest@gmail.com>

  • attachment auto_now_add_fix.2.diff added.

Better bug fix (evaluation order matters)

04/07/06 19:09:53 changed by Andy Dustman <farcepest@gmail.com>

  • summary changed from auto_now_add fields set to NULL on update to [patch] auto_now_add fields set to NULL on update.

Patch available

05/09/06 11:07:42 changed by anonymous

  • cc changed from mir@noris.de to mir@noris.de,fawad@fawad.net.

05/09/06 17:44:19 changed by anonymous

  • cc changed from mir@noris.de,fawad@fawad.net to mir@noris.de,fawad@fawad.net, upadhyay@gmail.com.

05/11/06 10:20:53 changed by fawad@fawad.net

I'm seeing that this problem happens on the current Django trunk as well.

class NotificationSchedule(models.Model):
    class Admin:
        pass
    def __str__(self):
        return "%s (%s hours before the event)" % (self.name, self.offset)
    name = models.CharField("Description of the schedule", maxlength = 72, core = True)
    offset = models.FloatField("Number of hours before event the notifications should be sent", core = True,
        decimal_places = 2, max_digits = 10)
    created = models.DateTimeField(auto_now_add = True)
    modified = models.DateTimeField(auto_now = True)
[fawad@fawad5 meetup]$ python manage.py shell --plain
Python 2.5a1 (trunk:45386, Apr 14 2006, 09:22:06)
[GCC 3.4.4 20050721 (Red Hat 3.4.4-2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from meetup.models import NotificationSchedule
>>> x=NotificationSchedule(name="foo", offset=3)
>>> x.save()
>>> x.offset=4
>>> x.save()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/local/stow/python-cvs/lib/python2.5/site-packages/django/db/models/base.py", line 169, in save
    db_values + [pk_val])
  File "/usr/local/stow/python-cvs/lib/python2.5/site-packages/django/db/backends/util.py", line 12, in execute
    return self.cursor.execute(sql, params)
  File "/usr/local/stow/python-cvs/lib/python2.5/site-packages/django/db/backends/sqlite3/base.py", line 73, in execute
    return Database.Cursor.execute(self, query, params)
IntegrityError: meetup_notificationschedule.created may not be NULL

05/26/06 20:43:58 changed by Andy Dustman <farcepest@gmail.com>

  • cc changed from mir@noris.de,fawad@fawad.net, upadhyay@gmail.com to farcepest@gmail.com, mir@noris.de, fawad@fawad.net, upadhyay@gmail.com.
  • version changed from magic-removal to SVN.
  • milestone set to Version 0.92.

With the demise/merging of magic-removal, this is still an issue in the trunk. Presumably other people who are watching this bug would have spoken up if the patch didn't work, and it's simple enough that it's "obviously" correct (for sufficiently large values of obvious).

05/29/06 07:57:38 changed by asmodai@in-nomine.org

This is biting me as well on trunk. Using a a FileField in conjunction.

The patch does not seem to work for me though. Although someone on IRC did solve his problem with it. Leaves me to assume the issue runs a bit deeper.

I see that after a save in the Admin gui the failing SQL is an UPDATE with the date field set to None on the update, which of course fails the constraint and gives me an IntegrityError submit_date may not be NULL.

submit_date is: models.DateField?(auto_now_add = True)

05/29/06 08:05:41 changed by asmodai@in-nomine.org

The person on IRC noted that his constraint was removed. It also fails for him.

05/29/06 08:49:14 changed by mdt@emdete.de

i had to change the line in question (line 421 in 3001) to

if self.auto_now or (self.auto_now_add and (add or value is None)):

which works for me. i dont understand why pre_save() just returns the value without setting it at the instance...

05/29/06 11:40:01 changed by lukeplant

The patch doesn't exactly fix it: if you save an object n times, the datetime value will be set to the datetime at the last time you saved, not the first. The problem is that the value is not being saved to the object. The pre_save method cannot currently do this, since it doesn't have access to the object (pre_save is a method on a Field object and Field objects are essentially definitions that don't contain data -- the data itself is a member of the model class instance).

The reason this is not normally a problem is that you normally discard' an object after saving it -- the next time it is used will be by another request, which will load it fresh from the database, and the datetime value will be set.

The easiest way to fix it, as I see it, is to change the arguments of Field.pre_save() so that it takes a model instance instead of a value. I'll come up with a patch and check it with Adrian.

05/29/06 12:04:43 changed by lukeplant

  • attachment auto_now_add_fix.patch added.

Patch involving reworked Field.pre_save()

05/29/06 12:09:00 changed by lukeplant

  • status changed from new to closed.
  • resolution set to fixed.

(In [3002]) Fixed #1584 - auto_now_add fields now work when saving multiple times.

05/29/06 12:14:19 changed by lukeplant

As you can tell, I went ahead and committed the patch -- I was pretty sure about it. The only issue might be compatibility with people who have subclassed Field, but as I understand it that's an internal class -- subclassing Field isn't documented anywhere.

07/09/06 16:57:03 changed by dave@thebarproject.com

  • status changed from closed to reopened.
  • resolution deleted.

Even with the patch, when updating edit_inline fields, null is set (individual editing of the same model has been fixed.) Had to override save() for inline editing of models with auto_now_add.

07/27/06 17:18:03 changed by jacob

  • status changed from reopened to closed.
  • resolution set to fixed.

Reclosing -- edit_inline is broken in more ways than this, and is being rewritten.

10/09/06 02:43:11 changed by mir@noris.de

  • cc changed from farcepest@gmail.com, mir@noris.de, fawad@fawad.net, upadhyay@gmail.com to farcepest@gmail.com, fawad@fawad.net, upadhyay@gmail.com.

Removing myself from Cc.

10/24/06 15:17:23 changed by adrian

  • milestone deleted.

Milestone Version 0.92 deleted


Add/Change #1584 ([patch] auto_now_add fields set to NULL on update)




Change Properties
Action