मैं सामग्री प्रकार या मॉडल को परिभाषित किए बिना Django अनुमतियों का उपयोग कैसे कर सकता हूं?


84

मैं अपने Django एप्लिकेशन के भीतर कुछ कार्यों को प्रतिबंधित करने के लिए अनुमतियों पर आधारित प्रणाली का उपयोग करना चाहता हूं। इन क्रियाओं को किसी विशेष मॉडल से संबंधित नहीं होना चाहिए (जैसे एप्लिकेशन में अनुभागों तक पहुंच, खोज ...), इसलिए मैं सीधे स्टॉक अनुमतियों के ढांचे का उपयोग नहीं कर सकता , क्योंकि Permissionमॉडल को स्थापित सामग्री प्रकार के संदर्भ की आवश्यकता होती है।

मैं अपना स्वयं का अनुमति मॉडल लिख सकता हूं लेकिन फिर मुझे Django अनुमतियों के साथ शामिल सभी अच्छाइयों को फिर से लिखना होगा, जैसे:

मैंने कुछ एप्लिकेशन जैसे django-Authority और django-guardian की जाँच की है , लेकिन वे प्रति-ऑब्जेक्ट अनुमति देकर मॉडल सिस्टम को और भी अधिक युग्मित करने की अनुमति प्रदान करते हैं।

क्या परियोजना के लिए किसी भी मॉडल (इसके अलावा Userऔर Group) को परिभाषित किए बिना इस ढांचे का पुन: उपयोग करने का एक तरीका है ?

जवाबों:


57

Django के Permissionमॉडल को एक ContentTypeउदाहरण की आवश्यकता है

मुझे लगता है कि इसके चारों ओर एक रास्ता ऐसा डमी बना रहा है ContentTypeजो किसी भी मॉडल से संबंधित नहीं है ( app_labelऔर modelफ़ील्ड्स को किसी भी स्ट्रिंग मान पर सेट किया जा सकता है)।

यदि आप यह सब साफ और अच्छा चाहते हैं, तो आप एक Permission प्रॉक्सी मॉडल बना सकते हैं जो डमी के सभी बदसूरत विवरणों को संभालता है ContentTypeऔर "मॉडेलस" अनुमति उदाहरण बनाता है। आप एक कस्टम प्रबंधक भी जोड़ सकते हैं जो Permissionवास्तविक मॉडल से संबंधित सभी उदाहरणों को फ़िल्टर करता है ।


3
यदि आपको कोई आपत्ति नहीं है, तो मैं आपके उत्तर को अपने कार्यान्वयन के साथ पूरा करूँगा।
Chewie

अफसोस की बात है कि मैं यह स्वीकार नहीं कर सकता कि आपके संपादन की समीक्षा करने के लिए मेरे पास पर्याप्त प्रतिष्ठा नहीं है (यह मुझसे 2k के लिए पूछता है)। अन्य उपयोगकर्ता आपके संपादनों को अस्वीकार कर रहे हैं, इसलिए मेरा सुझाव है कि आप इसे एक और उत्तर के रूप में जोड़ दें (आपके पास मेरा उत्थान है!) फिर से धन्यवाद।
गोंजालो

1
वह अजीब है। यह वास्तव में आपके उत्तर के लिए एक पूर्णता है, इसलिए यह इसे संपादित करने के लिए समझ में आता है। वैसे भी, मैंने इसे दूसरे जवाब में डाल दिया।
Chewie

138

आप में से उन लोगों के लिए, जो अभी भी खोज रहे हैं:

आप एक डेटाबेस तालिका के साथ एक सहायक मॉडल बना सकते हैं। वह मॉडल आपके प्रोजेक्ट को आपकी अनुमति के लिए ला सकता है। ContentType से निपटने या अनुमति ऑब्जेक्ट को स्पष्ट रूप से बनाने की कोई आवश्यकता नहीं है।

from django.db import models
        
class RightsSupport(models.Model):
            
    class Meta:
        
        managed = False  # No database table creation or deletion  \
                         # operations will be performed for this model. 
                
        default_permissions = () # disable "add", "change", "delete"
                                 # and "view" default permissions

        permissions = ( 
            ('customer_rights', 'Global customer rights'),  
            ('vendor_rights', 'Global vendor rights'), 
            ('any_rights', 'Global any rights'), 
        )

