django admin - thêm các trường biểu mẫu tùy chỉnh không phải là một phần của mô hình


106

Tôi có một mô hình được đăng ký trong trang web quản trị. Một trong các trường của nó là một biểu thức chuỗi dài. Tôi muốn thêm các trường biểu mẫu tùy chỉnh vào trang thêm / cập nhật của mô hình này trong quản trị viên mà dựa trên các giá trị trường này, tôi sẽ xây dựng biểu thức chuỗi dài và lưu nó trong trường mô hình có liên quan.

Làm thế nào tôi có thể làm điều đó?

CẬP NHẬT: Về cơ bản những gì tôi đang làm là xây dựng một biểu thức toán học hoặc chuỗi từ các ký hiệu, người dùng chọn các ký hiệu (đây là các trường tùy chỉnh không phải là một phần của mô hình) và khi anh ta nhấp vào lưu thì tôi tạo biểu thức chuỗi từ danh sách các ký hiệu và lưu trữ nó trong DB. Tôi không muốn các biểu tượng là một phần của mô hình và DB, chỉ là biểu thức cuối cùng.

Câu trả lời:


156

Trong admin.py hoặc trong một form.py riêng biệt, bạn có thể thêm một lớp ModelForm và sau đó khai báo các trường bổ sung bên trong lớp đó như bạn thường làm. Tôi cũng đã đưa ra một ví dụ về cách bạn có thể sử dụng các giá trị này trong 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

Để có các trường bổ sung xuất hiện trong quản trị viên, chỉ cần:

  1. chỉnh sửa admin.py của bạn và đặt thuộc tính biểu mẫu để tham chiếu đến biểu mẫu bạn đã tạo ở trên
  2. bao gồm các trường mới của bạn trong các trường hoặc khai báo tập trường của bạn

Như thế này:

class YourModelAdmin(admin.ModelAdmin):

    form = YourModelForm

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

CẬP NHẬT: Trong django 1.8, bạn cần thêm fields = '__all__'vào siêu kính của YourModelForm.


2
Có, tôi thực sự muốn biết lý do
Vishnu

13
Bạn nên thêm fields = '__all__'vào Metalớp học của mình , nếu không django phàn nàn:Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is deprecated
IsaacKleiner

1
@sthzg, Vì nó không chính xác. Nó mang lại cho tôi lỗi:YourModelAdmin.list_display[0], 'extra_field' is not a callable or an attribute of 'YourModelAdmin' or found in the model 'YourModel'.
Cerin

7
Nếu vì lý do nào đó, bạn nhận được một AttributeError: Unable to lookup "extra_field"..., hãy thử thêm một labelvào extra_fieldđịnh nghĩa. Có vẻ như django cố gắng "đoán" nhãn của nó, bằng cách xem xét ModelModelAdminđịnh nghĩa thuộc tính như vậy.
alxs

1
Điều này hoạt động tốt nếu extra_field là một CharField (). Nếu đó là một Trường học ẩn [Trong Django 1.11], thì đã xảy ra lỗi Unknown field(s) (extra_field) specified for YourModel. Check fields/fieldsets/exclude attributes of class YourModelAdmin.. Cách giải quyết cho điều đó làextra_field = forms.CharField(widget=forms.HiddenInput())
kakoma

35

Nó có thể làm trong quản trị, nhưng không có một cách rất đơn giản để làm điều đó. Ngoài ra, tôi muốn đưa ra lời khuyên là hãy giữ hầu hết logic nghiệp vụ trong các mô hình của bạn, để bạn không bị phụ thuộc vào Quản trị viên Django.

Có lẽ sẽ dễ dàng hơn (và thậm chí có thể tốt hơn) nếu bạn có hai trường riêng biệt trên mô hình của mình. Sau đó, thêm một phương thức trên mô hình của bạn để kết hợp chúng.

Ví dụ:

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)

Sau đó, trong quản trị viên, bạn có thể thêm trường combined_fields()dưới dạng trường chỉ đọc:

class MyModelAdmin(models.ModelAdmin):

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

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

Nếu bạn muốn lưu trữ combined_fieldstrong cơ sở dữ liệu, bạn cũng có thể lưu nó khi lưu mô hình:

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

4
Cảm ơn vì câu trả lời, nhưng đây không phải là điều tôi đang tìm kiếm. Tôi không muốn các trường tùy chỉnh được lưu trong DB, chỉ lưu chuỗi được tính toán. Về cơ bản những gì tôi đang làm là xây dựng một biểu thức toán học hoặc chuỗi từ các ký hiệu, người dùng chọn các ký hiệu (đây là các trường tùy chỉnh không phải là một phần của mô hình) và khi anh ta nhấp vào lưu thì tôi tạo biểu thức chuỗi từ danh sách và lưu trữ nó trong DB.
michalv82

@ michalv82 Bạn cũng có thể lưu nó vào cơ sở dữ liệu trong save()phương pháp của mô hình , kiểm tra các cập nhật của câu trả lời của tôi.
gitaarik

1
nhờ một lần nữa, nhưng vấn đề là tôi không muốn để lưu trữ các lĩnh vực mà kết hợp các lĩnh vực chính thức (tức là những biểu tượng), tôi chỉ muốn chuỗi cuối cùng để được cứu rỗi
michalv82

Lưu 2 trường có vấn đề gì không? Có lẽ nó có thể hữu ích, nếu bạn muốn biết cách trường kết hợp được tạo ra.
gitaarik,

6
cảm ơn một lần nữa nhưng nó không phải là 2 lĩnh vực, nó có thể sẽ nhiều hơn. Một lần nữa, tôi KHÔNG muốn lưu trữ chúng trong DB, vì vậy giải pháp này không thể hoạt động với tôi.
michalv82,

5

Django 2.1.1 Câu trả lời chính khiến tôi đi được nửa chặng đường để trả lời câu hỏi của mình. Nó không giúp tôi lưu kết quả vào một trường trong mô hình thực tế của tôi. Trong trường hợp của tôi, tôi muốn một trường văn bản mà người dùng có thể nhập dữ liệu vào, sau đó khi lưu xảy ra, dữ liệu sẽ được xử lý và kết quả được đưa vào một trường trong mô hình và được lưu. Trong khi câu trả lời ban đầu chỉ ra cách lấy giá trị từ trường bổ sung, nó không chỉ ra cách lưu nó trở lại mô hình ít nhất là trong Django 2.1.1

Điều này lấy giá trị từ trường tùy chỉnh không bị ràng buộc, xử lý và lưu nó vào trường mô tả thực của tôi:

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

bạn luôn có thể tạo mẫu quản trị viên mới và thực hiện những gì bạn cần trong admin_view của mình (ghi đè url thêm quản trị viên vào admin_view của bạn):

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

3

Nếu bạn hoàn toàn chỉ muốn lưu trữ trường kết hợp trên mô hình chứ không phải hai trường riêng biệt, bạn có thể làm như sau:

Tôi chưa bao giờ làm điều gì đó như thế này nên tôi không hoàn toàn chắc chắn nó sẽ diễn ra như thế nào.

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.