Python Django-如何使admin*changelist*界面中的表中的单元格仅在为空时才可编辑?

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):

我希望我的数据可以在Django管理页面内联编辑。但是,我只希望每行中的一些字段列是可编辑的。每行的这些列都将更改。基本上,如果某个单元格中的值为null,我希望显示一个下拉选项。如果它不是null,那么我不希望它是可编辑的,并且希望它是只读的

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
的解决方案有点复杂-您需要完全替换小部件,并且没有一个内置的小部件可以做正确的事情,因此您必须定义自己的小部件。我会更新的。