如何修改django以创建“查看”权限?

时间:2009-08-26 17:39:31

标签: django django-admin django-permissions

我最近开始使用django来管理使用twisted.web多年来有机增长的大型现有应用程序。我开始尝试使用django,它是自动管理界面,我对结果非常满意。

我的目的似乎缺少的一件事是能够为用户提供对数据的只读访问权限。例如,我们有一个角色,允许人们登录并创建采购订单。他们还需要能够查看,但不能编辑其他客户端或产品数据。

如何在django admin中创建“查看”权限,以便用户可以修改某些表的数据,同时只读取其他表的访问权限?

更新:Django Admin似乎给了我CRUD界面的CUD。如何获取具有关联权限和组的只读部分?

2010年2月12日更新:Django 1.2现在将包含只读。详情如下。


我猜我回答了自己的问题。将内容下移到下面的真实答案。

6 个答案:

答案 0 :(得分:35)

这就是我改变Django 1.0.2以添加“查看”权限的方式。对不起,没有差异可用。

[X] 1.在默认权限列表

中添加了“视图”
#./contrib/auth/management/__init__.py
def _get_all_permissions(opts):
    "Returns (codename, name) for all permissions in the given opts."
    perms = []
    for action in ('add', 'change', 'delete', 'view'):
        perms.append((_get_permission_codename(action, opts), u'Can %s %s' % (action, opts.verbose_name_raw)))
    return perms + list(opts.permissions)

[X] 2.测试'视图'权限被添加到所有模型

run manage.py syncdb

我确认现在为auth_permissions表中的所有表添加了视图权限

[X] 3.将“get_view_permission”添加到默认模型类。

将get_view_permission添加到模型类。您可以在./db/models/options.py文件中找到它。管理类将在下一步中使用它。

def get_view_permission(self):
    return 'view_%s' % self.object_name.lower()

[X] 4.将“has_view_permission”添加到默认管理类

为了保持一致,我要将“has_view_permission”添加到系统中。看起来它应该在 contrib / admin / options.py 中的某个地方。确保用户具有更改权限,然后自动隐含查看权限。

# /contrib/admin/options.py
# Added has_view_permissions
def has_view_permission(self, request, obj=None):
    """
    Returns True if the given request has permission to change or view
    the given Django model instance.

    If `obj` is None, this should return True if the given request has
    permission to change *any* object of the given type.
    """
    opts = self.opts
    return self.has_change_permission(request, obj) or \
        request.user.has_perm(opts.app_label + '.' + opts.get_view_permission())

# modified get_model_perms to include 'view' too.
# No idea where this may be used, but trying to stay consistent
def get_model_perms(self, request):
        """
        Returns a dict of all perms for this model. This dict has the keys
        ``add``, ``change``, and ``delete`` and ``view`` mapping to the True/False
        for each of those actions.
        """
        return {
            'add': self.has_add_permission(request),
            'change': self.has_change_permission(request),
            'delete': self.has_delete_permission(request),
            'view': self.has_view_permission(request),
        }

# modified response_add function to return the user to the mode list
# if they added a unit and have view rights
... 
    else:
        self.message_user(request, msg)

        # Figure out where to redirect. If the user has change permission,
        # redirect to the change-list page for this object. Otherwise,
        # redirect to the admin index.
        #if self.has_change_permission(request, None):
        if self.has_change_permission(request, None) or self.has_view_permission(request, None):
            post_url = '../'
        else:
            post_url = '../../../'
        return HttpResponseRedirect(post_url)

 # modified the change_view function so it becomes the details 
 # for users with view permission

    #if not self.has_change_permission(request, obj):
    if not (self.has_change_permission(request, obj) or (self.has_view_permission(request, obj) and not request.POST)):
        raise PermissionDenied


  # modified the changelist_view function so it shows the list of items
  # if you have view permissions
def changelist_view(self, request, extra_context=None):
    "The 'change list' admin view for this model."
    from django.contrib.admin.views.main import ChangeList, ERROR_FLAG
    opts = self.model._meta
    app_label = opts.app_label
    #if not self.has_change_permission(request, None):
    if not (self.has_change_permission(request, None) or self.has_view_permission(request, None)):
        raise PermissionDenied

[X] 5.如果用户具有查看权限,则更新默认模板以列出模型

我修改了contrib / admin / templates / admin / index.html中的默认模板。这也可以通过将文件复制到本地模板目录来处理。我对两者进行了更改,因此如果稍后的升级会覆盖我的更改,我会有一份副本。

 {% for model in app.models %}
            <tr>
            {% if model.perms.change %}
                <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
            {% else %}
                {% if model.perms.view %}
                    <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
                {% else %}
                    <th scope="row">{{ model.name }}</th>
                {% endif %}
            {% endif %}

