Jak utworzyć ślimak w Django?


218

Próbuję utworzyć SlugFieldw Django.

Stworzyłem ten prosty model:

from django.db import models

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

Następnie robię to:

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

Oczekiwałem b-b-b-b.

Odpowiedzi:


413

Musisz użyć funkcji slugify.

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

Możesz wywoływać slugifyautomatycznie, zastępując savemetodę:

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)

Należy pamiętać, że powyższe spowoduje zmianę adresu URL podczas qedycji pola, co może spowodować uszkodzenie linków . Podczas tworzenia nowego obiektu może być wskazane wygenerowanie ślimaka tylko raz:

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
nieśmiały masz specjalny typ modelu? dlaczego nie po prostu slugify CharFields?
— Johnd

23
SlugFields ustawia domyślnie wartość db_index = True, a także domyślnie używa pola formularza, które zawiera wyrażenie sprawdzające poprawność, aby wymagać prawidłowych informacji o pracy (jeśli są reprezentowane w ModelForm lub w adminie). Możesz to zrobić ręcznie za pomocą CharField, jeśli wolisz, tylko zmniejsza to intencję twojego kodu. Nie zapomnij również o ustawieniu ModelAdmin prepopulate_fields, jeśli chcesz, aby administrator administrował automatycznym prepopulowaniem opartym na JS.
— Carl Meyer

4
Jak powiedział poniżej Dingle w swojej odpowiedzi, trzeba wymienić def save(self):z def save(self, *args, **kwargs):aby uniknąć błędów z wyrzucane pisząc coś takiego test.objects.create(q="blah blah blah").
— Liam

6
Uważaj, aby ten kod aktualizował ślimak przy każdym zapisywaniu. Twój adres URL będzie zmienić, a „Cool URI nie zmieniają” w3.org/Provider/Style/URI.html
— Dzen

18
slugify()można również znaleźć w django.utils.text.slugify, nie jest jasne, kiedy to zostało dodane.
— mrmagooey

112

Istnieje narożnik z niektórymi znakami utf-8

Przykład:

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

Można to rozwiązać za pomocą Unidecode

>>> from unidecode import unidecode
>>> from django.template.defaultfilters import slugify
>>> slugify(unidecode(u"test ąęśćółń"))
u'test-aescoln'

7
utf-8 jest teraz poprawnie obsługiwany przez slugify (w django 1.8.5)
— Rick Westera

Jak powiedział @RickWestera, teraz jest to obsługiwane przez slugify, chociaż jeśli z jakiegoś powodu nie chcesz używać slugify, sprawdź iri_to_uri z django.utils.encoding: docs.djangoproject.com/en/2.0/ref/unicode/…
— Erwol

64

Mała korekta odpowiedzi Thepeera: Aby zastąpić save()funkcję w klasach modeli, lepiej dodaj do niej argumenty:

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)

W przeciwnym razie test.objects.create(q="blah blah blah")spowoduje force_insertbłąd (nieoczekiwany argument).


2
Jeszcze jedna drobna rzecz, którą należy dodać do odpowiedzi typera: Chciałbym zrobić ostatnią linię return super(test, self).save(*args, **kwargs). Myślę, że ta metoda powraca Nonei nie wiem o żadnych planach jej zmiany, ale nie szkodzi zwróceniu tego, co robi metoda nadklasy na wypadek, gdyby w przyszłości uległa zmianie.
— Duncan Parkes,

Dodaj, że z tego django.utils.text import jest wymagany slugify .
— Routhinator

1
@Routhinator to zrobił
— Jonas Gröger

Zgłaszając pytania, czy wciąż jest to preferowana metoda.
— sytech

29

Jeśli używasz interfejsu administratora, aby dodać nowe elementy swojego modelu, możesz skonfigurować ModelAdminw swoim admin.pyi wykorzystać prepopulated_fieldsdo zautomatyzowania wprowadzania ślimaka:

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

admin.site.register(Client, ClientAdmin)

Tutaj, gdy użytkownik wpisze wartość w formularzu administratora dla namepola, slugzostanie on automatycznie wypełniony poprawnym slugified name.


Moje slugi namepola mają tłumaczenia. Jak mogę to zrobić z tłumaczeniami? Ponieważ próbowałem dodać 'slug_en':('name_en',)błąd, ale ten atrybut nie istnieje w moim modelu.
— patricia

22

W większości przypadków ślimak nie powinien się zmienić, więc naprawdę chcesz go obliczyć tylko przy pierwszym zapisie:

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

Użyj prepopulated_fieldsw swojej klasie administratora:

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

admin.site.register(Article, ArticleAdmin)

1
Czy możesz wytłumaczyć? Jak administrator wpływa na projekt?
— Bryce

5

Jeśli nie chcesz ustawić slugfield na Nie można edytować, to uważam, że będziesz chciał ustawić właściwości Null i Blank na False. W przeciwnym razie wystąpi błąd podczas próby zapisania w Administratorze.

Zatem modyfikacją powyższego przykładu byłoby:

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

Dokumenty na temat edycji
— Stephen

4

Używam Django 1.7

Utwórz SlugField w swoim modelu w następujący sposób:

slug = models.SlugField()

Następnie admin.pyzdefiniuj prepopulated_fields;

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

Dokładnie to, czego chciałem
— Nick

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.