Look here: https://bitbucket.org/depaolim/optlock
The snippet of Marco De Paoli is much better than this one! :-)
=========================================================
If two users save same record, the second one will overwrite first one. Use this snippet to achieve an optimistic locking, so the second user will get an exception. Save the snippet in optlock.py and put it anywhere in your pythonpath.
Do not put _version_opt_lock in readonly_fields or the snippet will fail! (if you need to hide it, use jquery).
The snippet need in request.POST the original value of _version_opt_lock and if you make it a readonly field Django doesn't POST its value. When this bug will be fixed it should be possible to use a hiddeninput widget.
models.py example:
...
import optlock
...
class YourModel(optlock.Model):
...
admin.py example:
...
import optlock
...
class YourModelAdmin(optlock.ModelAdmin):
...
That's it :-)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #!/usr/bin/env python
# -*- coding: utf-8 -
#
#
# Look here: https://bitbucket.org/depaolim/optlock
# The snippet of Marco De Paoli is much better than this one! :-)
#
#
#
# @contact: [email protected]
# @version: 1.0
# @license: MIT http://www.opensource.org/licenses/mit-license.php
#
from django.db import models, connection
from django.utils.translation import ugettext as _
from django.contrib import admin
class ExceptionNewVersionInDb(Exception):
def __init__(self, obj, version, code=None, params=None):
from django.utils.encoding import force_unicode
self.message = force_unicode("{0} ver {1}: {2}".format(unicode(obj),
version, _("saved by another user")))
def __str__(self):
return repr(self.message)
def __repr__(self):
return 'ExceptionNewVersionInDb(%s)' % repr(self.message)
class Model(models.Model):
_version_opt_lock = models.IntegerField(
blank = True, null = True,
default = 0,
verbose_name = _("Version"))
def get_version_in_db(self):
if self.pk:
cursor = connection.cursor()
raw_query = 'select _version_opt_lock from "{0}" where "{1}" = '.format(
self._meta.db_table, self._meta.pk.attname)
cursor.execute(raw_query + "%s", (self.pk,))
retval = cursor.fetchone()
return retval[0]
return 0
def save(self, *args, **kw_args):
if self.pk:
version_in_db = self.get_version_in_db()
if self._version_opt_lock != version_in_db:
raise ExceptionNewVersionInDb(self, version_in_db)
self._version_opt_lock = version_in_db + 1
else:
self._version_opt_lock = 1
super(Model, self).save(*args, **kw_args)
class Meta:
abstract = True
class ModelAdmin(admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, *args, **kwargs):
formfield = super(ModelAdmin, self).formfield_for_dbfield(db_field, *args, **kwargs)
if (db_field.name == "_version_opt_lock"):
formfield.widget.attrs["readonly"] = "readonly"
return formfield
|
More like this
- Stuff by NixonDash 1 month, 1 week ago
- Add custom fields to the built-in Group model by jmoppel 3 months, 1 week ago
- Month / Year SelectDateWidget based on django SelectDateWidget by pierreben 6 months, 3 weeks ago
- Python Django CRUD Example Tutorial by tuts_station 7 months, 1 week ago
- Browser-native date input field by kytta 8 months, 3 weeks ago
Comments
why do you use a raw query? I suppose it is a performance choice
#
maybe it should be better to use self._meta.pk.attname in place of self._meta.pk.name (see comment in django/models/fields/__init__.py:43). ...the use of a ForeignKey as PrimaryKey was exactly my, unusual, case ;-)
#
You can't use ORM because it caches the _version_opt_lock value.
#
Yep! You are right: I fix it!
#
Please login first before commenting.