2010-04-10 12 views
22

मुझे लगता है कि इसी तरह की समस्या पर चर्चा की गई होगी, लेकिन मुझे यह नहीं मिला।उपयोगकर्ता के आधार पर django-admin में फ़ील्ड को सीमित कैसे करें?

की मैं एक संपादक और एक पर्यवेक्षक मान लीजिए करते हैं। मैं चाहता हूं कि संपादक नई सामग्री (उदाहरण के लिए एक समाचार पोस्ट) जोड़ने में सक्षम हो, लेकिन प्रकाशन से पहले इसे पर्यवेक्षक द्वारा स्वीकार किया जाना चाहिए।

जब संपादक सभी वस्तुओं को सूचीबद्ध करता है, तो मैं कुछ फ़ील्ड मॉडल (जैसे 'एक' फ़ील्ड) को केवल पढ़ने के लिए सेट करना चाहता हूं (इसलिए वह जान सकता था कि क्या किया गया था और अभी भी क्या इंतजार कर रहा है) लेकिन पर्यवेक्षक सब कुछ बदलने में सक्षम होना चाहिए (list_editable सही)

इस समस्या के संभावित समाधान क्या हैं?

उत्तर

15

मुझे लगता है कि वहाँ एक और अधिक आसान तरीका है कि ऐसा करने के लिए है:

अतिथि हम ब्लॉग के एक ही समस्या है -Post

ब्लॉग/models.py:

ब्लॉग/admin.py:

Class Blog(models.Model): 
    ... 
    #fields like autor, title, stuff.. 
    ... 

class Post(models.Model): 
    ... 
    #fields like blog, title, stuff.. 
    ... 
    approved = models.BooleanField(default=False) 
    approved_by = models.ForeignKey(User) 
    class Meta: 
     permissions = (
      ("can_approve_post", "Can approve post"), 
     ) 

और जादू व्यवस्थापक में है

... 
from django.views.decorators.csrf import csrf_protect 
... 
def has_approval_permission(request, obj=None): 
    if request.user.has_perm('blog.can_approve_post'): 
     return True 
    return False 

Class PostAdmin(admin.ModelAdmin): 
    @csrf_protect 
    def changelist_view(self, request, extra_context=None): 
     if not has_approval_permission(request): 
      self.list_display = [...] # list of fields to show if user can't approve the post 
      self.editable = [...] 
     else: 
      self.list_display = [...] # list of fields to show if user can approve the post 
     return super(PostAdmin, self).changelist_view(request, extra_context) 
    def get_form(self, request, obj=None, **kwargs): 
     if not has_approval_permission(request, obj): 
      self.fields = [...] # same thing 
     else: 
      self.fields = ['approved'] 
     return super(PostAdmin, self).get_form(request, obj, **kwargs) 

इस तरह आप dzango में custom permission के एपीआई का उपयोग कर सकते हैं, और आप मॉडल को सहेजने के लिए विधियों को ओवरराइड कर सकते हैं या यदि आपको करना है तो क्वेरीसेट प्राप्त कर सकते हैं। मेथिड has_approval_permission में आप उस तर्क को परिभाषित कर सकते हैं जब उपयोगकर्ता कुछ कर सकता है या नहीं कर सकता है।

+0

आप शायद मतलब self.exclude = [ 'को मंजूरी दे दी'] get_form में () और वहाँ भी है changelist_view (में थोड़ा गड़बड़) ;) धन्यवाद, इस महान और टी से बिट्स के साथ संयुक्त लग रहा है पत्थर का जवाब, यह वही है जो मैं देख रहा हूं :) – minder

+0

क्या होगा यदि मुझे 'ऑब्जेक्ट में कोई विशेषता नहीं है' कुकीज '? – andi

+0

क्या व्यवस्थापक मॉड्यूल में कहीं और अनुमतियों को पंजीकृत किया जाना चाहिए? – andi

2

