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.