仅具有查看权限的 Django 模型表单将所有字段排除在外

Posted

技术标签:

【中文标题】仅具有查看权限的 Django 模型表单将所有字段排除在外【英文标题】:Django model form with only view permission puts all fields on exclude 【发布时间】:2019-11-25 04:11:17 【问题描述】:

如果表单为仅具有查看权限的用户呈现(Django 2.1 中的新功能),则在我的默认(django 管理员)更改视图中使用自定义 ModelForm 会给我一个空变量 self.fields

这是我的代码:

# models.py

class Door(ValidateOnSaveMixin, models.Model):
    ...

    motor_type = models.ForeignKey(
        MotorType,
        on_delete=models.SET_NULL,
        default=None,
        blank=True,
        null=True)
    ...
    door_type = models.CharField(
        max_length=3,
        choices=DOOR_TYPES,
        null=True,
        default=None)
    ...
    vehicle_variant = models.ForeignKey(
        VehicleVariant,
        on_delete=models.CASCADE)

    class Meta:
        unique_together = ("vehicle_variant", "location", "motor_type")

    ...



# admin.py

@admin.register(Door)
class DoorAdmin(ImportExportModelAdmin):
    form = DoorAdminForm

    list_display = ('descriptor', 'get_customer_link', 'get_variant', 'location', 'get_motor_type_link',
                    'window_type', 'door_type', 'drum_diameter', 'dist_per_motor_rotation')
    fields = ('vehicle_variant', 'description', 'location', 'motor_type',
              'drum_diameter', 'window_type', 'door_type')

    ...

# forms.py

class DoorAdminForm(ModelForm):

    class Meta:
        model = Door
        fields = '__all__'
        widgets = 
            'motor_type': DoorMotorTypeWidget,
        

    def __init__(self, *args, **kwargs):
        super(DoorAdminForm, self).__init__(*args, **kwargs)
        # this line is crashing on access with a user who has only the view permission, as self.fields is empty
        self.fields['vehicle_variant'].queryset = VehicleVariant.objects.all().prefetch_related('customer').order_by('customer__name', 'name')

根本原因与DoorAdminForm中Meta类的exclude属性有关。 无论我向字段/排除属性写入什么内容,模型的所有字段都会自动放入排除列表并防止填充self.fields。这使我的代码崩溃。

当然我可以检查'verhicle_variant' in self.fields,但我不明白这种行为的原因。我在 django 源代码中也找不到使用所有模型字段填充 exclude 属性的部分。

有人知道这是不是有意的?该行为的根本原因是什么(忽略 Meta 类的字段和排除属性)?

【问题讨论】:

【参考方案1】:

将所有字段放入exclude 的点在这里: https://github.com/django/django/blob/cf79f92abee2ff5fd4fdcc1a124129a9773805b8/django/contrib/admin/options.py#L674

我从未使用过仅具有“查看”权限的 django admin。还没有真正找到很多关于这应该是什么样子的信息:django-admin 带有添加和更改视图等,但没有 viewonly-view?几乎看起来它并不真正知道如何处理没有“更改”权限的用户。它将他们引导到 change_view,然后注意到他们不允许更改任何内容,因此它显示一个空表单? 我想您可以将所有字段声明为只读视图吗?


更新:vehicle_variant 字段不会出现在 form.fields 中,因为由于没有更改权限,它仍然会被排除在外,但至少您不会在表单的初始化时崩溃。除了所有内容都是只读的之外,我仍然不知道没有更改权限的 change_view 应该是什么样子。

class DoorAdminForm(ModelForm):
    qs = VehicleVariant.objects.prefetch_related('customer').order_by('customer__name', 'name')
    model_field = Door._meta.get_field('vehicle_variant')

    vehicle_variant = model_field.formfield(queryset=qs)

    class Meta:
        model = Door
        fields = '__all__'
        widgets = 
            'motor_type': DoorMotorTypeWidget,
        

【讨论】:

感谢您的链接!没看出来我认为他们在 CRUD 中实现 R 时做得很好 :) 所以 viewonly 视图实际上是更改视图,但不允许更改,这对我来说很有意义。如果我在管理类中使用 get_form 方法,我可以省略 change 参数并防止排除。但我目前不确定它会有什么副作用。我会调查的。 以其他方式设置vehicle_variant 的查询集可能更容易。在您的 DoorAdminForm? 上明确声明该字段? 你会怎么做?我决定不使用 get_form 方法,而是检查 self.仅视图中的字段我实际上不需要查询优化。但是从 if 语句来看,为什么我需要检查键仍然不是很明显。所以我想有一些自我记录的实施方式。但现在我很高兴在这些线上设置一些 cmets。 更新了我的帖子,希望我没有遗漏一些明显的东西。 我也使用了您对更新的建议,它适用于 ForeignKey 关系,但不适用于 ManyToMany。

以上是关于仅具有查看权限的 Django 模型表单将所有字段排除在外的主要内容,如果未能解决你的问题,请参考以下文章

DJANGO - 仅针对模型中的某些对象将管理面板的权限分配给用户

以原子方式比较-交换 Django 中的模型字段

具有浮点形式输入的 django 整数模型字段

在 Django 模型中保存时区

仅定义权限的 Django 模型中断测试

Django Admin:仅对一个模型字段使用自定义小部件