django admin - कस्टम फ़ॉर्म फ़ील्ड जोड़ें जो मॉडल का हिस्सा नहीं हैं


106

मेरे पास व्यवस्थापक साइट में पंजीकृत एक मॉडल है। इसका एक क्षेत्र एक लंबी स्ट्रिंग अभिव्यक्ति है। मैं व्यवस्थापक में इस मॉडल के ऐड / अपडेट पृष्ठ पर कस्टम फ़ॉर्म फ़ील्ड जोड़ना चाहूंगा जो इन फ़ील्ड मानों के आधार पर मैं लंबी स्ट्रिंग अभिव्यक्ति का निर्माण करूँगा और इसे संबंधित मॉडल फ़ील्ड में सहेजूंगा।

मैं उसे कैसे कर सकता हूँ?

अद्यतन: मूल रूप से मैं जो कर रहा हूं वह प्रतीकों से एक गणितीय या स्ट्रिंग अभिव्यक्ति का निर्माण कर रहा है, उपयोगकर्ता प्रतीकों का चयन करता है (ये कस्टम फ़ील्ड हैं जो मॉडल का हिस्सा नहीं हैं) और जब वह क्लिक करता है तो मैं एक स्ट्रिंग अभिव्यक्ति का प्रतिनिधित्व करता हूं प्रतीकों की सूची और डीबी में संग्रहीत करें। मैं नहीं चाहता कि प्रतीक मॉडल और 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. आपके द्वारा बनाए गए फ़ॉर्म को संदर्भित करने के लिए अपने व्यवस्थापक को संपादित करें और फ़ॉर्म संपत्ति सेट करें
  2. अपने क्षेत्र या क्षेत्र घोषणा में अपने नए क्षेत्र शामिल करें

ऐशे ही:

class YourModelAdmin(admin.ModelAdmin):

    form = YourModelForm

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

UPDATE: django 1.8 में आपको fields = '__all__'YourModelForm के मेटाक्लास में जोड़ना होगा।


2
हां, मैं वास्तव में इसका कारण जानना चाहता हूं
विष्णु

13
आपको fields = '__all__'अपनी Metaकक्षा में जोड़ना चाहिए , अन्यथा django शिकायत करता है:Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is deprecated
इसहाकलाइनर

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तरह की विशेषता परिभाषा के लिए।
अलक्स

1
यह खूबसूरती से काम किया अगर extra_field एक CharField () है। यदि यह एक छिपा हुआ है, हालांकि [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())
काकोमा

35

यह व्यवस्थापक में करना संभव है, लेकिन इसके लिए बहुत सीधा रास्ता नहीं है। इसके अलावा, मैं आपके मॉडलों में अधिकांश व्यावसायिक तर्क रखने की सलाह देना चाहूंगा, इसलिए आप Django एडमिन पर निर्भर नहीं होंगे।

हो सकता है कि यह आसान (और शायद बेहतर भी हो) यदि आपके पास अपने मॉडल पर दो अलग-अलग क्षेत्र हैं। फिर अपने मॉडल पर एक विधि जोड़ें जो उन्हें जोड़ती है।

उदाहरण के लिए:

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
उत्तर के लिए धन्यवाद, लेकिन यह वह नहीं है जिसकी मुझे तलाश है। मैं नहीं चाहता कि कस्टम फ़ील्ड DB में सहेजी जाए, केवल परिकलित स्ट्रिंग। मूल रूप से मैं जो कर रहा हूं वह प्रतीकों में से एक गणितीय या स्ट्रिंग अभिव्यक्ति का निर्माण कर रहा है, उपयोगकर्ता प्रतीकों का चयन करता है (ये कस्टम फ़ील्ड हैं जो मॉडल का हिस्सा नहीं हैं) और जब वह क्लिक करता है तो मैं एक स्ट्रिंग अभिव्यक्ति का प्रतिनिधित्व करता हूं प्रतीकों और DB में इसे स्टोर।
माइकल ५ mic

@ michalv82 आप इसे मॉडल की save()विधि में डेटाबेस में भी सहेज सकते हैं , मेरे उत्तर के अपडेट की जांच कर सकते हैं।
गीताकार

1
धन्यवाद फिर से, लेकिन मुद्दा यह है कि मैं उन फ़ील्ड्स को संग्रहीत नहीं करना चाहता जो अंतिम फ़ील्ड (यानी प्रतीकों) को संयोजित करते हैं, मैं बस चाहता हूं कि अंतिम स्ट्रिंग को बचाया जाए
michalv82

क्या यह 2 क्षेत्रों को बचाने के लिए एक समस्या है? शायद यह काम आ सकता है, यदि आप जानना चाहते हैं कि संयुक्त क्षेत्र कैसे उत्पन्न हुआ।
गीताकार

6
धन्यवाद फिर से, लेकिन यह 2 क्षेत्र नहीं है, यह शायद अधिक होगा। फिर, मैं उन्हें डीबी में संग्रहीत नहीं करना चाहता, इसलिए यह समाधान मेरे लिए काम नहीं कर सकता।
मीकलव 8282

5

Django 2.1.1 मेरे सवाल का जवाब देने के लिए प्राथमिक उत्तर मुझे आधा मिल गया। इसने मुझे मेरे वास्तविक मॉडल के क्षेत्र में परिणाम को बचाने में मदद नहीं की। मेरे मामले में मैं एक टेक्स्टफील्ड चाहता था कि एक उपयोगकर्ता डेटा में प्रवेश कर सके, फिर जब एक बचत हुई तो डेटा को संसाधित किया जाएगा और परिणाम मॉडल में एक फ़ील्ड में डाल दिया जाएगा और सहेजा जाएगा। जबकि मूल उत्तर में दिखाया गया था कि अतिरिक्त क्षेत्र से मूल्य कैसे प्राप्त किया जाए, यह नहीं दिखा कि कम से कम DjNO 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 जोड़ें):

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

3

यदि आप पूरी तरह से केवल मॉडल पर संयुक्त क्षेत्र को संग्रहीत करना चाहते हैं और दो अलग-अलग फ़ील्ड नहीं, तो आप कुछ इस तरह से कर सकते हैं:

मैंने कभी ऐसा कुछ नहीं किया इसलिए मुझे पूरा यकीन नहीं है कि यह कैसे काम करेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.