Moved retry mechanism to mixin

This commit is contained in:
Swen Kooij 2017-02-03 10:35:39 +02:00
parent 5db87763fb
commit bb11253207
6 changed files with 57 additions and 37 deletions

View File

@ -2,8 +2,9 @@ from .util import get_language_codes
from .forms import LocalizedFieldForm, LocalizedFieldWidget
from .fields import (LocalizedField, LocalizedBleachField,
LocalizedAutoSlugField, LocalizedUniqueSlugField)
from .localized_value import LocalizedValue
from .mixins import AtomicSlugRetryMixin
from .models import LocalizedModel
from .localized_value import LocalizedValue
__all__ = [
'get_language_codes',
@ -14,5 +15,6 @@ __all__ = [
'LocalizedBleachField',
'LocalizedFieldWidget',
'LocalizedFieldForm',
'LocalizedModel'
'LocalizedModel',
'AtomicSlugRetryMixin'
]

View File

@ -34,14 +34,14 @@ def _get_backend_base():
'\'%s\' is not a valid database back-end.'
' The module does not define a DatabaseWrapper class.'
' Check the value of LOCALIZED_FIELDS_DB_BACKEND_BASE.'
))
) % base_class_name)
if isinstance(base_class, Psycopg2DatabaseWrapper):
raise ImproperlyConfigured((
'\'%s\' is not a valid database back-end.'
' It does inherit from the PostgreSQL back-end.'
' Check the value of LOCALIZED_FIELDS_DB_BACKEND_BASE.'
))
) % base_class_name)
return base_class

View File

@ -1,9 +1,11 @@
from django.conf import settings
from django.utils.text import slugify
from django.core.exceptions import ImproperlyConfigured
from ..util import get_language_codes
from ..mixins import AtomicSlugRetryMixin
from ..localized_value import LocalizedValue
from .localized_autoslug_field import LocalizedAutoSlugField
from ..util import get_language_codes
class LocalizedUniqueSlugField(LocalizedAutoSlugField):
@ -17,6 +19,8 @@ class LocalizedUniqueSlugField(LocalizedAutoSlugField):
- Improved performance
When in doubt, use this over :see:LocalizedAutoSlugField.
Inherit from :see:AtomicSlugRetryMixin in your model to
make this field work properly.
"""
def __init__(self, *args, **kwargs):
@ -46,6 +50,12 @@ class LocalizedUniqueSlugField(LocalizedAutoSlugField):
The localized slug that was generated.
"""
if not isinstance(instance, AtomicSlugRetryMixin):
raise ImproperlyConfigured((
'Model \'%s\' does not inherit from AtomicSlugRetryMixin. '
'Without this, the LocalizedUniqueSlugField will not work.'
) % type(instance).__name__)
slugs = LocalizedValue()
for lang_code, _ in settings.LANGUAGES:

View File

@ -0,0 +1,38 @@
from django.db import transaction
from django.conf import settings
from django.db.utils import IntegrityError
class AtomicSlugRetryMixin:
"""Makes :see:LocalizedUniqueSlugField work by retrying upon
violation of the UNIQUE constraint."""
def save(self, *args, **kwargs):
"""Saves this model instance to the database."""
max_retries = getattr(
settings,
'LOCALIZED_FIELDS_MAX_RETRIES',
100
)
if not hasattr(self, 'retries'):
self.retries = 0
with transaction.atomic():
try:
return super().save(*args, **kwargs)
except IntegrityError as ex:
# this is as retarded as it looks, there's no
# way we can put the retry logic inside the slug
# field class... we can also not only catch exceptions
# that apply to slug fields... so yea.. this is as
# retarded as it gets... i am sorry :(
if 'slug' not in str(ex):
raise ex
if self.retries >= max_retries:
raise ex
self.retries += 1
return self.save()

View File

@ -34,33 +34,3 @@ class LocalizedModel(models.Model):
value = LocalizedValue()
setattr(self, field.name, value)
def save(self, *args, **kwargs):
"""Saves this model instance to the database."""
max_retries = getattr(
settings,
'LOCALIZED_FIELDS_MAX_RETRIES',
100
)
if not hasattr(self, 'retries'):
self.retries = 0
with transaction.atomic():
try:
return super(LocalizedModel, self).save(*args, **kwargs)
except IntegrityError as ex:
# this is as retarded as it looks, there's no
# way we can put the retry logic inside the slug
# field class... we can also not only catch exceptions
# that apply to slug fields... so yea.. this is as
# retarded as it gets... i am sorry :(
if 'slug' not in str(ex):
raise ex
if self.retries >= max_retries:
raise ex
self.retries += 1
return self.save()

View File

@ -2,7 +2,7 @@ from django.db import connection, migrations
from django.db.migrations.executor import MigrationExecutor
from django.contrib.postgres.operations import HStoreExtension
from localized_fields import LocalizedModel
from localized_fields import LocalizedModel, AtomicSlugRetryMixin
def define_fake_model(name='TestModel', fields=None):
@ -14,7 +14,7 @@ def define_fake_model(name='TestModel', fields=None):
if fields:
attributes.update(fields)
model = type(name, (LocalizedModel,), attributes)
model = type(name, (AtomicSlugRetryMixin,LocalizedModel,), attributes)
return model