Opened 5 years ago

Closed 5 years ago

#13974 closed (wontfix)

saving object with multi-table inheritance is not transactional by default

Reported by: ccurvey Owned by: nobody
Component: Database layer (models, ORM) Version: 1.2
Severity: Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

if you are using multi-table inheritance, and there is some problem writing to one of the tables, some tables are updated, and some are not.

(MySQL 5.x on Ubuntu, Django 1.2rc 1 on Windows)

1) Set up a new project with database settings like so:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', 
        'NAME': 'mydb',
        'USER': 'myuser',
        'PASSWORD': 'mypassword'
        'HOST': 'myhost',
        'PORT': '', 
        'OPTIONS' : {
            'init_command' : 'set storage_engine=INNODB',
            },

    }
}

2) Now set up some models that use inheritance:

from django.db import models

# Create your models here.

class Foo(models.Model):
    a = models.IntegerField()
    
class Bar(Foo):
    b = models.IntegerField()
    

3) Now create a script that does something obviously wrong.

import sys
sys.path.append(r"C:\users\ccurvey")
sys.path.append(r"C:\users\ccurvey\testme")
sys.path.append(r"C:\users\ccurvey\testme\foobar")

import os
os.environ["DJANGO_SETTINGS_MODULE"] = 'settings'

from foobar.models import Bar

# try testing something that is clearly wrong.
bar = Bar(a=1, b="A")

# this is going to throw a ValueError
bar.save()

4) Now go look at the underlying tables in MySQL:

mysql> select * from foobar_foo;
+----+---+
| id | a |
+----+---+
|  1 | 1 |
+----+---+
1 row in set (0.00 sec)

mysql> select * from foobar_bar;
Empty set (0.00 sec)

The workaround is to add @commit_on_success and a save() method to Bar, like so, but it seems (to me) like this should be unncessary.

from django.db.transaction import commit_on_success

    
class Bar(Foo):
    b = models.IntegerField()
    
    @commit_on_success
    def save(self):
        super(Bar, self).save()
    

Change History (1)

comment:1 Changed 5 years ago by emulbreh

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to wontfix
  • Status changed from new to closed

Django cannot know the scope of your transaction. At best, Model.save() could be wrapped with a savepoint.

Note: See TracTickets for help on using tickets.
Back to Top