Django-Admin: CharField dưới dạng TextArea


87

Tôi có

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 )

làm cách nào để gán tiện ích TextArea cho trường 'descr' trong giao diện quản trị?

cập nhật:
Chỉ trong giao diện Quản trị viên !

Ý tưởng hay để sử dụng ModelForm.


3
Câu trả lời được chấp nhận là quá mức cần thiết cho mục đích sửa đổi chỉ một trường! DÂN THEO câu trả lời này bởi Carl Meyer CHO MỤC ĐÍCH CỦA ĐƠN GIẢN: stackoverflow.com/questions/430592/...
andilabs

Câu trả lời:


99

Bạn sẽ phải tạo một biểu mẫu forms.ModelFormmô tả cách bạn muốn descrtrường được hiển thị, sau đó yêu admin.ModelAdmincầu sử dụng biểu mẫu đó. Ví dụ:

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

Các formthuộc tính của admin.ModelAdminđược ghi chép lại trong các tài liệu chính thức Django. Đây là một nơi để xem xét .


6
Để thay thế một tiện ích biểu mẫu đơn giản, bạn không cần phải tạo toàn bộ biểu mẫu của riêng mình. Bạn chỉ có thể ghi đè lên formfield_for_dbfieldcủa bạn ModelAdmin, hãy xem câu trả lời của tôi bên dưới.
Carl Meyer

1
Điều này mang lạidjango.core.exceptions.ImproperlyConfigured: Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is prohibited
John Wu

4
Bắt đầu từ Django 1.7, bạn cũng cần thêm vào fields = '__all__'bên dưới class Meta:.
skoll

2
Bạn không cần phải tự tạo biểu mẫu, bạn có thể ghi đè get_formphương thức. Hãy xem câu trả lời của tôi .
x-yuri

Cách tiếp cận beeter là sử dụng Meta Meta lớp: mô hình = nhắn widget = { 'text': forms.Textarea (attrs = { 'cols': 80, 'hàng': 20}),}
Amulya Acharya

58

Đối với trường hợp này, lựa chọn tốt nhất có lẽ chỉ là sử dụng TextField thay vì CharField trong mô hình của bạn. Bạn cũng có thể ghi đè formfield_for_dbfieldphương thức của ModelAdminlớp mình:

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

có nhược điểm nào trong điều này so với câu trả lời đã chọn không? cái này trông gọn gàng hơn để triển khai vì chúng tôi không cần tạo ModelForm mới ...
Filipe Pina

3
được thay thế formfield.widget = forms.Textarea()bằng formfield.widget = forms.Textarea(attrs=formfield.widget.attrs)để giữ tất cả các thuộc tính được tạo tự động cho TextField, Cảm ơn!
Filipe Pina

2
Tôi không biết tại sao câu trả lời khác được chấp nhận hơn câu trả lời này; Tôi nghĩ nếu tất cả những gì bạn đang làm là thay thế một widget thì việc này đơn giản hơn. Nhưng một trong hai sẽ hoạt động tốt.
Carl Meyer

Điều này hoạt động hoàn hảo, cảm ơn. Tuy nhiên, lời gọi super () có vẻ hơi dài dòng, có cách nào đơn giản hơn để thực hiện không?
rjh

2
@rjh Trong py3, bạn có thể loại bỏ mọi thứ bên trong parens và chỉ cần sử dụng super(). Nếu không thì không.
Carl Meyer

32

Ayaz có khá nhiều điểm, ngoại trừ một chút thay đổi (?!):

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)

Vì vậy, bạn không cần phải xác định lại một trường trong ModelForm để thay đổi widget của nó, chỉ cần đặt các widget dict trong Meta.


1
Điều này giữ lại nhiều thuộc tính "tự động" hơn câu trả lời của Ayaz, nhưng có mẹo nào về cách giữ xác thực độ dài trường không?
Filipe Pina

14

Bạn có thể phân lớp trường của riêng mình bằng formfieldphương thức cần thiết :

class CharFieldWithTextarea(models.CharField):

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

Điều này sẽ ảnh hưởng đến tất cả các biểu mẫu đã tạo.


9

Bạn không cần phải tự tạo lớp biểu mẫu:

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)

Xem ModelAdmin.get_form .


7

Nếu bạn đang cố gắng thay đổi Textarea trên admin.py, đây là giải pháp phù hợp với tôi:

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)

Nếu bạn đang sử dụng MySQL DB, độ dài cột của bạn thường sẽ được tự động đặt thành 250 ký tự, vì vậy bạn sẽ muốn chạy BẢNG ALTER để thay đổi độ dài trong MySQL DB của mình, để bạn có thể tận dụng Textarea mới lớn hơn mà bạn có trong bạn quản trị trang web Django.


6

Thay vì a models.CharField, hãy sử dụng models.TextFieldfor descr.


4
Thật không may, max_length = hoàn toàn bị Django bỏ qua trên TextField, vì vậy khi bạn cần xác thực độ dài trường (chẳng hạn như để thư ký nhập tóm tắt sự kiện), cách duy nhất để có được nó là sử dụng CharField. Nhưng CharField là cách viết tắt để nhập 300 ký tự vào. Do đó giải pháp ayaz.
shacker

3
Đây không phải là một câu trả lời hay vì nó thay đổi cơ sở dữ liệu. Mục đích của việc thay đổi widget là để thay đổi như thế nào lĩnh vực này sẽ được hiển thị, không phải để thay đổi giản đồ cơ sở dữ liệu

1
Đó là một câu trả lời tuyệt vời cho một người (như tôi), những người đang học cách sử dụng Django và sẽ thiết lập cơ sở dữ liệu khác ngay từ đầu nếu tôi biết rõ hơn.
Andrew Swift,

5

Bạn có thể sử dụng models.TextFieldcho mục đích này:

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

3
Điều này sẽ thay đổi cấu trúc DB vì vậy hãy cẩn thận
bạc Elad

3

Tôi muốn mở rộng câu trả lời của Carl Meyer, câu trả lời hoạt động hoàn hảo cho đến ngày nay.

Tôi luôn sử dụng TextFieldthay vì CharField(có hoặc không có lựa chọn) và áp đặt giới hạn ký tự ở phía UI / API hơn là ở cấp DB. Để làm cho điều này hoạt động động:

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

Tôi có một tên mô hình Postở đâu title, slug& stateTextFields và statecó các lựa chọn. Định nghĩa quản trị có dạng như sau:

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

Nghĩ rằng những người khác đang tìm kiếm câu trả lời có thể thấy điều này hữu ích.


Đây có phải là formfield_for_dbfieldtài liệu?
x-yuri
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.