如何在Django中实现指定字段仅超级用户可编辑、普通用户只读
实现方案
以下针对不同使用场景分别给出实现方式:
1. Django Admin 后台权限控制
通过重写ModelAdmin的get_readonly_fields方法实现字段权限控制:
from django.contrib import admin from .models import QuestionModel class QuestionModelAdmin(admin.ModelAdmin): def get_readonly_fields(self, request, obj=None): # 非超级用户访问时,将answer字段加入只读列表 if not request.user.is_superuser: return self.readonly_fields + ('answer',) return self.readonly_fields admin.site.register(QuestionModel, QuestionModelAdmin)
2. 普通表单/类视图场景
首先自定义ModelForm,在初始化时根据当前用户权限设置字段是否禁用:
from django import forms from .models import QuestionModel class QuestionModelForm(forms.ModelForm): class Meta: model = QuestionModel fields = '__all__' def __init__(self, *args, **kwargs): # 从参数中获取当前登录用户 user = kwargs.pop('user', None) super().__init__(*args, **kwargs) if user and not user.is_superuser: # 设置answer字段为禁用,Django会自动忽略该字段的提交值,避免前端篡改绕过 self.fields['answer'].disabled = True
在视图中传递当前用户给表单即可,以通用更新视图为例:
from django.views.generic.edit import UpdateView from .models import QuestionModel from .forms import QuestionModelForm class QuestionUpdateView(UpdateView): model = QuestionModel form_class = QuestionModelForm success_url = '/questions/' def get_form_kwargs(self): kwargs = super().get_form_kwargs() # 将当前登录用户传入表单 kwargs['user'] = self.request.user return kwargs
3. Django REST Framework 接口场景
通过自定义序列化器的字段属性实现权限控制:
from rest_framework import serializers from .models import QuestionModel class QuestionModelSerializer(serializers.ModelSerializer): class Meta: model = QuestionModel fields = '__all__' def get_fields(self): fields = super().get_fields() request = self.context.get('request') # 非超级用户调用接口时,将answer字段设为只读 if request and not request.user.is_superuser: fields['answer'].read_only = True return fields
4. 模型层兜底校验
为了避免业务代码绕过视图层直接修改answer字段,可以重写模型的save方法做最终校验:
class QuestionModel(models.Model): # 原有字段定义保持不变 question = models.TextField() author = models.ForeignKey(User, on_delete=models.CASCADE) doubt_class_id = models.ForeignKey(DoubtClasses, on_delete=models.CASCADE, null=True, blank=True) conceptual_class_id = models.ForeignKey(LiveClass_details, on_delete=models.CASCADE, null=True, blank=True) mentor = models.ForeignKey(Mentor, on_delete=models.CASCADE, null=True, blank=True) answer = models.TextField(default='') def save(self, *args, **kwargs): user = kwargs.pop('user', None) # 非超级用户更新已有实例时,强制保持原有answer值不变 if self.pk and user and not user.is_superuser: original_obj = QuestionModel.objects.get(pk=self.pk) self.answer = original_obj.answer super().save(*args, **kwargs)
内容的提问来源于stack exchange,提问作者Dhruv singhal
相关产品推荐
相关产品推荐