ठीक इसके बाद manage.py makemigrationsऔर manage.py migrateआप किसी अन्य की तरह इन अनुमतियों का उपयोग कर सकते हैं।

# Decorator

@permission_required('app.customer_rights')
def my_search_view(request):
    …

# Inside a view

def my_search_view(request):
    request.user.has_perm('app.customer_rights')

# In a template
# The currently logged-in user’s permissions are stored in the template variable {{ perms }}

{% if perms.app.customer_rights %}
    <p>You can do any customer stuff</p>
{% endif %}

2
यह प्रतिभा है, मेरा दिन बचाओ!
रोरक्स

2
मेरे द्वारा प्रबंधित किए जाने के बाद कुछ नहीं बदला। माइग्रेट करने के बाद ... मुझे कोई नई अनुमतियां नहीं दिख रही हैं :(
आयु 15

2
क्या आपने अपने ऐप को अपने प्रोजेक्ट (INSTALLED_APPS) में जोड़ा है?
दिमित्री

2
यह उत्तर एकदम सही है। मैं [] एड default_permissions, मॉडल के सेव () पर NotImplementedError बढ़ाता हूं, और बनाने पर विचार कर सकता है, अगर अप्रबंधित मॉडल वास्तव में इस अनुमति के लिए JUST है तो _ * _ अनुमति () लौटाएं।
डगलस डेनहरटोग

4
मैं निम्नलिखित मेटा क्लास में जोड़ने का सुझाव देता हूं default_permissions = ():। यह Django को स्वचालित रूप से इस मॉडल के लिए डिफ़ॉल्ट ऐड / चेंज / डिलीट / व्यू परमिशन बनाने से रोकेगा, जो कि इस दृष्टिकोण का उपयोग करने पर सबसे अधिक अनावश्यक हैं।
जॉर्डन

51

गोंज़ालो की सलाह के बाद , मैंने एक डमी सामग्री प्रकार के साथ मेरी "मॉडेलस" अनुमतियों को संभालने के लिए एक प्रॉक्सी मॉडल और एक कस्टम मैनेजर का उपयोग किया ।

from django.db import models
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType


class GlobalPermissionManager(models.Manager):
    def get_query_set(self):
        return super(GlobalPermissionManager, self).\
            get_query_set().filter(content_type__name='global_permission')


class GlobalPermission(Permission):
    """A global permission, not attached to a model"""

    objects = GlobalPermissionManager()

    class Meta:
        proxy = True

    def save(self, *args, **kwargs):
        ct, created = ContentType.objects.get_or_create(
            name="global_permission", app_label=self._meta.app_label
        )
        self.content_type = ct
        super(GlobalPermission, self).save(*args, **kwargs)

10
कोड के लिए धन्यवाद, इस कोड का उपयोग करने के तरीके पर एक उदाहरण दिखाना भी अच्छा होगा।
केन कोचरन

2
उस मॉडल की अनुमति कहां रहनी चाहिए?
मिरात कैन बयार

4
GlobalPermission बनाने के लिए: app.models से GlobalPermission gp = GlobalPermission.objects.create (कोडनाम = 'can_do_it', name = 'can it') आयात करें। एक बार जब यह चलाया जाता है तो आप किसी अन्य अनुमति की तरह उपयोगकर्ताओं / समूह में उस अनुमति को जोड़ सकते हैं ।
जूलियन ग्रेनियर

3
@JulienGrenier कोड Django 1.8 में टूटता है FieldError: Cannot resolve keyword 'name' into field. Choices are: app_label, id, logentry, model, permission:।
मैकिक

2
चेतावनी: Django के नए संस्करणों (कम से कम 1.10) को "get_queryset" विधि को ओवरराइड करने की आवश्यकता है ("क्वेरी" और "सेट" शब्दों के बीच _ की कमी पर ध्यान दें।)
लोब

10

Django 1.8 में Chewie के उत्तर के लिए फिक्स, जिसे कुछ टिप्पणियों में अनुरोध किया गया था।

यह जारी नोटों में कहते हैं:

Django.contrib.contenttypes.models.ContentType का नाम फ़ील्ड माइग्रेशन द्वारा हटा दिया गया है और एक संपत्ति द्वारा प्रतिस्थापित किया गया है। इसका मतलब है कि इस फ़ील्ड द्वारा किसी भी सामग्री को किसी भी प्रकार से क्वेरी या फ़िल्टर करना संभव नहीं है।

तो यह ContentType के संदर्भ में 'नाम' है जिसका उपयोग GlobalPims में नहीं है।

जब मैं इसे ठीक करता हूं तो मुझे निम्नलिखित मिलते हैं:

from django.db import models
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType


class GlobalPermissionManager(models.Manager):
    def get_queryset(self):
        return super(GlobalPermissionManager, self).\
            get_queryset().filter(content_type__model='global_permission')


class GlobalPermission(Permission):
    """A global permission, not attached to a model"""

    objects = GlobalPermissionManager()

    class Meta:
        proxy = True
        verbose_name = "global_permission"

    def save(self, *args, **kwargs):
        ct, created = ContentType.objects.get_or_create(
            model=self._meta.verbose_name, app_label=self._meta.app_label,
        )
        self.content_type = ct
        super(GlobalPermission, self).save(*args)

GlobalPermissionManager वर्ग अपरिवर्तित है लेकिन पूर्णता के लिए शामिल है।


1
यह अभी भी django 1.8 के लिए इसे ठीक नहीं करता है जैसा कि syncdb django द्वारा दावा किया गया है कि "नाम" फ़ील्ड शून्य नहीं है।
अर्मिता

यह मेरे लिए काम करता है, लेकिन मैं अपने प्रोजेक्ट में अभी भी गैर-डेंगू विरासत सामान के कारण पलायन का उपयोग नहीं कर रहा हूं। क्या आप पिछले django से अपग्रेड कर रहे हैं, क्योंकि 1.8 में एक नाम फ़ील्ड नहीं माना जाता है
rgammans

4

यह वैकल्पिक समाधान है। पहले अपने आप से पूछें: डमी-मॉडल क्यों नहीं बनाते हैं जो वास्तव में डीबी में मौजूद है, लेकिन कभी भी अनुमतियों को छोड़कर, कभी भी उपयोग नहीं किया जाता है? यह अच्छा नहीं है, लेकिन मुझे लगता है कि यह वैध और सीधे आगे का समाधान है।

from django.db import models

class Permissions(models.Model):

    can_search_blue_flower = 'my_app.can_search_blue_flower'

    class Meta:
        permissions = [
            ('can_search_blue_flower', 'Allowed to search for the blue flower'),
        ]

उपरोक्त समाधान में यह लाभ है, कि आप Permissions.can_search_blue_flowerशाब्दिक स्ट्रिंग "my_app.can_search_blue_flower" का उपयोग करने के बजाय अपने स्रोत कोड में चर का उपयोग कर सकते हैं । इसका मतलब है कम टाइपोस और आईडीई में अधिक स्वत: पूर्ण।


1
क्या किसी कारण से उपयोग managed=Falseनहीं Permissions.can_search_blue_flowerकरने देता है?
सैम बोबेल

@Sambusel हाँ, आप सही हो सकते हैं। मुझे लगता है कि मैंने पिछली बार "अमूर्त" की कोशिश की थी।
गुत्थी

1

आप इसके proxy modelलिए डमी सामग्री प्रकार के साथ उपयोग कर सकते हैं ।

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType


class CustomPermission(Permission):

    class Meta:
        proxy = True

    def save(self, *args, **kwargs):
        ct, created = ContentType.objects.get_or_create(
            model=self._meta.verbose_name, app_label=self._meta.app_label,
        )
        self.content_type = ct
        super(CustomPermission, self).save(*args)

अब आप केवल nameऔर मॉडल codenameसे अनुमति के साथ अनुमति बना सकते हैं CustomPermission

 CustomPermission.objects.create(name='Can do something', codename='can_do_something')

और आप इस तरह से अपने टेम्प्लेट में केवल कस्टम अनुमतियों को क्वेरी और प्रदर्शित कर सकते हैं।

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