2012-01-02 18 views
7

मेरे पास एक मॉडल है, Director दो डेटफिल्ड्स, और दो उप-वर्ग (नीचे कोड) के साथ। मैं प्रत्येक निदेशक के लिए एक व्यवस्थापक पृष्ठ बनाने की कोशिश कर रहा हूं जो संबंधित सबक्लास उदाहरण दिखाता है, न कि Director उदाहरण; यह हिस्सा अधिकतर आसान है (मैं प्रत्येक उप-वर्ग के लिए एक इनलाइन बना देता हूं, मुख्य मॉडलएडमिन को सभी फ़ील्ड को छोड़कर एक फॉर्म देता हूं, और मुख्य मॉडलएडमिन केवल इनलाइनों से फ़ॉर्मेट्स का अनुरोध करता है जिसमें एक समान उदाहरण होता है - कोड; एक अनसुलझा समस्या है इस दृष्टिकोण के साथ, जो मैं नीचे नोट करता हूं, लेकिन इस प्रश्न का ध्यान नहीं है)।Django व्यवस्थापक: रीडोनली फ़ील्ड को प्रारूपित करने के लिए कैसे?

मेरी समस्या यह है कि मैं उपयोगकर्ता को प्रदर्शित मूल्यों को मालिश करना चाहता हूं, जिनमें से एक एक पाठक क्षेत्र में दिखाया गया है, जिसमें से एक नहीं है। प्रसंस्करण यह है कि मैं एक जादू मान (date(1,1,1)) स्ट्रिंग "On incorporation" में बदलना चाहता हूं।

रीडोनली फ़ील्ड में तिथियां पार्सिंग के लिए बहुत अनुकूल प्रारूप में प्रस्तुत नहीं की जाती हैं, और मैं जावास्क्रिप्ट पर अनावश्यक निर्भरता को कम करना चाहता हूं, इसलिए मैं सर्वर-साइड समाधान को बहुत पसंद करूंगा।

नीचे दिया गया कोड फॉर्मों को प्रदर्शित करता है जैसा कि मैं उन्हें चाहता हूं, सिवाय इसके कि तिथि मानों को मालिश नहीं किया जाता है, और सहेजते समय, कोई गड़बड़ है "कृपया नीचे दी गई त्रुटि को सही करें" संदेश, भले ही कोई त्रुटि न हो, और सभी फ़ील्ड सही ढंग से सहेजे गए हैं।

मेरा प्रश्न है: मैं पृष्ठ पर पाठों को, पाठ क्षेत्रों में और रूपों के दोनों क्षेत्रों में कैसे प्रस्तुत किया जा सकता हूं, और उन्हें मेरे चयन की एक स्ट्रिंग प्रदर्शित करने के लिए कैसे बदल सकता हूं?

मॉडल (अब तक सामग्री के रूप में):

class Director(models.Model, Specializable): 
    date_of_appointment = models.DateField() 
    date_ceased_to_act = models.DateField(blank=True,null=True) 

class DirectorsIndividual(Director): 
    pass 

class DirectorsCorporate(Director): 
    pass 

व्यवस्थापक कोड:

class DirectorAdmin(EnhancedAdmin): 

    fields =() 

## def formfield_for_dbfield(self, db_field, **kwargs): 
##  return None 

    def queryset(self, request): 
     """ Directors for all companies which are incorporated by the current user's organisation """ 
     individual = Individual.for_user(request.user) 
     return Director.objects.filter(company__incorporation_ticket__ordered_by__in = Organisation.all_organisations_for_which_individual_authorised_to_incorporate(individual)) 

    class form(forms.ModelForm): 
     # have this return no html - that way only inlines are shown 
     class Meta: 
      fields =() 
      pass 

     def is_valid(self): 
      self._errors = {} 
      return True 

    class DirectorsIndividualInline(admin.StackedInline): 
     model = DirectorsIndividual 
     fk_name = 'director_ptr' 
     extra = 0 
     readonly_fields = ('deferred_on','company','date_of_appointment',) 
     can_delete = False 

     def get_readonly_fields(self, request, obj=None): 
      if obj and obj.company and not obj.company.is_submitted(): return self.readonly_fields # allow editing of fields listed in else 
      else: 
       return itertools.chain(self.readonly_fields, ('individual', 'is_secretary')) 

     def has_delete_permission(self, request, obj=None): 
      return obj and ((obj.company and not obj.company.is_submitted()) or not obj.company) 

     class form(forms.ModelForm): 
      def __init__(self, *args, **kwargs): 
       super(forms.ModelForm, self).__init__(*args, **kwargs) 
       self.fields['surrogate_for'].required = False 
       self.fields['representative_for'].required = False 
       if self.instance: 
        obj = self.instance 
        for field in (f for f in type(obj)._meta.fields if type(f) == fields.DateField): 
         val = field.value_from_object(obj) 
         assert (type(val) in (datetime.date, type(None),)) 
         # assert field.name != 'date_of_appointment' 
         if val == inc_consts.EARLIEST_DATE: 
          self.initial[field.name] = "On incorporation" 

      def is_valid(self): 
       self._errors = {} 
       return True 

    class DirectorsCorporateInline(admin.StackedInline): 

     model = DirectorsCorporate 
     fk_name = 'director_ptr' 
     extra = 0 
     can_delete = False 

     class form(forms.ModelForm): 
      def __init__(self, *args, **kwargs): 
       super(forms.ModelForm, self).__init__(*args, **kwargs) 
       if True: 
        for k in self.fields: 
         self.fields[k].required = False 

      def is_valid(self): 
       self._errors = {} 
       return True 


    inlines = (DirectorsIndividualInline,DirectorsCorporateInline) 

    def get_inlines(self, request, obj=None): 
     return (inline for inline in (self.inline_instances) 
       if inline.model.objects.filter(**{(inline.fk_name or self.model._meta.object_name.lower()) : obj })) 

    def get_formsets(self, request, obj=None): 
     """ only return formset for inlines for which there exists an object """ 
     return (inline.get_formset(request, obj) for inline in self.get_inlines(request, obj)) 