[X] 6.确认用户可以“查看”但不能“更改”模型

发现contrib / admin / templatetags / admin_modify.py似乎控制了保存/保存和继续按钮的显示与否。将“保存”字段更改为默认值始终为True,以检查上下文和权限。如果用户有更改或添加权限,他们应该可以保存。

 'show_save': (change and context['has_change_permission']) or (context['add'] and context['has_add_permission'])

[X] 7.如果用户正在查看项目

,请删除“保存并添加另一个”按钮

再次修改contrib / admin / templatetags / admin_modify.py。我不知道'save_as'是什么意思所以也许我打破了一些东西,但似乎有效。

    #'show_save_and_add_another': context['has_add_permission'] and
    #                    not is_popup and (not save_as or context['add']) ,
    'show_save_and_add_another': not is_popup and
        (( change and context['has_change_permission']) or (context['add'] and context['has_add_permission']))
        and
        (not save_as or context['add']),

[X] 8.修改“查看”权限,使表格只读

如果用户具有“查看”权限和“更改”权限,则不执行任何操作。更改覆盖视图。

如果用户具有“查看”权限而没有“更改”,则更改默认表单并将DISABLED或READONLY属性添加到表单元素。并非所有浏览器都支持此功能,但出于我的目的,我可以要求用户使用正确的浏览器。 Disabled / Readonly example

发现并非所有浏览器都尊重“readonly”,因此它将一些控件设置为readonly,其他控件设置为disabled。这允许用户在需要时从文本控件复制数据。

#/django/contrib/admin/templates/admin/change_form.html

{# JavaScript for prepopulated fields #}
{% prepopulated_fields_js %}

</div>
</form></div>
{% if has_view_permission and not has_change_permission %}
    <script type="text/javascript">
    jQuery('input:text').attr('readonly', 'readonly');
    jQuery('textarea').attr('readonly', 'readonly');
    jQuery('input:checkbox').attr('disabled', true);
    jQuery('select').attr('disabled', true);
    jQuery('.add-another').hide();
    </script>
{% endif %}

答案 1 :(得分:11)

此代码段将使超级用户成为唯一具有写访问权限的用户。

class AdminOwn(admin.ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        if request.user.is_superuser:
            return self.readonly_fields
        #get all fields as readonly
        fields = [f.name for f in self.model._meta.fields]
        return fields

答案 2 :(得分:6)

就在管理员那里。您可以在管理员中为用户和组设置权限,以添加,更改和删除特定模型。

更新:抱歉,我误解了这个问题,因为我误解了单词视图,给它Django含义而不是“只读”。如果你想使用管理员只读,我认为你需要做一些工作。见this thread,James Bennett(Django发布经理)说:

  

通过搜索你会发现   这个列表的档案,这不是   Django管理界面的东西   旨在支持,所以任何   解决方案需要完全解决   从你编写自己的代码。

  

Django管理员运行三个   权限:“添加”,“更改”和   “删除”。没有“观点而是制造   没有修改“许可,因此   没有办法申请这样的   限制没有重要   自定义编码。

额外的工作将涉及为某些模型添加“只读”权限,并更改基本管理模板以检查用户是否具有该权限 - 如果是,则禁用某些控件(如保存按钮)并制作其他模板只读。这样可以防止随意修改,但您可能还需要修改服务器端逻辑以检查相同的权限,以避免以偷偷摸摸的方式进行任何POST以绕过权限。

答案 3 :(得分:3)

您可以在模型中创建“只读”权限,并使用jasuca的代码进行修改:

models.py:

class MyModel(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=256, null=True, blank=True)

    class Meta:
        permissions = (
            ('readonly_mymodel','Readonly MyModel'),
        )

admin.py:

class MyModelAdmin(admin.ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        if not request.user.is_superuser and request.user.has_perm('mymodel.readonly_mymodel'):
            return [f.name for f in self.model._meta.fields]
        return self.readonly_fields

在应用程序的管理员中,您必须向用户授予“更改”和“只读”权限。

答案 4 :(得分:2)

现在,Django 1.2版中包含了向管理视图添加只读字段的功能。

见票号342 http://code.djangoproject.com/ticket/342

请参阅变更集编号11965 http://code.djangoproject.com/changeset/11965

参见文档 http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields

答案 5 :(得分:0)

您可以在auth模块中创建组。然后在admin.py中根据用户组登录,设置modeladmin的readonly_fields属性。添加方法def has_add_permission(self,request)为具有readonly权限的组返回false。为组添加,修改权限。他们只能读取模型属性。