Django - 我如何才能使管理 *changelist* 界面中的表格中的单元格只有在它为空时才可编辑?
问题描述
我希望我的数据在 Django 管理页面中是可编辑的.但是,我只希望每行中的某些字段列是可编辑的.这些列将随每一行而改变.基本上,如果某个单元格中的值为空,我希望显示一个下拉选项.如果它不为空,那么我不希望它是可编辑的并且希望它是只读的.
I would like my data to be editable inline in the Django admin page. However, I only want some fields columns in each row to be editable. These columns will change for each row. Basically, I want a dropdown choice to be displayed if the value in a certain cell is null. If it is not null, then I don't want it to be editable and would like it to be readonly.
models.py
:
class Size(models.Model):
size = models.CharField(max_length=20, primary_key=True)
class Book(models.Model):
title = models.CharField(max_length=100, primary_key=True)
size = models.ForeignKey(Size, null=False)
class Pamphlet(models.Model):
title = models.CharField(max_length=100, primary_key=True)
size = models.ForeignKey(Size, null=True)
book = models.ForeignKey(Book, null=True)
admin.py
:
class PamphletAdmin(admin.ModelAdmin):
model = Pamphlet
list_editable = ('size','book')
list_display = ('title', 'size', 'book',)
def get_changelist_form(self, request, **kwargs):
return PamphletChangeListForm
forms.py
:
class PamphletChangeListForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PamphletChangeListForm, self).__init__(*args, **kwargs)
instance = kwargs.get('instance')
if instance:
self.fields['book'].queryset = Book.objects.filter(
size=instance.size
)
if instance.size is not None:
self.fields['size'].widget.attrs['readonly'] = 'readonly'
此设置不适用于我.size
在更改列表表单中显示为可编辑,即使它不为空.还有 - 我有什么不明白的?
This setup is not working for me. The size
shows as editable in the changelist form even when it is not null. Also - what have I failed to understand?
解决方案
如果您的字段使用 input
元素,例如 TextField
,请添加 readonly
属性到更改列表表单的 __init__
方法中的字段小部件的 attrs
dict.像这样的:
If your field uses an input
element, such as a TextField
, add the readonly
attribute to the field's widget's attrs
dict in the changelist form's __init__
method. Something like this:
class PamphletChangeListForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PamphletChangeListForm, self).__init__(*args, **kwargs)
instance = kwargs.get('instance')
if instance:
self.fields['book'].queryset = Book.objects.filter(
size=instance.size
)
if instance.size is not None:
self.fields['size'].widget.attrs['readonly'] = 'readonly'
这不会保护您免受恶意用户伪造帖子数据的侵害 - 因为您需要进一步自定义您的管理员.但是,如果您的管理员中有恶意用户,您的问题就更大了.
That won't protect you against a malicious user faking post data - for that you'd need to customize your admin further. But if you have malicious users on your admin you have bigger problems.
如果您的字段使用 select
元素,则必须对其进行更多更改 - select
属性没有 readonly
作为受支持的属性.相反,您需要一个具有不变值的隐藏输入和一个文本表示,以便用户可以看到设置是什么.Django 不包含这样的小部件,但您可以定义自己的:
If your field uses a select
element, you have to change it more - select
attributes don't have readonly
as a supported attribute. Instead, you'll want a hidden input with the unchanging value, and a text representation so the user can see what the setting is. Django does not include such a widget, but you can define your own:
class LabeledHiddenInput(forms.widgets.HiddenInput):
def render(self, name, value, attrs=None):
base_output = super(LabeledHiddenInput, self).render(name, value, attrs)
if value:
return base_output + unicode(value)
else:
return base_output
您可能需要更小心的转义甚至一些 HTML 格式,这只是一个简单的示例.如果您需要更多示例,请查看内置小部件的源代码.
You might need more careful escaping or even some HTML formatting, this is just a quick example. Check the source code for the built in widgets if you need more examples.
然后您可以使用该小部件而不是默认选择:
Then you can use that widget instead of the default select:
if instance.size is not None:
self.fields['size'].widget = LabeledHiddenInput()
相关文章