Come faccio a creare una lumaca in Django?


218

Sto cercando di creare un SlugFieldin Django.

Ho creato questo semplice modello:

from django.db import models

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

Quindi faccio questo:

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

Mi aspettavo b-b-b-b.

Risposte:


413

Dovrai usare la funzione slugify.

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

Puoi chiamare slugifyautomaticamente sovrascrivendo il savemetodo:

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)

Tieni presente che quanto sopra causerà la modifica del tuo URL quando il qcampo viene modificato, il che può causare collegamenti interrotti . Potrebbe essere preferibile generare la lumaca solo una volta quando si crea un nuovo oggetto:

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
timido hai un tipo di modello speciale? perché non solo slugify CharFields?
Johnd,

23
SlugFields imposta db_index = True per impostazione predefinita e utilizza anche un campo modulo per impostazione predefinita che ha una regex di convalida per richiedere lumache valide (se rappresentato in un ModelForm o nell'amministratore). Puoi fare queste cose manualmente con un CharField se preferisci, rende solo meno chiara l'intenzione del tuo codice. Inoltre, non dimenticare l'impostazione prepopulate_fields ModelAdmin, se si desidera la prepopolazione automatica basata su JS nell'amministratore.
Carl Meyer,

4
Come Dingle ha detto di seguito nella sua risposta, dovrai sostituirlo def save(self):con def save(self, *args, **kwargs):per evitare errori durante la scrittura di qualcosa del genere test.objects.create(q="blah blah blah").
Liam,

6
Attenzione che questo codice aggiornerà la lumaca che salva. il tuo URL cambierà e "Gli URI fantastici non cambieranno" w3.org/Provider/Style/URI.html
dzen

18
slugify()può anche essere trovato in django.utils.text.slugify, non è chiaro quando è stato aggiunto.
mrmagooey,

112

C'è un caso d'angolo con alcuni caratteri utf-8

Esempio:

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

Questo può essere risolto con Unidecode

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

7
utf-8 ora è gestito correttamente da slugify (in django 1.8.5)
Rick Westera,

Come ha detto @RickWestera, questo è ora gestito da slugify, anche se per qualche motivo non vuoi usare slugify, controlla iri_to_uri da django.utils.encoding: docs.djangoproject.com/en/2.0/ref/unicode/…
Erwol,

64

Una piccola correzione alla risposta di Thepeer: per sovrascrivere la save()funzione nelle classi del modello, aggiungere meglio gli argomenti:

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)

In caso contrario, test.objects.create(q="blah blah blah")si verificherà un force_inserterrore (argomento imprevisto).


2
Un'altra cosa molto minore da aggiungere alla risposta di thepeer: vorrei fare l'ultima riga return super(test, self).save(*args, **kwargs). Penso che questo metodo ritorni Nonee non conosco alcun piano per cambiarlo, ma non fa male restituire ciò che fa il metodo della superclasse nel caso in cui cambi in futuro.
Duncan Parkes,

Si prega di aggiungere che da django.utils.text è richiesta l' importazione di slugify per questa soluzione.
Routhinator

1
@Routhinator l'ha fatto
Jonas Gröger il

Mettere in campo alcuni sensori per chiedere se questo è ancora un metodo preferito per farlo.
sytech,

29

Se stai utilizzando l'interfaccia di amministrazione per aggiungere nuovi elementi del tuo modello, puoi impostare un ModelAdminnel tuo admin.pye utilizzarlo prepopulated_fieldsper automatizzare l'inserimento di una lumaca:

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

admin.site.register(Client, ClientAdmin)

Qui, quando l'utente inserisce un valore nel modulo di amministrazione per il namecampo, questo slugverrà automaticamente popolato con la slugified corretta name.


Il mio sluge i namecampi hanno traduzioni. Come posso farlo con le traduzioni? Perché ho provato ad aggiungere 'slug_en':('name_en',)e ho ricevuto l'errore che l'attributo non esiste nel mio modello.
Patricia,

22

Nella maggior parte dei casi la lumaca non dovrebbe cambiare, quindi vuoi davvero calcolarla solo al primo salvataggio:

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

Utilizzare prepopulated_fieldsnella classe di amministrazione:

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

admin.site.register(Article, ArticleAdmin)

1
Potresti spiegare? In che modo l'amministratore influisce sul progetto?
Bryce,

5

Se non vuoi impostare il campo slug su Non modificabile, credo che vorrai impostare le proprietà Null e Blank su False. Altrimenti riceverai un errore quando provi a salvare in Admin.

Quindi una modifica all'esempio sopra sarebbe:

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

Documenti modificabili
stephen

4

Sto usando Django 1.7

Crea un SlugField nel tuo modello in questo modo:

slug = models.SlugField()

Quindi in admin.pydefinisci prepopulated_fields;

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

Esattamente quello che volevo
Nick,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.