Bagaimana cara membuat siput di Django?


218

Saya mencoba membuat SlugFielddi Django.

Saya membuat model sederhana ini:

from django.db import models

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

Saya kemudian melakukan ini:

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

Saya mengharapkan b-b-b-b.

Jawaban:


413

Anda harus menggunakan fungsi slugify.

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

Anda dapat menelepon slugifysecara otomatis dengan mengganti savemetode:

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)

Perlu diketahui bahwa di atas akan menyebabkan URL Anda berubah ketika qbidang diedit, yang dapat menyebabkan tautan rusak . Mungkin lebih baik untuk menghasilkan siput hanya sekali ketika Anda membuat objek baru:

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
malu memiliki tipe model khusus? mengapa tidak hanya membasmi CharFields?
Johnd

23
SlugFields set db_index = Benar secara default, dan juga menggunakan bidang formulir secara default yang memiliki regex validasi untuk meminta siput yang valid (jika diwakili dalam ModelForm atau di admin). Anda dapat melakukan hal-hal itu secara manual dengan CharField jika Anda mau, itu hanya membuat maksud kode Anda kurang jelas. Juga, jangan lupa pengaturan ModelAdmin prepopulate_fields, jika Anda ingin auto-prepopulate berbasis JS di admin.
Carl Meyer

4
Seperti yang dikatakan Dingle di bawah dalam jawabannya, Anda harus menggantinya def save(self):dengan def save(self, *args, **kwargs):untuk menghindari kesalahan yang terjadi saat menulis sesuatu seperti test.objects.create(q="blah blah blah").
Liam

6
Berhati-hatilah bahwa kode ini akan memperbarui siput yang disimpan masing-masing. url Anda akan berubah, dan "Cool URIs tidak berubah" w3.org/Provider/Style/URI.html
dzen

18
slugify()juga dapat ditemukan di django.utils.text.slugify, tidak jelas kapan ini ditambahkan.
mrmagooey

112

Ada kasus sudut dengan beberapa karakter utf-8

Contoh:

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

Ini dapat diatasi dengan Unidecode

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

7
utf-8 sekarang ditangani dengan benar oleh slugify (dalam django 1.8.5)
Rick Westera

Seperti @RickWestera mengatakan ini sekarang ditangani oleh slugify, walaupun jika karena alasan tertentu Anda tidak ingin menggunakan slugify, periksa iri_to_uri dari django.utils.encoding: docs.djangoproject.com/en/2.0/ref/unicode/…
Erwol

64

Koreksi kecil untuk jawaban Thepeer: Untuk menggantikan save() fungsi di kelas model, lebih baik tambahkan argumen ke dalamnya:

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)

Jika tidak, test.objects.create(q="blah blah blah")akan menghasilkan force_insertkesalahan (argumen yang tidak terduga).


2
Satu hal lagi yang sangat kecil untuk ditambahkan ke jawaban thepeer: Saya akan membuat baris terakhir return super(test, self).save(*args, **kwargs). Saya pikir metode ini kembali None, dan saya tidak tahu ada rencana untuk mengubahnya, tetapi tidak ada salahnya untuk mengembalikan apa yang dilakukan metode superclass kalau-kalau itu berubah di masa depan.
Duncan Parkes

Silakan tambahkan bahwa dari django.utils.text, impor slugify diperlukan untuk solusi ini.
Routhinator

1
@Routhinator melakukannya
Jonas Gröger

Keluarkan beberapa perasa untuk bertanya apakah ini masih merupakan metode yang disukai untuk melakukan ini.
sytech

29

Jika Anda menggunakan antarmuka admin untuk menambahkan item baru dari model Anda, Anda dapat mengatur ModelAdmindi Anda admin.pydan menggunakannya prepopulated_fieldsuntuk secara otomatis memasukkan siput:

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

admin.site.register(Client, ClientAdmin)

Di sini, ketika pengguna memasukkan nilai dalam formulir admin untuk namebidang, maka slugakan secara otomatis diisi dengan slugified yang benar name.


Bidang saya slugdan namememiliki terjemahan. Bagaimana saya bisa melakukannya dengan terjemahan? Karena saya sudah mencoba menambahkan 'slug_en':('name_en',)dan mendapatkan kesalahan bahwa atribut tidak ada dalam model saya.
patricia

22

Dalam kebanyakan kasus siput tidak boleh berubah, jadi Anda benar-benar hanya ingin menghitungnya pada penyimpanan pertama:

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

Gunakan prepopulated_fieldsdi kelas admin Anda:

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

admin.site.register(Article, ArticleAdmin)

1
Bisakah Anda jelaskan? Bagaimana admin mempengaruhi proyek?
Bryce

5

Jika Anda tidak ingin mengatur slugfield menjadi Tidak dapat diedit, maka saya yakin Anda ingin mengatur properti Null dan Blank menjadi False. Kalau tidak, Anda akan mendapatkan kesalahan saat mencoba menyimpan di Admin.

Jadi modifikasi pada contoh di atas akan menjadi ::

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

Documents on diedit
stephen

4

Saya menggunakan Django 1.7

Buat SlugField dalam model Anda seperti ini:

slug = models.SlugField()

Kemudian di admin.pydefinisikan prepopulated_fields;

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

Apa yang saya inginkan
Nick

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.