mirror of
https://github.com/SectorLabs/django-localized-fields.git
synced 2025-04-25 11:42:54 +03:00
Moved retry mechanism to mixin
This commit is contained in:
parent
5db87763fb
commit
bb11253207
@ -2,8 +2,9 @@ from .util import get_language_codes
|
|||||||
from .forms import LocalizedFieldForm, LocalizedFieldWidget
|
from .forms import LocalizedFieldForm, LocalizedFieldWidget
|
||||||
from .fields import (LocalizedField, LocalizedBleachField,
|
from .fields import (LocalizedField, LocalizedBleachField,
|
||||||
LocalizedAutoSlugField, LocalizedUniqueSlugField)
|
LocalizedAutoSlugField, LocalizedUniqueSlugField)
|
||||||
from .localized_value import LocalizedValue
|
from .mixins import AtomicSlugRetryMixin
|
||||||
from .models import LocalizedModel
|
from .models import LocalizedModel
|
||||||
|
from .localized_value import LocalizedValue
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'get_language_codes',
|
'get_language_codes',
|
||||||
@ -14,5 +15,6 @@ __all__ = [
|
|||||||
'LocalizedBleachField',
|
'LocalizedBleachField',
|
||||||
'LocalizedFieldWidget',
|
'LocalizedFieldWidget',
|
||||||
'LocalizedFieldForm',
|
'LocalizedFieldForm',
|
||||||
'LocalizedModel'
|
'LocalizedModel',
|
||||||
|
'AtomicSlugRetryMixin'
|
||||||
]
|
]
|
||||||
|
@ -34,14 +34,14 @@ def _get_backend_base():
|
|||||||
'\'%s\' is not a valid database back-end.'
|
'\'%s\' is not a valid database back-end.'
|
||||||
' The module does not define a DatabaseWrapper class.'
|
' The module does not define a DatabaseWrapper class.'
|
||||||
' Check the value of LOCALIZED_FIELDS_DB_BACKEND_BASE.'
|
' Check the value of LOCALIZED_FIELDS_DB_BACKEND_BASE.'
|
||||||
))
|
) % base_class_name)
|
||||||
|
|
||||||
if isinstance(base_class, Psycopg2DatabaseWrapper):
|
if isinstance(base_class, Psycopg2DatabaseWrapper):
|
||||||
raise ImproperlyConfigured((
|
raise ImproperlyConfigured((
|
||||||
'\'%s\' is not a valid database back-end.'
|
'\'%s\' is not a valid database back-end.'
|
||||||
' It does inherit from the PostgreSQL back-end.'
|
' It does inherit from the PostgreSQL back-end.'
|
||||||
' Check the value of LOCALIZED_FIELDS_DB_BACKEND_BASE.'
|
' Check the value of LOCALIZED_FIELDS_DB_BACKEND_BASE.'
|
||||||
))
|
) % base_class_name)
|
||||||
|
|
||||||
return base_class
|
return base_class
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.text import slugify
|
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_value import LocalizedValue
|
||||||
from .localized_autoslug_field import LocalizedAutoSlugField
|
from .localized_autoslug_field import LocalizedAutoSlugField
|
||||||
from ..util import get_language_codes
|
|
||||||
|
|
||||||
|
|
||||||
class LocalizedUniqueSlugField(LocalizedAutoSlugField):
|
class LocalizedUniqueSlugField(LocalizedAutoSlugField):
|
||||||
@ -17,6 +19,8 @@ class LocalizedUniqueSlugField(LocalizedAutoSlugField):
|
|||||||
- Improved performance
|
- Improved performance
|
||||||
|
|
||||||
When in doubt, use this over :see:LocalizedAutoSlugField.
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -46,6 +50,12 @@ class LocalizedUniqueSlugField(LocalizedAutoSlugField):
|
|||||||
The localized slug that was generated.
|
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()
|
slugs = LocalizedValue()
|
||||||
|
|
||||||
for lang_code, _ in settings.LANGUAGES:
|
for lang_code, _ in settings.LANGUAGES:
|
||||||
|
38
localized_fields/mixins.py
Normal file
38
localized_fields/mixins.py
Normal 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()
|
@ -34,33 +34,3 @@ class LocalizedModel(models.Model):
|
|||||||
value = LocalizedValue()
|
value = LocalizedValue()
|
||||||
|
|
||||||
setattr(self, field.name, value)
|
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()
|
|
||||||
|
@ -2,7 +2,7 @@ from django.db import connection, migrations
|
|||||||
from django.db.migrations.executor import MigrationExecutor
|
from django.db.migrations.executor import MigrationExecutor
|
||||||
from django.contrib.postgres.operations import HStoreExtension
|
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):
|
def define_fake_model(name='TestModel', fields=None):
|
||||||
@ -14,7 +14,7 @@ def define_fake_model(name='TestModel', fields=None):
|
|||||||
|
|
||||||
if fields:
|
if fields:
|
||||||
attributes.update(fields)
|
attributes.update(fields)
|
||||||
model = type(name, (LocalizedModel,), attributes)
|
model = type(name, (AtomicSlugRetryMixin,LocalizedModel,), attributes)
|
||||||
|
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user