Як створити кулі в 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.

Відповіді:


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?
Джонд

23
SlugFields встановити db_index = True за замовчуванням, а також використовувати поле форми за замовчуванням, у якому є регекс перевірки, щоб вимагати дійсних слуг (якщо вони представлені в ModelForm або в адміністраторі). Ви можете робити ці речі вручну за допомогою CharField, якщо ви хочете, це просто робить намір вашого коду менш зрозумілим. Крім того, не забувайте налаштування prepopulate_fields ModelAdmin, якщо ви хочете, щоб в адміністраторі було засновано JS на основі JS.
Карл Мейєр

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'

7
utf-8 тепер правильно обробляється slugify (у django 1.8.5)
Rick Westera

Як сказав @RickWestera, це тепер обробляється slugify, хоча якщо з якоїсь причини ви не хочете використовувати slugify, перевірте iri_to_uri з django.utils.encoding: docs.djangoproject.com/en/2.0/ref/unicode/…
Ервол

64

Невелика корекція відповіді Тепера: Щоб переотримати 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, і я не знаю жодних планів змінити це, але не шкода повернути те, що робить метод суперкласу, якщо він зміниться десь у майбутньому.
Duncan Parkes

Будь ласка, додайте, що для цього рішення потрібен слуховий імпорт з django.utils.text .
Ротатор

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.


Мої 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()

6

Використання prepopulated_fieldsу вашому класі адміністратора:

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

admin.site.register(Article, ArticleAdmin)

1
Чи можете ви пояснити? Як адміністратор впливає на проект?
Брайс

5

Якщо ви не хочете, щоб поле slugfield було не для редагування, я вважаю, що ви хочете встановити для властивостей Null and Blank значення False. Інакше ви отримаєте помилку при спробі збереження в адміністраторі.

Отже, модифікація вищевказаного прикладу буде:

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

Документи про редагування
Stephen

4

Я використовую Django 1.7

Створіть SlugField у своїй моделі так:

slug = models.SlugField()

Потім у admin.pyвизначенні prepopulated_fields;

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

Саме те, що я хотів
Нік

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.