मुझे पता DirectorsCorporateInline और DirectorsIndividualInline के बीच एक विषमता है कि वहाँ; ऐसा इसलिए है क्योंकि मैं DirectorsIndividual उदाहरण के साथ एक उदाहरण पर परीक्षण कर रहा हूं। उपरोक्त कोड मॉडलों में दिखाए गए मॉडल फ़ील्ड को संदर्भित करता है, क्योंकि वे दिनांक समस्या के लिए सामग्री नहीं हैं; उन क्षेत्रों को बदलने के बिना नकली त्रुटि समस्या के लिए उन्हें असंतोष देना संभव होना चाहिए (हालांकि मुझे एहसास है कि इस मुद्दे के लिए यह कम सहायक है, मैं इस प्रश्न को ज्यादातर एक मुद्दे पर केंद्रित रखना चाहता हूं)। EnhancedAdmin कुछ मामूली बदलावों के साथ ModelAdmin सबक्लास है जो परिणाम का नहीं होना चाहिए। अतिरिक्त कोड तर्कसंगत अनुरोध पर दिखाया जा सकता है, लेकिन मैं अप्रासंगिक कोड से भ्रमित नहीं होना चाहता हूं।

पूर्णता के लिए: मैं अजगर 2.7.2 पर django 1.3.1 का उपयोग कर रहा हूं।

उत्तर

3

अपने Director वर्ग के सदस्य फ़ंक्शन को परिभाषित करें जो readonly_field को आप चाहते हैं।

class Director(models.Model, Specializable): 
    date_of_appointment = models.DateField() 
    date_ceased_to_act = models.DateField(blank=True,null=True) 
    def date_of_appointment_str(self): 
     if self.date_of_appointment == datetime.date(1,1,1): 
      return "On incorporation" 
     else: 
      return "%s" % (self.date_of_appointment) # format as you wish 

और फिर बस व्यवस्थापक में readonly_fields की अपनी सूची में 'date_of_appointment_str' जोड़ें।

संपादित करें: मुझे यह जोड़ना चाहिए कि यह एक त्वरित समाधान है। एक और मजबूत समाधान models.DateField को MyCustomDateField में उपclass करना है जो DateField जैसा कार्य करता है सिवाय इसके कि जब मान date(1,1,1) होता है तो यह "निगमन पर" या जब उपयोगकर्ता "निगमन पर" सहेजता है तो यह मान को date(1,1,1) के रूप में सहेजता है। यह सुनिश्चित करेगा कि आप इस क्षेत्र के प्रकार के हर जगह इस कार्यक्षमता का पुन: उपयोग कर सकते हैं। हालांकि, अगर यह केवल एक ही स्थान पर दिखाई देता है; यह अधिक हो सकता है।

आपको कुछ की आवश्यकता होगी (यह अनचाहे है; आपको अपने फॉर्म DateField और/या अन्य चीजों को बदलने की आवश्यकता हो सकती है, उदाहरण के लिए, यदि आप डीजेंगो-दक्षिण का उपयोग करते हैं तो आपको कस्टम आत्मनिरीक्षण नियम जोड़ना होगा)। ModelAdmin का उपयोग करेगा -

class Director(models.Model, Specializable): 
    date_of_appointment = models.DateField() 
    date_ceased_to_act = models.DateField(blank=True,null=True) 

    #def date_formatter and def _date_format_factory omitted 

    date_of_appointment_formatted = lambda self: self.date_formatter(getattr(self, 'date_of_appointment')) 
    date_ceased_to_act_formatted = _date_format_factory(None, 'date_ceased_to_act') #for some reason, I get a 'classmethod/staticmethod object is not callable' error if I decorate _date_format_factory 
    date_of_appointment_formatted.short_description = u'Date of appointment' 

