mirror of
https://github.com/SectorLabs/django-localized-fields.git
synced 2025-10-29 18:18:57 +03:00
Add a new auto-slug field that is concurrency resistent
This commit is contained in:
@@ -5,6 +5,8 @@ from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db.backends.postgresql.base import \
|
||||
DatabaseWrapper as Psycopg2DatabaseWrapper
|
||||
|
||||
from ..fields import LocalizedField
|
||||
|
||||
|
||||
def _get_backend_base():
|
||||
"""Gets the base class for the custom database back-end.
|
||||
@@ -153,7 +155,22 @@ class SchemaEditor(_get_schema_editor_base()):
|
||||
*args, **kwargs
|
||||
)
|
||||
|
||||
self._update_hstore_constraints(model, old_field, new_field)
|
||||
is_old_field_localized = isinstance(old_field, LocalizedField)
|
||||
is_new_field_localized = isinstance(new_field, LocalizedField)
|
||||
|
||||
if is_old_field_localized or is_new_field_localized:
|
||||
self._update_hstore_constraints(model, old_field, new_field)
|
||||
|
||||
def create_model(self, model):
|
||||
"""Ran when a new model is created."""
|
||||
|
||||
super().create_model(model)
|
||||
|
||||
for field in model._meta.local_fields:
|
||||
if not isinstance(field, LocalizedField):
|
||||
continue
|
||||
|
||||
self._update_hstore_constraints(model, field, field)
|
||||
|
||||
|
||||
class DatabaseWrapper(_get_backend_base()):
|
||||
|
||||
@@ -59,6 +59,9 @@ class LocalizedMagicSlugField(LocalizedAutoSlugField):
|
||||
continue
|
||||
|
||||
slug = slugify(value, allow_unicode=True)
|
||||
if instance.retries > 0:
|
||||
slug += '-%d' % instance.retries
|
||||
|
||||
slugs.set(lang_code, slug)
|
||||
|
||||
setattr(instance, self.name, slugs)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from django.db import models
|
||||
from django.db.utils import IntegrityError
|
||||
from django.db import transaction
|
||||
|
||||
from .fields import LocalizedField
|
||||
from .localized_value import LocalizedValue
|
||||
@@ -32,3 +34,30 @@ class LocalizedModel(models.Model):
|
||||
value = LocalizedValue()
|
||||
|
||||
setattr(self, field.name, value)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""Saves this model instance to the database."""
|
||||
|
||||
if not hasattr(self, 'retries'):
|
||||
self.retries = 0
|
||||
|
||||
error = None
|
||||
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
|
||||
|
||||
error = ex
|
||||
|
||||
if self.retries >= 100:
|
||||
raise error
|
||||
|
||||
self.retries += 1
|
||||
return self.save()
|
||||
|
||||
Reference in New Issue
Block a user