You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
63 lines
2.2 KiB
63 lines
2.2 KiB
# -*- coding: utf-8 -*- |
|
from __future__ import unicode_literals |
|
|
|
import re |
|
|
|
from .text import slugify |
|
|
|
|
|
# TODO Remove deprecated location |
|
from .models.slugs import AutoSlugField |
|
|
|
|
|
def uniquify_field_value(instance, field_name, value, max_length=None, queryset=None): |
|
""" |
|
Makes a char field value unique by appending an index, taking care of the |
|
field's max length. |
|
|
|
FIXME Doesn't work with model inheritance, where the field is part of the parent class. |
|
""" |
|
if not queryset: |
|
queryset = instance._meta.default_manager.get_queryset() |
|
|
|
field = instance._meta.get_field(field_name) |
|
if not max_length: |
|
max_length = instance._meta.get_field(field_name).max_length |
|
if not value: |
|
if field.blank: |
|
# Special case: Make sure only one row has ean empty value |
|
if queryset.exclude(pk=instance.pk).filter(**{field_name: ''}).exists(): |
|
raise ValueError("Only one blank (root) entry allowed.") |
|
return |
|
else: |
|
raise ValueError("Cannot uniquify empty value") |
|
# TODO Instead get value from instance.field, or use a default value? |
|
|
|
def get_similar_values(value): |
|
return queryset.exclude(pk=instance.pk) \ |
|
.filter(**{"%s__istartswith" % field_name: value}).values_list(field_name, flat=True) |
|
|
|
# Find already existing counter |
|
m = re.match(r'(.+)(-\d+)$', value) |
|
if m: |
|
base_value, counter = m.groups() |
|
index = int(counter.strip("-")) + 1 |
|
else: |
|
base_value = value |
|
index = 2 # Begin appending "-2" |
|
|
|
similar_values = get_similar_values(value) |
|
while value in similar_values or len(value) > max_length: |
|
value = "%s-%i" % (base_value, index) |
|
if len(value) > max_length: |
|
base_value = base_value[:-(len(value) - max_length)] |
|
value = "%s-%i" % (base_value, index) |
|
similar_values = get_similar_values(base_value) |
|
index += 1 |
|
return value |
|
|
|
|
|
# TODO Remove alias |
|
def unique_slug(instance, slug_field, slug_value, max_length=50, queryset=None): |
|
slug_value = slugify(slug_value) |
|
return uniquify_field_value(instance, slug_field, slug_value, max_length=50, queryset=None)
|
|
|