Opened 15 years ago
Closed 15 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.