django admin - เพิ่มฟิลด์แบบกำหนดเองที่ไม่ได้เป็นส่วนหนึ่งของโมเดล


106

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

ฉันจะทำเช่นนั้นได้อย่างไร?

UPDATE: โดยพื้นฐานแล้วสิ่งที่ฉันกำลังทำคือการสร้างนิพจน์ทางคณิตศาสตร์หรือสตริงจากสัญลักษณ์ผู้ใช้จะเลือกสัญลักษณ์ (นี่คือฟิลด์ที่กำหนดเองซึ่งไม่ได้เป็นส่วนหนึ่งของโมเดล) และเมื่อเขาคลิกบันทึกฉันจะสร้างการแสดงนิพจน์สตริงจาก รายการสัญลักษณ์และเก็บไว้ในฐานข้อมูล ฉันไม่ต้องการให้สัญลักษณ์เป็นส่วนหนึ่งของโมเดลและ DB แต่เป็นนิพจน์สุดท้ายเท่านั้น

คำตอบ:


156

ไม่ว่าจะใน admin.py ของคุณหรือใน form.py แยกต่างหากคุณสามารถเพิ่มคลาส ModelForm จากนั้นประกาศฟิลด์เพิ่มเติมของคุณภายในที่คุณทำตามปกติ ฉันยังให้ตัวอย่างว่าคุณจะใช้ค่าเหล่านี้ใน form.save () ได้อย่างไร:

from django import forms
from yourapp.models import YourModel


class YourModelForm(forms.ModelForm):

    extra_field = forms.CharField()

    def save(self, commit=True):
        extra_field = self.cleaned_data.get('extra_field', None)
        # ...do something with extra_field here...
        return super(YourModelForm, self).save(commit=commit)

    class Meta:
        model = YourModel

หากต้องการให้ช่องพิเศษปรากฏในผู้ดูแลระบบให้ทำดังนี้

  1. แก้ไข admin.py ของคุณและตั้งค่าคุณสมบัติของฟอร์มเพื่ออ้างถึงแบบฟอร์มที่คุณสร้างไว้ด้านบน
  2. รวมฟิลด์ใหม่ของคุณในการประกาศฟิลด์หรือชุดฟิลด์ของคุณ

แบบนี้:

class YourModelAdmin(admin.ModelAdmin):

    form = YourModelForm

    fieldsets = (
        (None, {
            'fields': ('name', 'description', 'extra_field',),
        }),
    )

UPDATE: ใน django 1.8 คุณต้องเพิ่มfields = '__all__'metaclass ของ YourModelForm


2
ใช่ฉันอยากรู้เหตุผลจริงๆ
วิษณุ

13
คุณควรเพิ่มfields = '__all__'ในMetaชั้นเรียนของคุณมิฉะนั้น django จะบ่น:Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is deprecated
IsaacKleiner

1
@sthzg เพราะมันไม่ถูกต้อง มันทำให้ฉันมีข้อผิดพลาด:YourModelAdmin.list_display[0], 'extra_field' is not a callable or an attribute of 'YourModelAdmin' or found in the model 'YourModel'.
Cerin

7
หากมีเหตุผลบางอย่างที่คุณจะได้รับการAttributeError: Unable to lookup "extra_field"...พยายามเพิ่มlabelให้กับextra_fieldนิยาม ดูเหมือนว่า django จะพยายาม "เดา" ป้ายกำกับโดยดูที่ModelและModelAdminสำหรับนิยามแอตทริบิวต์ดังกล่าว
alxs

1
สิ่งนี้ทำงานได้อย่างสวยงามหาก extra_field เป็น CharField () ถ้ามันเป็น hiddenField แม้ว่า [ใน Django 1.11] Unknown field(s) (extra_field) specified for YourModel. Check fields/fieldsets/exclude attributes of class YourModelAdmin.ข้อผิดพลาดที่สร้างขึ้น วิธีแก้ปัญหาคือextra_field = forms.CharField(widget=forms.HiddenInput())
kakoma

35

เป็นไปได้ที่จะทำในผู้ดูแลระบบ แต่ไม่มีวิธีที่ตรงไปตรงมามากนัก นอกจากนี้ฉันต้องการคำแนะนำในการใช้ตรรกะทางธุรกิจส่วนใหญ่ในโมเดลของคุณดังนั้นคุณจะไม่ต้องพึ่งพา Django Admin

บางทีมันอาจจะง่ายกว่า (และอาจจะดีกว่าด้วยซ้ำ) ถ้าคุณมีสองฟิลด์แยกกันในแบบจำลองของคุณ จากนั้นเพิ่มวิธีการในแบบจำลองของคุณที่รวมเข้าด้วยกัน

ตัวอย่างเช่น:

class MyModel(models.model):

    field1 = models.CharField(max_length=10)
    field2 = models.CharField(max_length=10)

    def combined_fields(self):
        return '{} {}'.format(self.field1, self.field2)

จากนั้นในผู้ดูแลระบบคุณสามารถเพิ่มcombined_fields()เป็นฟิลด์แบบอ่านอย่างเดียว:

