ChatGPT解决这个技术问题 Extra ChatGPT

How do I create a slug in Django?

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.


N
NaturalBornCamper

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)

shy have a special model type? why not just slugify CharFields?
SlugFields set db_index=True by default, and also use a form field by default that has a validation regex to require valid slugs (if represented in a ModelForm or in the admin). You can do those things manually with a CharField if you prefer, it just makes the intention of your code less clear. Also, don't forget the prepopulate_fields ModelAdmin setting, if you want JS-based auto-prepopulate in the admin.
As Dingle said below in his answer, you'll need to replace def save(self): with def save(self, *args, **kwargs): in order to avoid errors from being thrown when writing something like test.objects.create(q="blah blah blah").
Beware that this code will update the slug each saves. your url will change, and "Cool URIs don't change" w3.org/Provider/Style/URI.html
slugify() can also be found in django.utils.text.slugify, not clear when this was added.
D
DooBLER

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'

utf-8 is now handled correctly by slugify (in django 1.8.5)
As @RickWestera said this is now handled by slugify, although if for some reason you don't want to use slugify, check iri_to_uri from django.utils.encoding: docs.djangoproject.com/en/2.0/ref/unicode/…
J
Jonas Gröger

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).


One further very minor thing to add to thepeer's answer: I would make that last line 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.
Please add that from django.utils.text import slugify is required for this solution.
@Routhinator did it
Putting out some feelers to ask if this is still a preferred method for doing this.
Y
Yaroslav Admin

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.


My 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.
s
spiffytech

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()

S
Streamweaver

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()

Docs on editable
d
daaawx

Use prepopulated_fields in your admin class:

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

admin.site.register(Article, ArticleAdmin)

Could you explain? How does the admin affect the project?
m
markwalker_

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",)}

Excactly what I wanted
R
Ralf

You can look at the docs for the SlugField to get to know more about it in more descriptive way.