Python Django-如何使admin*changelist*界面中的表中的单元格仅在为空时才可编辑?
我希望我的数据可以在Django管理页面内联编辑。但是,我只希望每行中的一些字段列是可编辑的。每行的这些列都将更改。基本上,如果某个单元格中的值为null,我希望显示一个下拉选项。如果它不是null,那么我不希望它是可编辑的,并且希望它是只读的Python Django-如何使admin*changelist*界面中的表中的单元格仅在为空时才可编辑?,python,django,django-models,django-forms,django-admin,Python,Django,Django Models,Django Forms,Django Admin,我希望我的数据可以在Django管理页面内联编辑。但是,我只希望每行中的一些字段列是可编辑的。每行的这些列都将更改。基本上,如果某个单元格中的值为null,我希望显示一个下拉选项。如果它不是null,那么我不希望它是可编辑的,并且希望它是只读的 models.py: class Size(models.Model): size = models.CharField(max_length=20, primary_key=True) class Book(models.Model):
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)
class PamphletAdmin(admin.ModelAdmin):
model = Pamphlet
list_editable = ('size','book')
list_display = ('title', 'size', 'book',)
def get_changelist_form(self, request, **kwargs):
return PamphletChangeListForm
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'
admin.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)
class PamphletAdmin(admin.ModelAdmin):
model = Pamphlet
list_editable = ('size','book')
list_display = ('title', 'size', 'book',)
def get_changelist_form(self, request, **kwargs):
return PamphletChangeListForm
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'
forms.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)
class PamphletAdmin(admin.ModelAdmin):
model = Pamphlet
list_editable = ('size','book')
list_display = ('title', 'size', 'book',)
def get_changelist_form(self, request, **kwargs):
return PamphletChangeListForm
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'
此设置不适用于我。
大小
在变更列表表单中显示为可编辑,即使它不为空。还有-我没有理解什么?如果您的字段使用了输入
元素,例如文本字段
,请将只读
属性添加到更改列表表单的初始化
方法中字段小部件的属性中。大概是这样的:
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'
这并不能保护你免受恶意用户伪造帖子数据的攻击——为此,你需要进一步自定义你的管理员。但是如果你的管理员中有恶意用户,你就会遇到更大的问题
如果字段使用select
元素,则必须对其进行更多更改-select
属性不支持readonly
。相反,您需要一个具有不变值的隐藏输入,以及一个文本表示,以便用户可以看到设置是什么。Django不包括此类小部件,但您可以定义自己的小部件:
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格式,这只是一个简单的示例。如果需要更多示例,请检查内置小部件的源代码
然后您可以使用该小部件而不是默认的选择:
if instance.size is not None:
self.fields['size'].widget = LabeledHiddenInput()
您是想在变更列表中还是在小册子编辑页面中执行此操作?我可以马上告诉你,你的管理类出了点问题——有一个小册子管理员和一个内联模型,因为小册子不符合你展示的模型关系。一个图书管理类可能会有一个小册子的内联模型。我正试图在变更列表中这样做。我认为内联实际上是指变更列表。我认为“内联”的意思是“表格每一行中出现的表单”。不,内联是用于编辑页面的,所以你可以(使用这个例子)同时编辑一本书和所有与之相关的小册子。我将在变更列表中添加一个答案,说明我将如何处理此问题。谢谢,我已对我的问题进行了编辑。我正在极大地简化我的实际模型,以关注这个问题,因此出现了一些拼写错误。然而,您的解决方案显然不起作用。如果我可以使用类似于ModelAdmin.get\u readonly\u字段(request,obj=None)
的功能,这将非常好:get\u readonly\u字段
只影响编辑页面,而不影响变更列表。如果您确实在某个地方使用内联线,它将是相关的。如果没有“它不起作用”以外的更多信息,我无法对变更列表解决方案进行进一步调试-我建议的第一件事是检查HTML,看看是否存在readonly
属性。是的,我可以在HTML中找到readonly属性:例如:1[etc]
,但变更列表页面看起来完全相同,有所有下拉选项的小部件就在那里,并且似乎可以正常工作。哦,对了<代码>只读
仅适用于输入
元素,而不是选择
。不幸的是,select
的解决方案有点复杂-您需要完全替换小部件,并且没有一个内置的小部件可以做正确的事情,因此您必须定义自己的小部件。我会更新的。