I am trying to create a SlugField
in Django.
I created this simple model:
from django.db import models
class Test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField()
I then do this:
>>> from mysite.books.models import Test
>>> t=Test(q="aa a a a", s="b b b b")
>>> t.s
'b b b b'
>>> t.save()
>>> t.s
'b b b b'
I was expecting b-b-b-b
.
You will need to use the slugify function.
>>> from django.template.defaultfilters import slugify
>>> slugify("b b b b")
u'b-b-b-b'
>>>
You can call slugify
automatically by overriding the save
method:
class Test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField()
def save(self, *args, **kwargs):
self.s = slugify(self.q)
super(Test, self).save(*args, **kwargs)
Be aware that the above will cause your URL to change when the q
field is edited, which can cause broken links. It may be preferable to generate the slug only once when you create a new object:
class Test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField()
def save(self, *args, **kwargs):
if not self.id:
# Newly created object, so set slug
self.s = slugify(self.q)
super(Test, self).save(*args, **kwargs)
There is corner case with some utf-8 characters
Example:
>>> from django.template.defaultfilters import slugify
>>> slugify(u"test ąęśćółń")
u'test-aescon' # there is no "l"
This can be solved with Unidecode
>>> from unidecode import unidecode
>>> from django.template.defaultfilters import slugify
>>> slugify(unidecode(u"test ąęśćółń"))
u'test-aescoln'
A small correction to Thepeer's answer: To override save()
function in model classes, better add arguments to it:
from django.utils.text import slugify
def save(self, *args, **kwargs):
if not self.id:
self.s = slugify(self.q)
super(test, self).save(*args, **kwargs)
Otherwise, test.objects.create(q="blah blah blah")
will result in a force_insert
error (unexpected argument).
return super(test, self).save(*args, **kwargs)
. I think this method returns None
, and I don't know of any plans to change that, but it does no harm to return what the superclass's method does in case it changes sometime in the future.
If you're using the admin interface to add new items of your model, you can set up a ModelAdmin
in your admin.py
and utilize prepopulated_fields
to automate entering of a slug:
class ClientAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('name',)}
admin.site.register(Client, ClientAdmin)
Here, when the user enters a value in the admin form for the name
field, the slug
will be automatically populated with the correct slugified name
.
slug
and name
fields have translations. How can I do that with translations? Because I've tried to add 'slug_en':('name_en',)
and got the error that attribute doesn't exist in my model.
In most cases the slug should not change, so you really only want to calculate it on first save:
class Test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField(editable=False) # hide from admin
def save(self):
if not self.id:
self.s = slugify(self.q)
super(Test, self).save()
If you don't want to set the slugfield to Not be editable, then I believe you'll want to set the Null and Blank properties to False. Otherwise you'll get an error when trying to save in Admin.
So a modification to the above example would be::
class test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField(null=True, blank=True) # Allow blank submission in admin.
def save(self):
if not self.id:
self.s = slugify(self.q)
super(test, self).save()
Use prepopulated_fields
in your admin class:
class ArticleAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)}
admin.site.register(Article, ArticleAdmin)
I'm using Django 1.7
Create a SlugField in your model like this:
slug = models.SlugField()
Then in admin.py
define prepopulated_fields
;
class ArticleAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)}
Success story sharing
def save(self):
withdef save(self, *args, **kwargs):
in order to avoid errors from being thrown when writing something liketest.objects.create(q="blah blah blah")
.slugify()
can also be found indjango.utils.text.slugify
, not clear when this was added.