नोट date_of_appointment_formatted.short_description:

class MyCustomDateField(models.DateField): 
    date_111_str = 'On incorporation' 
    def value_to_string(self, obj): 
     val = self._get_val_from_obj(obj) 
     if val is None: 
      data = '' 
     elif val.year == val.day == val.month == 1: 
      data = date_111_str 
     else: 
      data = datetime_safe.new_date(val).strftime("%Y-%m-%d") 
     return data 
    def get_prep_value(self, value): 
     if value == date_111_str: 
      value = datetime.date(1,1,1) 
     return super(MyCustomDateField,self).get_prep_value(self, value) 
0

मैं जावास्क्रिप्ट के साथ फ़ील्ड मानों को मालिश करूंगा। आप व्यवस्थापक टेम्पलेट्स override कर सकते हैं, और {% block extrahead %} ब्लॉक में अपने जावास्क्रिप्ट कोड को संलग्न कर सकते हैं (django book से कुछ और जानकारी)। अपने जादू मालिश समारोह उदाहरण को .ready() में रखें (यदि आप jQuery का उपयोग करते हैं)।

मुझे आशा है कि यह आपके लिए काम करेगा, क्योंकि मैं कुछ ऐसा करना चाहता हूं, लेकिन अभी तक लागू नहीं किया है। :)

+0

वे वास्तव में लगातार प्रस्तुत नहीं किए जाते हैं, जो जावास्क्रिप्ट को दर्द का उपयोग करेंगे; मुझे शायद जानकारी के लिए धन्यवाद देना होगा। – Marcin

1

रूप @drjimbob (और #django पर carljm) का सुझाव दिया, समाधान एक सदस्य समारोह या संपत्ति मॉडल पर, जैसे बनाने के लिए है short_descriptionreadonly_field के लिए लेबल के रूप में।

मॉडल क्षेत्रों के साथ काम करने के गुण प्राप्त करने के लिए, एक कस्टम प्रपत्र की जरूरत है:

class DirectorInlineForm(EnhancedModelForm): 
    from django.utils import formats 
    date_ceased_to_act_formatted = forms.DateField(required = False, widget = admin.widgets.AdminDateWidget, 
                label = u'Date officer\'s appointment terminated', 
                input_formats = formats.get_format('DATE_INPUT_FORMATS') + (Director.on_incorporation,)) 

      class Meta: 
       model = Director # Note that model declaration is necessary for this to work with additional fields declared 


    def __init__(self, *args, **kwargs): 
     super(DirectorInlineForm, self).__init__(*args, **kwargs) 
     # set initial values from model of declared fields 
     if self.instance: 
      self.initial['date_ceased_to_act_formatted'] = self.instance.date_ceased_to_act_formatted 


    def save(self, commit = True): 
     # save logic for magic formatted fields 
     if self._raw_value('date_ceased_to_act_formatted') == Director.on_incorporation: 
      sval = Director.on_incorporation 
     else: sval = self.cleaned_data['date_ceased_to_act_formatted'] 

     self.instance.date_ceased_to_act_formatted = sval 

     return super(forms.ModelForm, self).save(commit) 

ModelForm संपत्ति प्रदर्शित करने के लिए एक कस्टम फ़ील्ड की जरूरत है; प्रॉपर्टी से फ़ील्ड के लिए प्रारंभिक मान सेट करने के लिए एक कस्टम __init__, और कस्टम सेव, फॉर्म फ़ील्ड से मॉडल प्रॉपर्टी सेट करने के लिए।

मेरे उदाहरण में, सहेजने को जादू मूल्य के बारे में भी पता होना चाहिए, क्योंकि DateField जादू मूल्य को कैसे संभालता है। आप उस कोड को इसके बजाय एक कस्टम फ़ील्ड में धक्का दे सकते हैं।

4

ModelAdmin में कस्टम कॉलबैक को परिभाषित करके इसे करने का सबसे आसान तरीका है। मान लीजिए कि क्षेत्र my_datetime कहा जाता है दो:

from django.contrib import admin 
from django.utils.formats import localize 


class MyModelAdmin(admin.ModelAdmin): 
    readonly_fields = ('my_datetime_localized',) 

    def my_datetime_localized(self, obj): 
     return localize(obj.my_datetime) 
    end_datetime_localized.short_description = 'Date/time' 

नोट: यदि settings.USE_L10NTrue है, यह दर्शक, जो शायद तुम क्या चाहते है की स्थानीय समय में दिनांक प्रदर्शित करेगा। यदि आप USE_L10N को False के रूप में रखना चाहते हैं तो आप इसके व्यवहार को ओवरराइड कर सकते हैं: return localize(obj.my_datetime, use_l10n=True)

संबंधित मुद्दे