Django-Admin: CharField เป็น TextArea


88

ฉันมี

class Cab(models.Model):
    name  = models.CharField( max_length=20 )
    descr = models.CharField( max_length=2000 )

class Cab_Admin(admin.ModelAdmin):
    ordering     = ('name',)
    list_display = ('name','descr', )
    # what to write here to make descr using TextArea?

admin.site.register( Cab, Cab_Admin )

วิธีกำหนดวิดเจ็ต TextArea ให้กับฟิลด์ 'descr' ในอินเทอร์เฟซผู้ดูแลระบบ

อัปเดต:
ในส่วนติดต่อผู้ดูแลระบบเท่านั้น!

เป็นความคิดที่ดีที่จะใช้ ModelForm


3
คำตอบที่ได้รับการยอมรับคือ overkill มากสำหรับจุดประสงค์ของ modficiation เพียงช่องเดียว! คนปฏิบัติตามคำตอบนี้โดย Carl Meyer เพื่อวัตถุประสงค์ในการใช้งานง่าย: stackoverflow.com/questions/430592/…
andilabs

คำตอบ:


99

คุณจะต้องสร้างforms.ModelFormที่จะอธิบายว่าคุณต้องการให้descrฟิลด์แสดงอย่างไรจากนั้นบอกadmin.ModelAdminให้ใช้แบบฟอร์มนั้น ตัวอย่างเช่น:

from django import forms
class CabModelForm( forms.ModelForm ):
    descr = forms.CharField( widget=forms.Textarea )
    class Meta:
        model = Cab

class Cab_Admin( admin.ModelAdmin ):
    form = CabModelForm

formแอตทริบิวต์ของadmin.ModelAdminการบันทึกไว้ในเอกสาร Django อย่างเป็นทางการ นี่คือหนึ่งในสถานที่ที่จะมอง


6
สำหรับการเปลี่ยนวิดเจ็ตฟอร์มคุณไม่จำเป็นต้องสร้างแบบฟอร์มทั้งหมดของคุณเอง คุณสามารถแทนที่formfield_for_dbfieldของคุณModelAdminได้ดูคำตอบของฉันด้านล่าง
Carl Meyer

1
สิ่งนี้ให้django.core.exceptions.ImproperlyConfigured: Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is prohibited
John Wu

4
เริ่มต้นจาก Django 1.7 คุณต้องเพิ่มยังอยู่ภายใต้fields = '__all__' class Meta:
skoll

2
คุณไม่จำเป็นต้องสร้างแบบฟอร์มด้วยตัวเองคุณสามารถแทนที่get_formวิธีการได้ ดูคำตอบของฉัน
x-yuri

วิธีการบีเตอร์คือการใช้ Meta class Meta: model = Message widgets = {'text': form.Textarea (attrs = {'cols': 80, 'row': 20}),}
Amulya Acharya

58

สำหรับกรณีนี้ตัวเลือกที่ดีที่สุดอาจเป็นเพียงการใช้ TextField แทน CharField ในโมเดลของคุณ คุณยังสามารถแทนที่formfield_for_dbfieldเมธอดของModelAdminชั้นเรียนของคุณ:

