2011-11-04 31 views
11

Tôi muốn có thêm các trường liên quan đến giá trị của một trường. Do đó tôi xây dựng biểu mẫu quản trị viên tùy chỉnh để thêm một số trường mới.Các trường động trong Django Admin

liên quan đến bài đăng trên blog của Jacobian 1 đây là những gì tôi đã đưa ra:

class ProductAdminForm(forms.ModelForm): 
    class Meta: 
     model = Product 

    def __init__(self, *args, **kwargs): 
     super(ProductAdminForm, self).__init__(*args, **kwargs) 
     self.fields['foo'] = forms.IntegerField(label="foo") 

class ProductAdmin(admin.ModelAdmin): 
    form = ProductAdminForm 

admin.site.register(Product, ProductAdmin) 

Nhưng trường bổ sung 'foo' không hiển thị trong admin. Nếu tôi thêm lĩnh vực này như thế này, tất cả hoạt động tốt nhưng không phải là năng động theo yêu cầu, để thêm các lĩnh vực liên quan đến giá trị của một lĩnh vực của mô hình

class ProductAdminForm(forms.ModelForm): 

    foo = forms.IntegerField(label="foo") 

    class Meta: 
     model = Product 

class ProductAdmin(admin.ModelAdmin): 
    form = ProductAdminForm 

admin.site.register(Product, ProductAdmin) 

Vậy là có bất kỳ phương pháp mà tôi phải kích hoạt khởi tạo một lần nữa để làm cho lĩnh vực mới hoạt động? Hay có nỗ lực nào khác không?

Trả lời

14

Đây là giải pháp cho vấn đề. Nhờ koniiiik tôi đã cố gắng để giải quyết việc này bằng cách mở rộng get_fieldsets * * phương pháp

class ProductAdmin(admin.ModelAdmin): 
    def get_fieldsets(self, request, obj=None): 
     fieldsets = super(ProductAdmin, self).get_fieldsets(request, obj) 
     fieldsets[0][1]['fields'] += ['foo'] 
     return fieldsets 

Nếu bạn sử dụng nhiều fieldsets hãy chắc chắn để thêm vào bên phải fieldset bằng cách sử dụng các chỉ số thích hợp.

+1

'Trường không xác định (foo) được chỉ định cho GlobalLabel. Kiểm tra các lĩnh vực/fieldets/loại trừ các thuộc tính của lớp GlobalLabelAdmin.' Tôi nhận được lỗi này, tôi không biết tại sao ... bạn có thể vui lòng giúp tôi ra? – bhushya

+0

@bhushya: bạn có thể tìm ra điều này không? Tôi cũng không thể làm cho nó hoạt động trong django 1.9.3, ví dụ: 'django.core.exceptions.FieldError: Các trường không xác định (dynamicfield1, dynamicfield2) được chỉ định cho MyModel' – tehfink

+0

@tehfink có vẻ như bạn chưa xác định trường trong mô hình của bạn .. bạn có thể vui lòng đăng cấu trúc mô hình của bạn trên pastebin.com và chia sẻ liên kết không? – bhushya

5

Trong khi bài đăng của Jacob có thể hoạt động bình thường cho ModelForm s (mặc dù đã hơn một năm rưỡi), quản trị viên có vấn đề hơi khác.

Tất cả các cách khai báo xác định mô hình, biểu mẫu ModelAdmins và những gì không sử dụng nhiều metaclasses và lớp introspection. Tương tự với quản trị viên - khi bạn yêu cầu một số ModelAdmin để sử dụng một biểu mẫu cụ thể, hãy tạo một biểu mẫu mặc định, nó sẽ nhìn vào lớp . Nó nhận danh sách các trường và các thứ khác từ chính lớp đó mà không cần khởi tạo nó. Tuy nhiên,

Lớp tùy chỉnh của bạn không xác định trường biểu mẫu bổ sung ở cấp lớp thay vào đó tự động thêm sau nó đã được khởi tạo - đã quá muộn để ModelAdmin nhận ra thay đổi này.

Một cách để giải quyết vấn đề của bạn có thể là phân lớp ModelAdmin và ghi đè phương thức get_fieldsets để thực sự khởi tạo lớp ModelForm và nhận danh sách trường từ thể hiện thay vì lớp. Tuy nhiên, bạn sẽ phải ghi nhớ rằng điều này có thể hơi chậm hơn so với việc triển khai mặc định.