class MyModelAdmin(models.ModelAdmin):

    list_display = ('field1', 'field2', 'combined_fields')
    readonly_fields = ('combined_fields',)

    def combined_fields(self, obj):
        return obj.combined_fields()

หากคุณต้องการจัดเก็บcombined_fieldsในฐานข้อมูลคุณสามารถบันทึกได้เมื่อคุณบันทึกโมเดล:

def save(self, *args, **kwargs):
    self.field3 = self.combined_fields()
    super(MyModel, self).save(*args, **kwargs)

4
ขอบคุณสำหรับคำตอบ แต่นี่ไม่ใช่สิ่งที่ฉันกำลังมองหา ฉันไม่ต้องการให้บันทึกฟิลด์ที่กำหนดเองในฐานข้อมูลเฉพาะสตริงจากการคำนวณ โดยพื้นฐานแล้วสิ่งที่ฉันกำลังทำคือการสร้างนิพจน์ทางคณิตศาสตร์หรือสตริงจากสัญลักษณ์ผู้ใช้จะเลือกสัญลักษณ์ (นี่คือฟิลด์แบบกำหนดเองที่ไม่ได้เป็นส่วนหนึ่งของโมเดล) และเมื่อเขาคลิกบันทึกฉันจะสร้างการแสดงนิพจน์สตริงจากรายการ สัญลักษณ์และจัดเก็บไว้ในฐานข้อมูล
michalv82

@ michalv82 นอกจากนี้คุณยังสามารถบันทึกลงในฐานข้อมูลด้วยsave()วิธีการของโมเดลตรวจสอบการอัปเดตคำตอบของฉัน
gitaarik

1
ขอบคุณอีกครั้ง แต่ปัญหาคือฉันไม่ต้องการเก็บฟิลด์ที่รวมฟิลด์สุดท้าย (เช่นสัญลักษณ์) ฉันแค่ต้องการให้สตริงสุดท้ายถูกบันทึก
michalv82

เป็นปัญหาในการบันทึก 2 ช่องหรือไม่? บางทีอาจเป็นประโยชน์หากคุณต้องการทราบว่าฟิลด์รวมสร้างขึ้นได้อย่างไร
gitaarik

6
ขอบคุณอีกครั้ง แต่ไม่ใช่ 2 ช่องอาจจะมากกว่านี้ อีกครั้งฉันไม่ต้องการเก็บไว้ใน DB ดังนั้นวิธีนี้จึงไม่สามารถใช้ได้กับฉัน
michalv82

5

Django 2.1.1 คำตอบหลักทำให้ฉันตอบคำถามได้ครึ่งทาง มันไม่ได้ช่วยให้ฉันบันทึกผลลัพธ์ลงในฟิลด์ในแบบจำลองจริงของฉัน ในกรณีของฉันฉันต้องการฟิลด์ข้อความที่ผู้ใช้สามารถป้อนข้อมูลได้จากนั้นเมื่อเกิดการบันทึกข้อมูลจะถูกประมวลผลและผลลัพธ์จะใส่ลงในฟิลด์ในโมเดลและบันทึก ในขณะที่คำตอบเดิมแสดงวิธีรับค่าจากฟิลด์พิเศษ แต่ก็ไม่ได้แสดงวิธีบันทึกกลับไปที่โมเดลอย่างน้อยใน Django 2.1.1

สิ่งนี้รับค่าจากฟิลด์ที่กำหนดเองที่ไม่ถูกผูกไว้ประมวลผลและบันทึกลงในฟิลด์คำอธิบายจริงของฉัน:

class WidgetForm(forms.ModelForm):
    extra_field = forms.CharField(required=False)

    def processData(self, input):
        # example of error handling
        if False:
            raise forms.ValidationError('Processing failed!')

        return input + " has been processed"

    def save(self, commit=True):
        extra_field = self.cleaned_data.get('extra_field', None)

        # self.description = "my result" note that this does not work

        # Get the form instance so I can write to its fields
        instance = super(WidgetForm, self).save(commit=commit)

        # this writes the processed data to the description field
        instance.description = self.processData(extra_field)

        if commit:
            instance.save()

        return instance

    class Meta:
        model = Widget
        fields = "__all__"

4

คุณสามารถสร้างเทมเพลตผู้ดูแลระบบใหม่ได้ตลอดเวลาและทำสิ่งที่คุณต้องการใน admin_view ของคุณ (แทนที่ผู้ดูแลระบบเพิ่ม url ใน admin_view ของคุณ):

 url(r'^admin/mymodel/mymodel/add/$' , 'admin_views.add_my_special_model')

3

หากคุณต้องการเก็บเฉพาะฟิลด์ที่รวมไว้ในโมเดลเท่านั้นไม่ใช่สองฟิลด์ที่แยกจากกันคุณสามารถทำสิ่งนี้ได้:

ฉันไม่เคยทำอะไรแบบนี้ดังนั้นฉันจึงไม่แน่ใจว่ามันจะออกมาเป็นอย่างไร

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