问题
I have inherited some code for an app that was written for Django 1.4. We need to update the codebase to work with Django 1.7, and eventually 1.8 as the next Long Term Support release.
In a few places it uses the old style @transaction.commit_manually
and with transaction.commit_manually:
I do not know enough about transactions in general but I am trying to understand what they are used for, so I can either remove them (if unnecessary) or upgrade them to the newer set_autocommit(False)
or equivalent.
I have understood that transaction management in Django < 1.5 was not ideal, and too complicated for most use cases.
The database connection looks like this, with no special transaction management. (Using Postgres 9.3)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'dbname',
'USER': 'user',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '',
}
}
There is no special transaction middleware.
I find the following view particularly puzzling. (Edited)
@UserRequiredDecorator
class XMLModelView(View):
@transaction.commit_manually
def get(self, request, *args, **kwargs):
user = request.user
xml_models = models.XMLModel.objects.filter(user=user).order_by('-created').all()
if xml_models:
xml_model = xml_models[0]
model = xml_model.xml_field
else:
obj = initialize_xml_model(user)
model = obj.xml_field
transaction.commit()
if isinstance(model, unicode):
model = model.encode('utf-8')
with transaction.commit_manually():
xml = XMLManipulator(model, remove_blank_text=True)
xml.insert_user_info(user)
xml.whitespace_cleanup()
model = xml.tostring()
del xml
transaction.commit()
return HttpResponse(model, content_type='text/xml')
Where initialize_xml_model
is a function that takes a flat xml file (xml model template) and creates a new XMLModel object. And insert_user_info
inserts information stored in the user object into the xml model.
The way I read this code is
- We turn off
autocommit
withcommit_manually
-
- We either get the most recent XMLModel object for the user, or
- initialize a new XMLModel object
transaction.commit()
stores this to the db if there are no errors.- We check if our
model
is a unicode instance and then encodes it (I'm not sure what this does exactly) - We open a new transaction
- Instanciate an XMLManipulator object with
model
- Insert stuff and clean up xml
- Assign xml instance back to
model
as string (tostring
is an XMLManipulator method that retains stylesheet declarations. ) - delete the
xml
object - Commit transaction
After 5. the only thing that deals with the db (in a read) is the insert_user_info method.
I don't really understand why this is happening in a special transaction. There is no writing to the db?
There is no other methods on this view, only get.
I might have missed out something important here, feel free to ask any questions or for more information.
Is the transaction really necessary here, and if so, how could this be rewritten to suit the new transaction.set_autocommit
?
Any help or pointers would be greatly appreciated.
回答1:
A good way to do this now is using transaction.atomic. In your example I'd do:
from django.db import transaction
@UserRequiredDecorator
class XMLModelView(View):
def get(self, request, *args, **kwargs):
with transaction.atomic():
user = request.user
xml_models = models.XMLModel.objects.filter(user=user).order_by('-created').all()
if xml_models:
xml_model = xml_models[0]
model = xml_model.xml_field
else:
obj = initialize_xml_model(user)
model = obj.xml_field
if isinstance(model, unicode):
model = model.encode('utf-8')
with transaction.atomic():
xml = XMLManipulator(model, remove_blank_text=True)
xml.insert_user_info(user)
xml.whitespace_cleanup()
model = xml.tostring()
del xml
return HttpResponse(model, content_type='text/xml')
来源:https://stackoverflow.com/questions/29149714/upgrading-transaction-commit-manually-to-django-1-6