0

không chắc chắn lý do tại sao không hoạt động, nhưng cách giải quyết có thể là xác định trường tĩnh (trên biểu mẫu) và sau đó ghi đè trường đó trong __init__?

2

Câu trả lời của Stephan là thanh lịch, nhưng khi tôi sử dụng trong dj1.6, nó yêu cầu trường phải là một bộ dữ liệu. Giải pháp hoàn chỉnh trông giống như sau:

class ProductForm(ModelForm): 
    foo = CharField(label='foo') 


class ProductAdmin(admin.ModelAdmin): 
    form = ProductForm 
    def get_fieldsets(self, request, obj=None): 
     fieldsets = super(ProductAdmin, self).get_fieldsets(request, obj) 
     fieldsets[0][1]['fields'] += ('foo',) 
     return fieldsets 
+0

Bạn có nhớ không, nếu tôi đưa câu trả lời này vào câu trả lời của mình;) –

3

Bạn có thể tạo trường động và fieldset bằng cách sử dụng lớp meta biểu mẫu. Mã mẫu được đưa ra dưới đây. Thêm logic vòng lặp theo yêu cầu của bạn.

class CustomAdminFormMetaClass(ModelFormMetaclass): 
    """ 
    Metaclass for custom admin form with dynamic field 
    """ 
    def __new__(cls, name, bases, attrs): 
     for field in get_dynamic_fields: #add logic to get the fields 
      attrs[field] = forms.CharField(max_length=30) #add logic to the form field 
     return super(CustomAdminFormMetaClass, cls).__new__(cls, name, bases, attrs) 


class CustomAdminForm(six.with_metaclass(CustomAdminFormMetaClass, forms.ModelForm)): 
    """ 
    Custom admin form 
    """ 

    class Meta: 
     model = ModelName 
     fields = "__all__" 


class CustomAdmin(admin.ModelAdmin): 
    """ 
    Custom admin 
    """ 

    fieldsets = None 
    form = CustomAdminForm 

    def get_fieldsets(self, request, obj=None): 
     """ 
     Different fieldset for the admin form 
     """ 
     self.fieldsets = self.dynamic_fieldset(). #add logic to add the dynamic fieldset with fields 
     return super(CustomAdmin, self).get_fieldsets(request, obj) 

    def dynamic_fieldset(self): 
     """ 
     get the dynamic field sets 
     """ 
     fieldsets = [] 
     for group in get_field_set_groups: #logic to get the field set group 
      fields = [] 
      for field in get_group_fields: #logic to get the group fields 
       fields.append(field) 

      fieldset_values = {"fields": tuple(fields), "classes": ['collapse']} 
      fieldsets.append((group, fieldset_values)) 

     fieldsets = tuple(fieldsets) 

     return fieldsets 
3

Câu trả lời được chấp nhận ở trên đã hoạt động trong phiên bản cũ của django và đó là cách tôi đang thực hiện. Điều này bây giờ đã bị phá vỡ trong phiên bản django sau này (tôi đang ở 1,68 vào lúc này, nhưng ngay cả đó là cũ bây giờ).

Lý do tại sao nó bị hỏng là do bất kỳ trường nào trong trường bạn quay trở lại từ ModelAdmin.get_fieldsets() cuối cùng được truyền dưới dạng trường = parameter đến modelform_factory(), điều này sẽ cho bạn lỗi vì các trường trong danh sách của bạn không tồn tại (và sẽ không tồn tại cho đến khi form của bạn được khởi tạo và __ init __ được gọi).

Để khắc phục điều này, chúng ta phải ghi đè ModelAdmin.get_form() và cung cấp danh sách các trường không bao gồm bất kỳ trường bổ sung nào sẽ được thêm sau này. Hành vi mặc định của get_form là để gọi get_fieldsets() để biết thông tin này, và chúng ta phải ngăn chặn điều đó xảy ra:

# CHOOSE ONE 
# newer versions of django use this 
from django.contrib.admin.utils import flatten_fieldsets 
# if above does not work, use this 
from django.contrib.admin.util import flatten_fieldsets 