मेरे पास एक ऐसी परियोजना है जो मैं अभी खत्म कर रहा हूं।

  • आप एक संपादक और एक पर्यवेक्षक को परिभाषित करने के लिए एक तरह से की जरूरत है: वहाँ बहुत काम इस एक साथ रखा करने के लिए यहाँ हो जाएगा, लेकिन घटक है कि मैं अपने सिस्टम काम करने के लिए किया था से कुछ हैं। यह तीन तरीकों से किया जा सकता है 1.) एक एम 2 एम फ़ील्ड जो पर्यवेक्षक को परिभाषित करता है [और यह मानते हुए कि पढ़ने/लिखने की अनुमति के साथ हर कोई एक संपादक है], 2.) उपयोगकर्ता से प्राप्त होने वाले 2 नए उपयोगकर्ता मॉडल बनाएं [ संभवतः ज़्यादा से ज़्यादा काम] या 3.) उपयोगकर्ता प्रोफाइल को रखने के लिए django.auth क्षमता का उपयोग करें। विधि # 1 शायद सबसे उचित है।

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

  • अन्त में आप "जनक" मॉडल के कुछ प्रकार है कि अनुमतियों जो कुछ के लिए संचालित किए जाने की आवश्यकता का आयोजन करेगा की आवश्यकता होगी। उदाहरण के लिए, यदि आपके पास एक ब्लॉग मॉडल और ब्लॉगपोस्ट मॉडल था (उसी साइट के भीतर कई ब्लॉग मानते हैं), तो ब्लॉग मूल मॉडल है (यह अनुमति देता है कि कौन मंजूरी देता है)। हालांकि, अगर आपके पास एक ब्लॉग है और ब्लॉगपोस्ट के लिए कोई मूल मॉडल नहीं है, तो हमें अनुमतियों को संग्रहीत करने के लिए कुछ जगह चाहिए। मैंने पाया है कि ContentType यहां अच्छी तरह से काम करता है।

यहाँ कोड (अपरीक्षित और वास्तविक से ज्यादा वैचारिक) में कुछ विचार है।

'मॉडरेटेड' नामक एक नया ऐप बनाएं जो हमारी सामान्य सामग्री को पकड़ लेगा।

moderated.models.py

class ModeratedModelParent(models.Model): 
    """Class to govern rules for a given model""" 
    content_type = models.OneToOneField(ContentType) 
    can_approve = models.ManyToManyField(User) 

class ModeratedModel(models.Model): 
    """Class to implement a model that is moderated by a supervisor""" 
    is_approved = models.BooleanField(default=False) 

    def get_parent_instance(self): 
     """ 
     If the model already has a parent, override to return the parent's type 
     For example, for a BlogPost model it could return self.parent_blog 
     """ 

     # Get self's ContentType then return ModeratedModelParent for that type 
     self_content_type = ContentType.objects.get_for_model(self) 
     try:    
      return ModeratedModelParent.objects.get(content_type=self_content_type) 
     except: 
      # Create it if it doesn't already exist... 
      return ModeratedModelParent.objects.create(content_type=self_content_type).save() 

    class Meta: 
     abstract = True 

तो अब हम कोड की एक सामान्य, फिर से प्रयोग करने योग्य बिट कि हम दिए गए मॉडल के लिए अनुमति की पहचान कर सकते हैं (जो हम मॉडल की पहचान करेंगे होना चाहिए इसके सामग्री प्रकार से)।

इसके बाद, हम हमारी नीतियों व्यवस्थापक में, फिर से एक सामान्य मॉडल के माध्यम से लागू कर सकते हैं:

moderated.admin.py

class ModeratedModelAdmin(admin.ModelAdmin): 

    # Save our request object for later 
    def __call__(self, request, url): 
     self.request = request 
     return super(ModeratedModelAdmin, self).__call__(request, url) 

    # Adjust our 'is_approved' widget based on the parent permissions 
    def formfield_for_dbfield(self, db_field, **kwargs): 
     if db_field.name == 'is_approved': 
      if not self.request.user in self.get_parent_instance().can_approve.all(): 
       kwargs['widget'] = forms.CheckboxInput(attrs={ 'disabled':'disabled' }) 

    # Enforce our "unapproved" policy on saves 
    def save_model(self, *args, **kwargs): 
     if not self.request.user in self.get_parent_instance().can_approve.all(): 
      self.is_approved = False 
     return super(ModeratedModelAdmin, self).save_model(*args, **kwargs) 

इन एक बार सेटअप और काम कर रहा है, हम फिर से कर सकते हैं उन्हें कई मॉडलों में उपयोग करें जैसा कि मैंने पाया है कि एक बार जब आप इस तरह के कुछ के लिए संरचित अनुमतियां जोड़ते हैं, तो आप आसानी से इसे कई अन्य चीजों के लिए चाहते हैं।

