ฉันจะสร้างกระสุนใน Django ได้อย่างไร


218

ฉันพยายามที่จะสร้างSlugFieldใน Django

ฉันสร้างแบบจำลองง่ายๆนี้:

from django.db import models

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

จากนั้นฉันทำสิ่งนี้:

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

b-b-b-bผมคาดหวังว่า

คำตอบ:


413

คุณจะต้องใช้ฟังก์ชัน slugify

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

คุณสามารถโทรslugifyโดยอัตโนมัติโดยการแทนที่saveเมธอด:

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)

โปรดทราบว่าข้อมูลด้านบนจะทำให้ URL ของคุณเปลี่ยนเมื่อqแก้ไขฟิลด์ซึ่งอาจทำให้ลิงค์เสียหาย มันอาจจะดีกว่าที่จะสร้างกระสุนเพียงครั้งเดียวเมื่อคุณสร้างวัตถุใหม่:

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
อายมีรูปแบบพิเศษไหม? เหตุใดจึงไม่เพียงทำให้ CharField ลดความอ้วนลง?
Johnd

23
SlugFields set db_index = True โดยค่าเริ่มต้นและยังใช้เขตข้อมูลแบบฟอร์มโดยค่าเริ่มต้นที่มีการตรวจสอบ regex เพื่อต้องการทากที่ถูกต้อง (ถ้าแสดงใน ModelForm หรือในผู้ดูแลระบบ) คุณสามารถทำสิ่งเหล่านั้นด้วยตนเองด้วย CharField ถ้าคุณต้องการมันแค่ทำให้ความตั้งใจของรหัสของคุณชัดเจนน้อยลง นอกจากนี้อย่าลืมการตั้งค่า prepopulate_fields ModelAdmin หากคุณต้องการการเติมอัตโนมัติโดยใช้ JS ในผู้ดูแลระบบ
Carl Meyer

4
ในฐานะที่เป็นหุบเขากล่าวว่าด้านล่างในคำตอบของเขาคุณจะต้องแทนที่def save(self):ด้วยเพื่อที่จะหลีกเลี่ยงข้อผิดพลาดจากการถูกโยนเมื่อเขียนสิ่งที่ต้องการdef save(self, *args, **kwargs): test.objects.create(q="blah blah blah")
เลียม

6
ระวังว่ารหัสนี้จะอัปเดตกระสุนแต่ละครั้งจะบันทึก url ของคุณจะเปลี่ยนไปและ "Cool URIs จะไม่เปลี่ยน" w3.org/Provider/Style/URI.html
dzen

18
slugify()สามารถพบได้ในdjango.utils.text.slugifyไม่ชัดเจนเมื่อเพิ่มนี้
mrmagooey

112

มีตัวพิมพ์มุมที่มีอักขระ utf-8 บางตัว

ตัวอย่าง:

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

สิ่งนี้สามารถแก้ไขได้ด้วยUnidecode

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

7
utf-8 ได้รับการจัดการอย่างถูกต้องโดย slugify (ใน django 1.8.5)
Rick Westera

ดังที่ @RickWestera กล่าวว่าสิ่งนี้ได้รับการจัดการโดย slugify แม้ว่าด้วยเหตุผลบางอย่างที่คุณไม่ต้องการใช้ slugify ให้ตรวจสอบ iri_to_uri จาก django.utils.encoding: docs.djangoproject.com/en/2.0/ref/unicode/
Erwol

64

การแก้ไขคำตอบของ Thepeer เพียงเล็กน้อย: หากต้องการแทนที่save()ฟังก์ชันในคลาสโมเดลให้เพิ่มอาร์กิวเมนต์ที่ดีกว่า:

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)

มิฉะนั้นtest.objects.create(q="blah blah blah")จะส่งผลให้เกิดforce_insertข้อผิดพลาด (อาร์กิวเมนต์ที่ไม่คาดคิด)


2
สิ่งหนึ่งที่เพิ่มเติมน้อยมากที่จะเพิ่มคำตอบของ thepeer: return super(test, self).save(*args, **kwargs)ฉันจะให้ที่บรรทัดสุดท้าย ฉันคิดว่าวิธีนี้จะส่งคืนNoneและฉันไม่รู้ว่าจะมีการเปลี่ยนแปลงใด ๆ แต่ก็ไม่เป็นอันตรายที่จะกลับมาใช้วิธีที่ Superclass ทำในกรณีที่มันเปลี่ยนไปในอนาคต
Duncan Parkes

โปรดเพิ่มสิ่งนั้นจาก django.utils.text slugify นำเข้าสำหรับโซลูชันนี้
Routhinator

1
@Routhinator ทำเช่นนั้น
Jonas Gröger

ให้ความรู้สึกบางอย่างเพื่อถามว่านี่ยังเป็นวิธีที่เหมาะสมสำหรับการทำสิ่งนี้หรือไม่
sytech

29

หากคุณกำลังใช้อินเตอร์เฟซผู้ดูแลระบบเพื่อเพิ่มรายการใหม่ของรูปแบบของคุณคุณสามารถตั้งค่าModelAdminในของคุณadmin.pyและใช้ประโยชน์prepopulated_fieldsได้โดยอัตโนมัติการป้อนกระสุน:

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

admin.site.register(Client, ClientAdmin)

นี่คือเมื่อผู้ใช้ป้อนค่าในรูปแบบผู้ดูแลระบบสำหรับnameข้อมูลที่slugจะมีประชากรโดยอัตโนมัติด้วย nameslugified


ฉันslugและnameสาขามีการแปล ฉันจะทำเช่นนั้นกับการแปลได้อย่างไร เนื่องจากฉันพยายามเพิ่ม'slug_en':('name_en',)และได้รับข้อผิดพลาดที่ไม่มีคุณสมบัติในโมเดลของฉัน
patricia

22

ในกรณีส่วนใหญ่กระสุนไม่ควรเปลี่ยนดังนั้นคุณต้องการคำนวณในการบันทึกครั้งแรกเท่านั้น:

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

ใช้prepopulated_fieldsในระดับผู้ดูแลระบบของคุณ:

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

admin.site.register(Article, ArticleAdmin)

1
คุณช่วยอธิบายได้ไหม ผู้ดูแลระบบส่งผลต่อโครงการอย่างไร
ไบรซ์

5

หากคุณไม่ต้องการตั้งค่า slugfield เป็นไม่สามารถแก้ไขได้ฉันเชื่อว่าคุณจะต้องการตั้งค่าคุณสมบัติ Null และ Blank เป็น False มิฉะนั้นคุณจะได้รับข้อผิดพลาดเมื่อพยายามบันทึกในผู้ดูแลระบบ

ดังนั้นการปรับเปลี่ยนตัวอย่างข้างต้นจะเป็น ::

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

เอกสารที่แก้ไขได้
stephen

4

ฉันใช้ Django 1.7

สร้าง SlugField ในโมเดลของคุณเช่นนี้:

slug = models.SlugField()

จากนั้นในการadmin.pyกำหนดprepopulated_fields;

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

สิ่งที่ฉันต้องการอย่างยอดเยี่ยม
นิค

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.