class MyModelForm(ModelForm): 
    def __init__(self, *args, **kwargs): 
     super(MyModelForm, self).__init__(*args, **kwargs) 
     # add your dynamic fields here.. 
     for fieldname in ('foo', 'bar', 'baz',): 
      self.fields[fieldname] = form.CharField() 

class MyAdmin(ModelAdmin): 
    form = MyModelForm 

    fieldsets = [ 
     # here you put the list of fieldsets you want displayed.. only 
     # including the ones that are not dynamic 
    ] 

    def get_form(self, request, obj=None, **kwargs): 
     # By passing 'fields', we prevent ModelAdmin.get_form from 
     # looking up the fields itself by calling self.get_fieldsets() 
     # If you do not do this you will get an error from 
     # modelform_factory complaining about non-existent fields. 

     # use this line only for django before 1.9 (but after 1.5??) 
     kwargs['fields'] = flatten_fieldsets(self.declared_fieldsets) 
     # use this line only for django 1.9 and later 
     kwargs['fields'] = flatten_fieldsets(self.fieldsets) 

     return super(MyAdmin, self).get_form(request, obj, **kwargs) 

    def get_fieldsets(self, request, obj=None): 
     fieldsets = super(MyAdmin, self).get_fieldsets(request, obj) 

     newfieldsets = list(fieldsets) 
     fields = ['foo', 'bar', 'baz'] 
     newfieldsets.append(['Dynamic Fields', { 'fields': fields }]) 

     return newfieldsets 
+0

Thật không may, 'ModelAdmin.declared_fieldsets' [đã bị xóa] (https://docs.djangoproject.com/en/1.9/internals/deprecation/) ở Django 1.9 – tehfink

+0

Hmm .. tôi đoán là khi tôi nâng cấp máy chủ lên 1.9 Tôi sẽ có một số công việc cần làm;) Nhưng may mắn là tôi đã sao chép hầu hết chức năng quản trị ở nơi khác trong ứng dụng của mình ... –

+0

Đồng thời 'django.contrib.admin.util' hiện là' django.contrib.admin.utils' –

4

này làm việc cho thêm các trường động trong Django 1.9.3, chỉ sử dụng một lớp ModelAdmin (không ModelForm) và bằng cách ghi đè get_fields. Tôi chưa biết mức độ mạnh mẽ của nó:

class MyModelAdmin(admin.ModelAdmin): 

    fields = [('title','status',), 'description', 'contact_person',] 
    exclude = ['material'] 

    def get_fields(self, request, obj=None): 
     gf = super(MyModelAdmin, self).get_fields(request, obj) 

     new_dynamic_fields = [ 
      ('test1', forms.CharField()), 
      ('test2', forms.ModelMultipleChoiceField(MyModel.objects.all(), widget=forms.CheckboxSelectMultiple)), 
     ] 

     #without updating get_fields, the admin form will display w/o any new fields 
     #without updating base_fields or declared_fields, django will throw an error: django.core.exceptions.FieldError: Unknown field(s) (test) specified for MyModel. Check fields/fieldsets/exclude attributes of class MyModelAdmin. 

     for f in new_dynamic_fields: 
      #`gf.append(f[0])` results in multiple instances of the new fields 
      gf = gf + [f[0]] 
      #updating base_fields seems to have the same effect 
      self.form.declared_fields.update({f[0]:f[1]}) 
     return gf 
+0

điều này dường như làm việc trong django 1.10 – nidhin

0

Tôi đã lâu không thể giải quyết vấn đề với việc bổ sung năng động của trường. Giải pháp "little_birdie" thực sự hoạt động. Cảm ơn Birdie)) Độ sắc thái duy nhất là: "Self.declared_fieldsets" nên được thay thế bằng "self.fieldsets".

#kwargs['fields'] = flatten_fieldsets(self.declared_fieldsets) 
kwargs['fields'] = flatten_fieldsets(self.fieldsets) 

Tôi đã sử dụng phiên bản 1.10. Có lẽ một cái gì đó đã thay đổi.

Nếu ai đó tìm thấy giải pháp đơn giản và thanh lịch hơn, hãy hiển thị tại đây.

Cảm ơn tất cả)))

+0

Bạn đang rất hoan nghênh. –

Các vấn đề liên quan