improve slug collision handling in _clean_changes
This commit is contained in:
parent
ac9a5f7be5
commit
b6886bb8ba
1 changed files with 24 additions and 11 deletions
|
@ -10,6 +10,7 @@ from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
|
from django.db.models import Q
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.http import int_to_base36
|
from django.utils.http import int_to_base36
|
||||||
from django.utils.timezone import make_naive
|
from django.utils.timezone import make_naive
|
||||||
|
@ -216,23 +217,35 @@ class ChangeSet(models.Model):
|
||||||
if issubclass(changed_object.model_class, LocationSlug):
|
if issubclass(changed_object.model_class, LocationSlug):
|
||||||
slug = changed_object.updated_fields.get('slug', None)
|
slug = changed_object.updated_fields.get('slug', None)
|
||||||
if slug is not None:
|
if slug is not None:
|
||||||
if slug in slugs:
|
|
||||||
changed_object.updated_fields.pop('slug', None)
|
|
||||||
to_save.add(changed_object)
|
|
||||||
else:
|
|
||||||
slugs.add(slug)
|
slugs.add(slug)
|
||||||
|
|
||||||
existing_slugs = set(LocationSlug.objects.filter(slug__in=slugs).values_list('slug', flat=True))
|
qs = LocationSlug.objects.filter(slug__in=slugs)
|
||||||
|
qs = qs.filter(reduce(operator.or_, (Q(slug__startswith=slug+'__') for slug in slugs)))
|
||||||
|
existing_slugs = dict(qs.values_list('slug', 'redirect__target_id'))
|
||||||
|
|
||||||
|
slug_length = LocationSlug._meta.get_field('slug').max_length
|
||||||
for changed_object in changed_objects:
|
for changed_object in changed_objects:
|
||||||
if issubclass(changed_object.model_class, LocationSlug):
|
if issubclass(changed_object.model_class, LocationSlug):
|
||||||
if changed_object.updated_fields.get('slug', None) in existing_slugs:
|
slug = changed_object.updated_fields.get('slug', None)
|
||||||
if issubclass(changed_object.model_class, LocationRedirect):
|
if slug is None:
|
||||||
|
continue
|
||||||
|
if slug in existing_slugs:
|
||||||
|
redirect_to = existing_slugs[slug]
|
||||||
|
if issubclass(changed_object.model_class, LocationRedirect) and redirect_to is not None:
|
||||||
to_save.discard(changed_object)
|
to_save.discard(changed_object)
|
||||||
changed_object.delete()
|
changed_object.delete()
|
||||||
else:
|
continue
|
||||||
changed_object.updated_fields.pop('slug', None)
|
new_slug = slug
|
||||||
|
i = 0
|
||||||
|
while new_slug in existing_slugs:
|
||||||
|
suffix = '__'+str(i)
|
||||||
|
new_slug = slug[:slug_length-len(suffix)]+suffix
|
||||||
|
i += 1
|
||||||
|
slug = new_slug
|
||||||
|
changed_object.updated_fields['slug'] = new_slug
|
||||||
to_save.add(changed_object)
|
to_save.add(changed_object)
|
||||||
|
existing_slugs[slug] = (None if not issubclass(changed_object.model_class, LocationRedirect)
|
||||||
|
else changed_object.updated_fields['target'])
|
||||||
|
|
||||||
for changed_object in to_save:
|
for changed_object in to_save:
|
||||||
changed_object.save(standalone=True)
|
changed_object.save(standalone=True)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue