Opened 14 years ago
Closed 14 years ago
#13974 closed (wontfix)
saving object with multi-table inheritance is not transactional by default
Reported by: | Chris Curvey | 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: | no | UI/UX: | no |
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()
Django cannot know the scope of your transaction. At best, Model.save() could be wrapped with a savepoint.