This is a simple solution aimed at saving some time when you simply want to get a slug from a model field just before saving.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | from django.db.models import CharField
from django.utils.encoding import force_unicode
from django.template.defaultfilters import slugify
def _get_field(instance, name):
try:
return getattr(instance, name)
except AttributeError:
raise ValueError("Model %s has no field '%s'" % \
(instance.__class__.__name__, name))
class AutoSlugField(CharField):
""" A SlugField that automatically populate itself using the value of another
field.
In addition to CharField's usual parameters you can specify:
populate_from (mandatory): the name of the field to be used for the slug
creation. ValueError will be raised at the
object save() time if the field does not exist.
slugify_func: the function to apply on the value of the field.
If unspecified django.template.defaultfilters.slugify will be
used.
append_field: the name of a field that will be appended to the slug, or
None. ValueError will be raised at the object save() time if
the field does not exist.
prepend_field: the name of a field that will be prepended to the slug, or
None. ValueError will be raised at the object save() time if
the field does not exist.
field_separator: the separator between the slug and the {pre, ap}pended
fields. The default value is u'-'.
Unless explicitly set otherwise, the field will be created with the
'editable' and 'db_index' parameters set respectively to False and
True. """
def __init__(self, *args, **kwargs):
# Set editable=False if not explicitly set
if 'editable' not in kwargs:
kwargs['editable'] = False
# Set db_index=True if not explicitly set
if 'db_index' not in kwargs:
kwargs['db_index'] = True
populate_from = kwargs.pop('populate_from', None)
slugify_func = kwargs.pop('slugify_func', slugify)
append_field = kwargs.pop('append_field', None)
prepend_field = kwargs.pop('prepend_field', None)
field_separator = kwargs.pop('field_separator', u'-')
if populate_from is None:
raise ValueError("missing 'populate_from' argument")
else:
self._populate_from = populate_from
self._slugify_func = slugify_func
self._prepend_field = prepend_field
self._append_field = append_field
self._field_separator = field_separator
super(AutoSlugField, self).__init__(*args, **kwargs)
def pre_save(self, model_instance, add):
populate_from = _get_field(model_instance, self._populate_from)
make_slug = self._slugify_func
chunks = list()
if self._prepend_field is not None:
prepend_field = _get_field(model_instance, self._prepend_field)
# Prepend the field's value only if it is not empty
if prepend_field:
chunks.append(force_unicode(prepend_field))
chunks.append(make_slug(populate_from))
if self._append_field is not None:
append_field = _get_field(model_instance, self._append_field)
# Append the field's value only if it is not empty
if append_field:
chunks.append(force_unicode(append_field))
value = self._field_separator.join(chunks)
setattr(model_instance, self.attname, value)
return value
def get_internal_type(self):
return 'SlugField'
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 8 months ago
Comments
Some simple examples:
#
I always just do something like this:
I dont really see the point of this field type..
#
That's what i used to do too. I just thought that the need of an automatically-generated slug was a common enough situation to write some genereal-purpose code and forget about it for the rest of my time. Moreover, i felt more comfortable with a declarative approach than with the standard idiom of overriding save(). Not really a big deal, i know :), but i eventually came up with this solution.
#
Please login first before commenting.