Wie erstelle ich eine Schnecke in Django?

218

Ich versuche ein SlugFieldin Django zu erstellen .

Ich habe dieses einfache Modell erstellt:

from django.db import models

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

Ich mache dann folgendes:

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

Ich hatte erwartet b-b-b-b.

Johnd
quelle

Antworten:

413

Sie müssen die Slugify-Funktion verwenden.

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

Sie können slugifyautomatisch aufrufen , indem Sie die saveMethode überschreiben :

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)

Beachten Sie, dass sich Ihre URL beim qBearbeiten des Felds ändert , was zu fehlerhaften Links führen kann . Es kann vorzuziehen sein, den Slug nur einmal zu generieren, wenn Sie ein neues Objekt erstellen:

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)
Kumpel
quelle
4
schüchtern haben einen speziellen Modelltyp? Warum nicht einfach CharFields schlagen?
Johnd
23
SlugFields setzen standardmäßig db_index = True und verwenden standardmäßig ein Formularfeld mit einer Validierungsregex, um gültige Slugs zu erfordern (sofern in einer ModelForm oder im Administrator dargestellt). Sie können diese Dinge manuell mit einem CharField ausführen, wenn Sie dies bevorzugen. Dadurch wird nur die Absicht Ihres Codes weniger klar. Vergessen Sie auch nicht die Einstellung prepopulate_fields ModelAdmin, wenn Sie JS-basiertes automatisches Prepopulate im Administrator wünschen.
Carl Meyer
4
Wie Dingle unter sagte in seiner Antwort, müssen Sie ersetzen def save(self):mit , def save(self, *args, **kwargs):um Fehler zu vermeiden von geworfen werden , wenn so etwas zu schreiben test.objects.create(q="blah blah blah").
Liam
6
Beachten Sie, dass dieser Code den Slug bei jedem Speichern aktualisiert. Ihre URL wird sich ändern und "Coole URIs ändern sich nicht" w3.org/Provider/Style/URI.html
dzen
18
slugify()kann auch in gefunden werden django.utils.text.slugify, nicht klar, wann dies hinzugefügt wurde.
Mrmagooey
112

Es gibt einen Eckfall mit einigen utf-8-Zeichen

Beispiel:

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

Dies kann mit Unidecode gelöst werden

>>> from unidecode import unidecode
>>> from django.template.defaultfilters import slugify
>>> slugify(unidecode(u"test ąęśćółń"))
u'test-aescoln'
DooBLER
quelle
7
utf-8 wird jetzt korrekt von slugify (in django 1.8.5) behandelt
Rick Westera
Wie @RickWestera sagte, wird dies jetzt von slugify erledigt. Wenn Sie jedoch aus irgendeinem Grund slugify nicht verwenden möchten, überprüfen Sie iri_to_uri unter django.utils.encoding: docs.djangoproject.com/de/2.0/ref/unicode/…
Erwol
64

Eine kleine Korrektur zu Thepeers Antwort: Um die save()Funktion in Modellklassen zu überschreiben , fügen Sie besser Argumente hinzu:

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)

Andernfalls test.objects.create(q="blah blah blah")führt dies zu einem force_insertFehler (unerwartetes Argument).

Dingle
quelle
2
Eine weitere sehr kleine Sache, die der Antwort von thepeer hinzugefügt werden sollte: Ich würde diese letzte Zeile machen return super(test, self).save(*args, **kwargs). Ich denke, diese Methode kehrt zurück None, und ich kenne keine Pläne, dies zu ändern, aber es schadet nicht, zurückzugeben, was die Methode der Oberklasse tut, falls sie sich irgendwann in der Zukunft ändert.
Duncan Parkes
Bitte fügen Sie hinzu, dass für diese Lösung der Import von django.utils.text slugify erforderlich ist.
Routhinator
1
@ Routhinator hat es geschafft
Jonas Gröger
Stellen Sie einige Fühler heraus, um zu fragen, ob dies immer noch eine bevorzugte Methode ist.
Sytech
29

Wenn Sie die Administrationsoberfläche verwenden, um neue Elemente Ihres Modells hinzuzufügen, können Sie ein ModelAdminin Ihrem einrichten admin.pyund verwenden, prepopulated_fieldsum die Eingabe eines Slugs zu automatisieren:

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

admin.site.register(Client, ClientAdmin)

Wenn der Benutzer im Administrationsformular einen Wert für das nameFeld slugeingibt , wird dieser automatisch mit dem richtigen Slugified gefüllt name.

Henrym
quelle
Meine slugund nameFelder haben Übersetzungen. Wie kann ich das mit Übersetzungen machen? Weil ich versucht habe hinzuzufügen 'slug_en':('name_en',)und den Fehler erhalten habe, dass das Attribut in meinem Modell nicht vorhanden ist.
Patricia
22

In den meisten Fällen sollte sich der Slug nicht ändern, daher möchten Sie ihn wirklich nur beim ersten Speichern berechnen:

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
quelle
6

Verwendung prepopulated_fieldsin Ihrer Admin-Klasse:

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

admin.site.register(Article, ArticleAdmin)
sergey
quelle
1
Könntest du erklären? Wie wirkt sich der Administrator auf das Projekt aus?
Bryce
5

Wenn Sie das Slugfield nicht auf Nicht bearbeitbar setzen möchten, sollten Sie die Eigenschaften Null und Leer auf False setzen. Andernfalls wird beim Speichern in Admin eine Fehlermeldung angezeigt.

Eine Modifikation des obigen Beispiels wäre also ::

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
quelle
Docs on editierbar
Stephen
4

Ich benutze Django 1.7

Erstellen Sie ein SlugField in Ihrem Modell wie folgt:

slug = models.SlugField()

Dann in admin.pydefinieren prepopulated_fields;

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}
min2bro
quelle
Genau das, was ich wollte
Nick