Как мне создать слизняк в Django?

218

Я пытаюсь создать SlugField в Джанго.

Я создал эту простую модель:

from django.db import models

class Test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField()

Затем я делаю это:

>>> 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'

Я ожидал b-b-b-b.

JohnD
источник

Ответы:

413

Вам нужно будет использовать функцию slugify.

>>> from django.template.defaultfilters import slugify
>>> slugify("b b b b")
u'b-b-b-b'
>>>

Вы можете позвонить slugifyавтоматически, переопределив saveметод:

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)

Имейте в виду, что вышеизложенное приведет к изменению вашего URL при qредактировании поля, что может привести к неработающим ссылкам . Может быть предпочтительнее генерировать слаг только один раз при создании нового объекта:

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)
дружище
источник
4
у вас есть особый тип модели? почему бы просто не убить CharFields?
Johnd
23
SlugFields установить db_index = True по умолчанию, а также использовать поле формы по умолчанию, которое имеет регулярное выражение проверки для требования допустимых слагов (если они представлены в ModelForm или в администраторе). Вы можете делать эти вещи вручную с помощью CharField, если вы предпочитаете, это только делает намерение вашего кода менее ясным. Кроме того, не забывайте параметр ModelAdmin prepopulate_fields, если вы хотите автоматически заполнять JP на основе администратора.
Карл Мейер
4
Как сказал Дингль ниже в своем ответе, вам необходимо заменить def save(self):с def save(self, *args, **kwargs):тем чтобы избежать от ошибок, появляющихся при написании что - то подобное test.objects.create(q="blah blah blah").
Лиам
6
Помните, что этот код будет обновлять слаг, который каждый сохраняет. Ваш URL будет меняться, и «Классные URIs не меняет» w3.org/Provider/Style/URI.html
дзен
18
slugify()также можно найти в django.utils.text.slugify, не ясно, когда это было добавлено.
mrmagooey
112

Угловой корпус с некоторыми символами utf-8

Пример:

>>> from django.template.defaultfilters import slugify
>>> slugify(u"test ąęśćółń")
u'test-aescon' # there is no "l"

Это можно решить с помощью Unidecode

>>> from unidecode import unidecode
>>> from django.template.defaultfilters import slugify
>>> slugify(unidecode(u"test ąęśćółń"))
u'test-aescoln'
DooBLER
источник
7
utf-8 теперь корректно обрабатывается slugify (в django 1.8.5)
Рик Вестера
Как сказал @RickWestera, теперь это обрабатывается slugify, хотя, если по какой-то причине вы не хотите использовать slugify, проверьте iri_to_uri из django.utils.encoding: docs.djangoproject.com/en/2.0/ref/unicode/…
Эрвол
64

Небольшое исправление к ответу Thepeer: чтобы переопределить save()функцию в модельных классах, лучше добавьте в нее аргументы:

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)

В противном случае test.objects.create(q="blah blah blah")приведет к force_insertошибке (неожиданный аргумент).

лощина
источник
2
Еще одна очень незначительная вещь, которую нужно добавить к ответу thepeer: я бы сделал эту последнюю строку return super(test, self).save(*args, **kwargs). Я думаю, что этот метод возвращается None, и я не знаю никаких планов изменить это, но не вредно возвращать то, что делает метод суперкласса, если он когда-нибудь изменится в будущем.
Дункан Паркс
Пожалуйста, добавьте, что из django.utils.text для этого решения требуется импорт slugify .
Routhinator
1
@Routhinator сделал это
Йонас Грёгер
Вытаскивая некоторые пробные, чтобы спросить, является ли это все еще предпочтительным методом для этого.
sytech
29

Если вы используете интерфейс администратора , чтобы добавить новые элементы модели, вы можете создать ModelAdminв вашем admin.pyи использовать prepopulated_fieldsдля автоматизации внесения слизняка:

class ClientAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('name',)}

admin.site.register(Client, ClientAdmin)

Здесь, когда пользователь вводит значение в форму администратора для nameполя, оно slugбудет автоматически заполнено правильной версией name.

henrym
источник
Мои slugи nameполя имеют переводы. Как я могу сделать это с переводами? Потому что я попытался добавить 'slug_en':('name_en',)и получил ошибку, что атрибут не существует в моей модели.
Patricia
22

В большинстве случаев слаг не должен меняться, поэтому вы действительно хотите рассчитать его только при первом сохранении:

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()
thepeer
источник
6

Используйте prepopulated_fieldsв своем классе администратора:

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

admin.site.register(Article, ArticleAdmin)
Сергей
источник
1
Могли бы вы объяснить? Как админ влияет на проект?
Брайс
5

Если вы не хотите устанавливать для поля слагов значение «Не быть редактируемым», то, я думаю, вы захотите установить для свойств «Пустой» и «Пустой» значение «Ложь». В противном случае вы получите ошибку при попытке сохранить в Admin.

Таким образом, модификация к приведенному выше примеру будет:

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()
Streamweaver
источник
Документы на Editable
стивен
4

Я использую Django 1.7

Создайте SlugField в вашей модели следующим образом:

slug = models.SlugField()

Затем в admin.pyопределение prepopulated_fields;

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}
min2bro
источник
Именно то, что я хотел
Ник