उदाहरण के लिए मान लें कि आप एक समाचार मॉडल है, तो आप बस और यह मॉडल हम अभी किए गए बंद के वारिस बनाने के लिए की आवश्यकता होगी आप अच्छा कर रहे हैं।

# in your app's models.py 
class NewsItem(ModeratedModel): 
    title = models.CharField(max_length=200) 
    text = models.TextField() 


# in your app's admin.py 
class NewsItemAdmin(ModeratedModelAdmin): 
    pass 

admin.site.register(NewsItem, NewsItemAdmin) 

मुझे यकीन है कि मैं वहाँ में कुछ कोड त्रुटियों और गलतियाँ की, लेकिन उम्मीद है कि इस आप कुछ विचार एक शुभारंभ पैड जो कुछ के लिए आप लागू करने का निर्णय के रूप में कार्य करने के लिए दे सकते हैं हूँ।

आखिरी बात आप क्या करना है, जो मैं आप पर निर्भर छोड़ देंगे, is_approved मदों के लिए छानने लागू करने के लिए है। (। यानी आप नहीं है ना अन-स्वीकृत आइटम समाचार अनुभाग में सूचीबद्ध किया जा रहा है?)

2

समस्या दृष्टिकोण @ diegueus9 द्वारा उल्लिखित का उपयोग कर कि ModelAdmin में कार्य करता है एक सिंगलटन पसंद आया है और प्रत्येक अनुरोध के लिए instanced नहीं है। इसका अर्थ यह है कि प्रत्येक अनुरोध उसी मॉडलएडमिन ऑब्जेक्ट को संशोधित कर रहा है जिसे अन्य अनुरोधों द्वारा एक्सेस किया जा रहा है, जो आदर्श नहीं है। नीचे @ diegueus9 द्वारा प्रस्तावित समाधान है:

# For example, get_form() modifies the single PostAdmin's fields on each request 
... 
class PostAdmin(ModelAdmin): 
    def get_form(self, request, obj=None, **kwargs): 
     if not has_approval_permission(request, obj): 
      self.fields = [...] # list of fields to show if user can't approve the post 
     else: 
      self.fields = ['approved', ...] # add 'approved' to the list of fields if the user can approve the post 
... 

एक वैकल्पिक दृष्टिकोण fields तो जैसे माता पिता की get_form() विधि में किसी कीवर्ड आर्ग के रूप में पारित करने के लिए होगा:

... 
from django.contrib.admin.util import flatten_fieldsets 

class PostAdmin(ModelAdmin): 
    def get_form(self, request, obj=None, **kwargs): 
     if has_approval_permission(request, obj): 
      fields = ['approved'] 
      if self.declared_fieldsets: 
       fields += flatten_fieldsets(self.declared_fieldsets) 

      # Update the keyword args as needed to allow the parent to build 
      # and return the ModelForm instance you require for the user given their perms 
      kwargs.update({'fields': fields}) 
     return super(PostAdmin, self).get_form(request, obj=None, **kwargs) 
... 

इस तरह, आप को संशोधित नहीं कर रहे हैं प्रत्येक अनुरोध पर PostAdmin सिंगलटन; आप बस माता-पिता से मॉडलफॉर्म बनाने और वापस करने के लिए आवश्यक उपयुक्त कीवर्ड तर्कों को पारित कर रहे हैं।

यह शायद अधिक जानकारी के लिए आधार ModelAdmin पर get_form() विधि को देख के लायक है: https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/options.py#L431

2

Django 1.7 से, आप अब get_fields हुक जो यह इतना सरल सशर्त क्षेत्रों को लागू करने के लिए बनाता है उपयोग कर सकते हैं।

class MyModelAdmin(admin.ModelAdmin): 
    ... 

    def get_fields(self, request, obj=None): 
     fields = super(MyModelAdmin, self).get_fields(request, obj) 
     if request.user.is_superuser: 
      fields += ('approve',) 

     return fields 
+0

ग्रेट तकनीक लेकिन 'फ़ील्ड = self.fields' के परिणामस्वरूप मेरे लिए 'कोई नहीं'।मैंने उस पंक्ति को 'फ़ील्ड = सुपर (माईमोडेलएडमिन, स्वयं) में बदल दिया .get_fields (अनुरोध, ओबीजे)' और यह एक आकर्षण की तरह काम करता था। – PaulR

+0

अच्छा पकड़ो। मैंने अपना जवाब अपडेट किया। – mixxorz

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

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