我想在Django管理员中为这种模型实现“另存为新”功能:
class Plasmid (models.Model):
name = models.CharField("Name", max_length = 255, blank=False)
other_name = models.CharField("Other Name", max_length = 255, blank=True)
selection = models.CharField("Selection", max_length = 50, blank=False)
created_by = models.ForeignKey(User)
在管理员中,如果请求质粒对象的用户与创建该对象的用户不同,则上述某些字段将设置为只读。如果用户相同,则他们都是可编辑的。例如:
class PlasmidPage(admin.ModelAdmin):
def get_readonly_fields(self, request, obj=None):
if obj:
if not request.user == obj.created_by:
return ['name', 'created_by',]
else:
return ['created_by',]
else:
return []
def change_view(self,request,object_id,extra_context=None):
self.fields = ('name', 'other_name', 'selection', 'created_by',)
return super(PlasmidPage,self).change_view(request,object_id)
我遇到的问题是,当字段为只读并且用户单击“另存为新”按钮时,该字段的值不会“传输”到新对象。另一方面,将传输非只读字段的值。
有人吗,或者我怎么能解决这个问题?我想将只读和非只读字段的值都传输到新对象。
答案 0 :(得分:0)
您尝试使用 Field.disabled属性吗?
禁用的布尔参数设置为True时,将使用禁用的HTML属性禁用表单字段,以便用户无法对其进行编辑。即使用户篡改了提交给服务器的字段的值,也将忽略该字段,而使用表单的初始数据中的值。
我在项目中进行了快速测试。当我添加新条目时,禁用的字段已发送到服务器。 所以这样的事情应该为您工作:
class PlasmidPage(admin.ModelAdmin):
def get_form(self, request, *args, **kwargs):
form = super(PlasmidPage, self).get_form(request, *args, **kwargs)
if not request.user == self.cleaned_data['created_by'].:
form.base_fields['created_by'].disabled = True
form.base_fields['name'].disabled = True
def change_view(self,request,object_id,extra_context=None):
self.fields = ('name', 'other_name', 'selection', 'created_by',)
return super(PlasmidPage,self).change_view(request,object_id)
答案 1 :(得分:0)
发生这种情况是因为Django使用request.POST数据来构建新对象,但是只读字段未随请求主体一起发送。您可以通过以下方式克服此问题:将小部件设置为只读,而不是将字段本身设置为:
form.fields['name'].widget.attrs = {'readonly': True}
这有一个缺点:仍然可以通过篡改表单来更改字段值(例如,如果您使用devtools控制台从窗口小部件中删除了该只读属性)。您可以通过检查clean()
方法中的值实际上没有更改来对此加以保护。
因此完整的解决方案将是:
class PlasmidForm(models.ModelForm):
class Meta:
model = Plasmid
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance and not self.instance.created_by == request.user:
self.fields['name'].widget.attrs = {'readonly': True}
def clean(self):
cleaned_data = super().clean()
if self.instance and not self.instance.created_by == request.user:
self.cleaned_data['name'] = instance.name # just in case user tampered with the form
return cleaned_data
class PlasmidAdmin(admin.ModelAdmin):
form = PlasmidForm
readonly_fields = ('created_by',)
def save_model(self, request, obj, form, change):
if obj.created_by is None:
obj.created_by = request.user
super().save_model(request, obj, form, change)
注意,我将created_by
保留为只读状态,而是在保存对象时使用当前用户填充它。我不认为您真的要从另一个对象转移此属性。