31

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

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

我将如何在 django 管理员中创建“查看”权限,以便用户可以修改某些表的数据,同时对其他表具有只读访问权限?

更新:Django Admin 似乎给了我一个 CRUD 接口的 CUD。如何获得具有关联权限和组的只读部分?

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


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

4

6 回答 6

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. 测试 'view' 权限被添加到所有模型

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 似乎可以控制是否出现保存/保存和继续按钮。将“保存”字段从默认的始终为真更改,以检查上下文和权限。如果他们有更改或添加权限,用户应该能够保存。

 '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 属性添加到表单元素。并非所有浏览器都支持这一点,但出于我的目的,我可以要求用户使用正确的浏览器。 禁用/只读示例

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

#/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 %}
于 2009-08-28T16:21:43.870 回答
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
于 2012-04-28T22:16:30.277 回答
6

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

更新:对不起,我误解了这个问题,因为我误解了 view 这个词,赋予它 Django 的含义,而不是“只读”。如果您想使用管理员只读,我认为您需要做一些工作。请参阅此线程,其中 James Bennett(Django 发布经理)说:

正如您通过搜索此列表的档案所发现的那样,这不是 Django 管理界面旨在支持的东西,因此任何解决方案都需要完全来自您编写自己的代码。

Django 管理员对三个权限进行操作:“添加”、“更改”和“删除”。没有“查看但不修改”权限,因此如果不进行重要的自定义编码,就无法应用这样的限制。

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

于 2009-08-26T17:57:48.477 回答
3

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

模型.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'),
        )

管理员.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

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

于 2012-10-16T21:31:21.950 回答
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

于 2010-01-27T19:02:25.857 回答
0

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

于 2012-01-18T05:36:46.837 回答