class CabAdmin(admin.ModelAdmin):
    def formfield_for_dbfield(self, db_field, **kwargs):
        formfield = super(CabAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == 'descr':
            formfield.widget = forms.Textarea(attrs=formfield.widget.attrs)
        return formfield

มีข้อเสียในเรื่องนี้เมื่อเทียบกับคำตอบที่เลือกหรือไม่? สิ่งนี้ดูสะอาดกว่าในการนำไปใช้เนื่องจากเราไม่จำเป็นต้องสร้าง ModelForm ใหม่ ...
Filipe Pina

3
แทนที่formfield.widget = forms.Textarea()ด้วยformfield.widget = forms.Textarea(attrs=formfield.widget.attrs)เพื่อให้แอตทริบิวต์ทั้งหมดสร้างขึ้นโดยอัตโนมัติสำหรับ TextField ขอบคุณ!
Filipe Pina

2
ฉันไม่รู้ว่าทำไมคำตอบอื่นถึงได้รับการยอมรับจากคำตอบนี้ ฉันคิดว่าถ้าสิ่งที่คุณทำคือการเปลี่ยนวิดเจ็ตมันจะง่ายกว่านี้ แต่อย่างใดอย่างหนึ่งจะทำงานได้ดี
Carl Meyer

สิ่งนี้ทำงานได้อย่างสมบูรณ์ขอบคุณ การเรียกใช้ super () ดูเหมือนจะดูละเอียดไปหน่อยมีวิธีที่ง่ายกว่านี้ไหม
rjh

2
@rjh ใน py3 คุณสามารถกำจัดทุกอย่างภายใน parens super()และการใช้งานเพียงแค่ อย่างอื่นไม่
Carl Meyer

33

Ayaz มีจุดที่ค่อนข้างชัดเจนยกเว้นการเปลี่ยนแปลงเล็กน้อย (?!):

class MessageAdminForm(forms.ModelForm):
    class Meta:
        model = Message
        widgets = {
            'text': forms.Textarea(attrs={'cols': 80, 'rows': 20}),
        }

class MessageAdmin(admin.ModelAdmin):
    form = MessageAdminForm
admin.site.register(Message, MessageAdmin)

ดังนั้นคุณไม่จำเป็นต้องกำหนดเขตข้อมูลใหม่ใน ModelForm เพื่อเปลี่ยนวิดเจ็ตเพียงตั้งค่าคำสั่งวิดเจ็ตใน Meta


1
สิ่งนี้ยังคงคุณสมบัติ "อัตโนมัติ" ไว้มากกว่าคำตอบของ Ayaz แต่มีเคล็ดลับในการตรวจสอบความยาวฟิลด์ด้วยหรือไม่?
Filipe Pina

14

คุณสามารถ subclass ฟิลด์ของคุณเองด้วยformfieldวิธีการที่จำเป็น:

class CharFieldWithTextarea(models.CharField):

    def formfield(self, **kwargs):
        kwargs.update({"widget": forms.Textarea})
        return super(CharFieldWithTextarea, self).formfield(**kwargs)

สิ่งนี้จะมีผลกับทุกรูปแบบที่สร้างขึ้น


9

คุณไม่จำเป็นต้องสร้างคลาสฟอร์มด้วยตัวเอง:

from django.contrib import admin
from django import forms

class MyModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        kwargs['widgets'] = {'descr': forms.Textarea}
        return super().get_form(request, obj, **kwargs)

admin.site.register(MyModel, MyModelAdmin)

ดูModelAdmin.get_form


7

แทนที่จะmodels.CharFieldใช้ a ให้ใช้models.TextFieldสำหรับdescr.


4
น่าเสียดายที่ max_length = ถูกละเว้นโดย Django บน TextField ดังนั้นเมื่อคุณต้องการการตรวจสอบความยาวของฟิลด์ (เช่นให้เลขานุการป้อนข้อมูลสรุปเหตุการณ์) วิธีเดียวที่จะได้รับคือการใช้ CharField แต่ CharField เป็นวิธีการย่อเพื่อพิมพ์ 300 ตัวอักษรเข้าไป ดังนั้นวิธีการแก้ปัญหาอายาซ
shacker

3
นี่ไม่ใช่คำตอบที่ดีเพราะมีการเปลี่ยนแปลงฐานข้อมูล จุดเปลี่ยนวิดเจ็ตคือเปลี่ยนวิธีแสดงฟิลด์ไม่ใช่เปลี่ยนสคีมาฐานข้อมูล

1
เป็นคำตอบที่ดีสำหรับใครบางคน (เช่นฉัน) ที่กำลังเรียนรู้วิธีใช้ Django และจะตั้งค่าฐานข้อมูลแตกต่างกันตั้งแต่แรกถ้าฉันรู้ดีกว่านี้
Andrew Swift

7

หากคุณกำลังพยายามเปลี่ยน Textarea บน admin.py นี่เป็นวิธีแก้ปัญหาที่เหมาะกับฉัน:

from django import forms
from django.contrib import admin
from django.db import models
from django.forms import TextInput, Textarea

from books.models import Book

class BookForm(forms.ModelForm):
    description = forms.CharField( widget=forms.Textarea(attrs={'rows': 5, 'cols': 100}))
    class Meta:
        model = Book

class BookAdmin(admin.ModelAdmin):
    form = BookForm

admin.site.register(Book, BookAdmin)

หากคุณใช้ MySQL DB ความยาวคอลัมน์ของคุณจะถูกตั้งค่าอัตโนมัติเป็น 250 ตัวอักษรดังนั้นคุณจะต้องเรียกใช้ ALTER TABLE เพื่อเปลี่ยนความยาวใน MySQL DB ของคุณเพื่อให้คุณสามารถใช้ประโยชน์จาก Textarea ใหม่ที่มีขนาดใหญ่ขึ้น มีอยู่ในไซต์ Admin Django ของคุณ


5

คุณสามารถใช้models.TextFieldเพื่อวัตถุประสงค์นี้:

class Sample(models.Model):
    field1 = models.CharField(max_length=128)
    field2 = models.TextField(max_length=1024*2)   # Will be rendered as textarea

3
สิ่งนี้จะเปลี่ยนโครงสร้าง DB ดังนั้นระวังให้ดี
elad silver

3

ต้องการขยายคำตอบของ Carl Meyer ซึ่งทำงานได้อย่างสมบูรณ์แบบจนถึงทุกวันนี้

ฉันมักจะใช้TextFieldแทนCharField(มีหรือไม่มีตัวเลือก) และกำหนดขีด จำกัด อักขระในฝั่ง UI / API มากกว่าที่ระดับ DB ในการทำงานนี้แบบไดนามิก:

from django import forms
from django.contrib import admin


class BaseAdmin(admin.ModelAdmin):
    """
    Base admin capable of forcing widget conversion
    """
    def formfield_for_dbfield(self, db_field, **kwargs):
        formfield = super(BaseAdmin, self).formfield_for_dbfield(
            db_field, **kwargs)

        display_as_charfield = getattr(self, 'display_as_charfield', [])
        display_as_choicefield = getattr(self, 'display_as_choicefield', [])

        if db_field.name in display_as_charfield:
            formfield.widget = forms.TextInput(attrs=formfield.widget.attrs)
        elif db_field.name in display_as_choicefield:
            formfield.widget = forms.Select(choices=formfield.choices,
                                            attrs=formfield.widget.attrs)

        return formfield

ฉันมีชื่อรูปแบบPostที่title, slugและstateมีTextFieldและstateมีทางเลือก คำจำกัดความของผู้ดูแลระบบมีลักษณะดังนี้:

@admin.register(Post)
class PostAdmin(BaseAdmin):
    list_display = ('pk', 'title', 'author', 'org', 'state', 'created',)
    search_fields = [
        'title',
        'author__username',
    ]
    display_as_charfield = ['title', 'slug']
    display_as_choicefield = ['state']

คิดว่าคนอื่นกำลังมองหาคำตอบอาจพบว่ามีประโยชน์


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