495

在 Django 表单中,如何将字段设置为只读(或禁用)?

当表单用于创建新条目时,应启用所有字段 - 但当记录处于更新模式时,某些字段需要是只读的。

例如,在创建新Item模型时,所有字段都必须是可编辑的,但在更新记录时,有没有办法禁用该sku字段,使其可见,但不能编辑?

class Item(models.Model):
    sku = models.CharField(max_length=50)
    description = models.CharField(max_length=200)
    added_by = models.ForeignKey(User)


class ItemForm(ModelForm):
    class Meta:
        model = Item
        exclude = ('added_by')

def new_item_view(request):
    if request.method == 'POST':
        form = ItemForm(request.POST)
        # Validate and save
    else:
            form = ItemForm()
    # Render the view

ItemForm可以重用吗?ItemFormItem模型类需要进行哪些更改?我是否需要编写另一个类“ ItemUpdateForm”来更新项目?

def update_item_view(request):
    if request.method == 'POST':
        form = ItemUpdateForm(request.POST)
        # Validate and save
    else:
        form = ItemUpdateForm()
4

28 回答 28

473

正如这个答案所指出的,Django 1.9 添加了Field.disabled属性:

disabled 布尔参数,当设置为 True 时,使用 disabled HTML 属性禁用表单字段,以便用户无法编辑它。即使用户篡改了提交给服务器的字段值,它也会被忽略,取而代之的是表单初始数据中的值。

使用 Django 1.8 及更早版本,要禁用小部件上的条目并防止恶意 POST 黑客攻击,除了readonly在表单字段上设置属性外,您还必须清理输入:

class ItemForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(ItemForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        if instance and instance.pk:
            self.fields['sku'].widget.attrs['readonly'] = True

    def clean_sku(self):
        instance = getattr(self, 'instance', None)
        if instance and instance.pk:
            return instance.sku
        else:
            return self.cleaned_data['sku']

或者,替换if instance and instance.pk为另一个表明您正在编辑的条件。disabled您还可以在输入字段上设置属性,而不是readonly.

clean_sku函数将确保该readonly值不会被 a 覆盖POST

否则,没有内置的 Django 表单字段会在拒绝绑定输入数据的同时呈现一个值。如果这是您想要的,您应该创建一个单独ModelForm的排除不可编辑的字段,然后将它们打印在您的模板中。

于 2008-11-28T04:09:23.527 回答
191

Django 1.9 添加了 Field.disabled 属性:https ://docs.djangoproject.com/en/stable/ref/forms/fields/#disabled

disabled 布尔参数,当设置为 True 时,使用 disabled HTML 属性禁用表单字段,以便用户无法编辑它。即使用户篡改了提交给服务器的字段值,它也会被忽略,取而代之的是表单初始数据中的值。

于 2015-12-30T22:22:00.283 回答
99

对小部件进行设置readonly只会使浏览器中的输入变为只读。添加clean_skuwhich 返回instance.sku可确保字段值不会在表单级别更改。

def clean_sku(self):
    if self.instance: 
        return self.instance.sku
    else: 
        return self.fields['sku']

这样您就可以使用模型(未修改的保存)并避免出现所需字段错误。

于 2008-12-01T17:25:04.500 回答
80

awalker的回答对我帮助很大!

我已经使用get_readonly_fields更改了他的示例以使用 Django 1.3 。

通常你应该在下面声明这样的东西app/admin.py

class ItemAdmin(admin.ModelAdmin):
    ...
    readonly_fields = ('url',)

我已经适应了这种方式:

# In the admin.py file
class ItemAdmin(admin.ModelAdmin):
    ...
    def get_readonly_fields(self, request, obj=None):
        if obj:
            return ['url']
        else:
            return []

它工作正常。现在,如果您添加一个项目,该url字段是可读写的,但在更改时它变为只读。

于 2011-08-13T10:25:18.187 回答
63

要使这项工作适用于某个ForeignKey领域,需要进行一些更改。首先,SELECT HTML标签没有只读属性。我们需要disabled="disabled"改用。但是,浏览器不会为该字段发送回任何表单数据。所以我们需要将该字段设置为不需要,以便该字段正确验证。然后我们需要将值重置回原来的值,这样它就不会被设置为空白。

因此,对于外键,您需要执行以下操作:

class ItemForm(ModelForm):

    def __init__(self, *args, **kwargs):
        super(ItemForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        if instance and instance.id:
            self.fields['sku'].required = False
            self.fields['sku'].widget.attrs['disabled'] = 'disabled'

    def clean_sku(self):
        # As shown in the above answer.
        instance = getattr(self, 'instance', None)
        if instance:
            return instance.sku
        else:
            return self.cleaned_data.get('sku', None)

这样浏览器就不会让用户更改字段,并且始终POST保持空白。然后我们重写该clean方法以将字段的值设置为实例中最初的值。

于 2009-09-14T23:47:47.857 回答
35

对于 Django 1.2+,您可以像这样覆盖该字段:

sku = forms.CharField(widget = forms.TextInput(attrs={'readonly':'readonly'}))
于 2011-01-10T14:03:02.673 回答
18

我创建了一个 MixIn 类,您可以继承它以便能够添加一个 read_only 可迭代字段,该字段将在非首次编辑时禁用和保护字段:

(基于 Daniel 和 Muhuk 的回答)

from django import forms
from django.db.models.manager import Manager

# I used this instead of lambda expression after scope problems
def _get_cleaner(form, field):
    def clean_field():
         value = getattr(form.instance, field, None)
         if issubclass(type(value), Manager):
             value = value.all()
         return value
    return clean_field

class ROFormMixin(forms.BaseForm):
    def __init__(self, *args, **kwargs):
        super(ROFormMixin, self).__init__(*args, **kwargs)
        if hasattr(self, "read_only"):
            if self.instance and self.instance.pk:
                for field in self.read_only:
                    self.fields[field].widget.attrs['readonly'] = "readonly"
                    setattr(self, "clean_" + field, _get_cleaner(self, field))

# Basic usage
class TestForm(AModelForm, ROFormMixin):
    read_only = ('sku', 'an_other_field')
于 2011-07-22T11:54:23.557 回答
12

我刚刚为只读字段创建了最简单的小部件 - 我真的不明白为什么表单还没有这个:

class ReadOnlyWidget(widgets.Widget):
    """Some of these values are read only - just a bit of text..."""
    def render(self, _, value, attrs=None):
        return value

在表格中:

my_read_only = CharField(widget=ReadOnlyWidget())

非常简单 - 让我只是输出。在带有一堆只读值的表单集中很方便。当然 - 你也可以更聪明一点,给它一个带有 attrs 的 div,这样你就可以向它附加类。

于 2013-02-28T11:40:12.783 回答
11

我遇到了类似的问题。看起来我可以通过在我的类中定义一个get_readonly_fields方法来解决它。ModelAdmin

像这样的东西:

# In the admin.py file

class ItemAdmin(admin.ModelAdmin):

    def get_readonly_display(self, request, obj=None):
        if obj:
            return ['sku']
        else:
            return []

好消息是,obj当您添加新项目时它将是无,或者当您更改现有项目时它将是正在编辑的对象。

get_readonly_display记录在这里

于 2011-03-08T20:51:34.080 回答
8

我如何使用 Django 1.11 做到这一点:

class ItemForm(ModelForm):
    disabled_fields = ('added_by',)

    class Meta:
        model = Item
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super(ItemForm, self).__init__(*args, **kwargs)
        for field in self.disabled_fields:
            self.fields[field].disabled = True
于 2017-07-24T15:34:58.527 回答
8

对于 django 1.9+,
您可以使用 Fields disabled 参数来禁用字段。例如,在 forms.py 文件中的以下代码片段中,我已禁用employee_code 字段

class EmployeeForm(forms.ModelForm):
    employee_code = forms.CharField(disabled=True)
    class Meta:
        model = Employee
        fields = ('employee_code', 'designation', 'salary')

参考 https://docs.djangoproject.com/en/dev/ref/forms/fields/#disabled

于 2018-03-26T08:15:13.413 回答
6

一个简单的选择是只输入form.instance.fieldName模板而不是form.fieldName.

于 2011-03-16T08:09:03.427 回答
6

再一次,我将提供另一种解决方案 :) 我使用的是Humphrey 的代码,所以这是基于此的。

但是,我遇到了字段是ModelChoiceField. 一切都会根据第一个请求进行。但是,如果表单集尝试添加新项目但验证失败,则SELECTED选项被重置为 default的“现有”表单出现问题---------

无论如何,我无法弄清楚如何解决这个问题。所以相反,(我认为这实际上在表单中更干净),我制作了 fields HiddenInputField()。这只是意味着您必须在模板中做更多的工作。

所以对我来说,解决方法是简化表格:

class ItemForm(ModelForm):

    def __init__(self, *args, **kwargs):
        super(ItemForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        if instance and instance.id:
            self.fields['sku'].widget=HiddenInput()

然后在模板中,您需要对formset 进行一些手动循环

因此,在这种情况下,您将在模板中执行以下操作:

<div>
    {{ form.instance.sku }} <!-- This prints the value -->
    {{ form }} <!-- Prints form normally, and makes the hidden input -->
</div>

这对我来说效果更好,而且形式操作更少。

于 2012-03-30T13:36:21.720 回答
5

作为对Humphrey 帖子的有用补充,我遇到了 django-reversion 的一些问题,因为它仍然将禁用字段注册为“已更改”。下面的代码解决了这个问题。

class ItemForm(ModelForm):

    def __init__(self, *args, **kwargs):
        super(ItemForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        if instance and instance.id:
            self.fields['sku'].required = False
            self.fields['sku'].widget.attrs['disabled'] = 'disabled'

    def clean_sku(self):
        # As shown in the above answer.
        instance = getattr(self, 'instance', None)
        if instance:
            try:
                self.changed_data.remove('sku')
            except ValueError, e:
                pass
            return instance.sku
        else:
            return self.cleaned_data.get('sku', None)
于 2011-03-10T03:28:10.370 回答
5

由于我还不能发表评论(muhuk 的解决方案),我将作为单独的答案回复。这是一个完整的代码示例,对我有用:

def clean_sku(self):
  if self.instance and self.instance.pk:
    return self.instance.sku
  else:
    return self.cleaned_data['sku']
于 2011-05-13T16:06:00.807 回答
4

我遇到了同样的问题,所以我创建了一个似乎适用于我的用例的 Mixin。

class ReadOnlyFieldsMixin(object):
    readonly_fields =()

    def __init__(self, *args, **kwargs):
        super(ReadOnlyFieldsMixin, self).__init__(*args, **kwargs)
        for field in (field for name, field in self.fields.iteritems() if name in self.readonly_fields):
            field.widget.attrs['disabled'] = 'true'
            field.required = False

    def clean(self):
        cleaned_data = super(ReadOnlyFieldsMixin,self).clean()
        for field in self.readonly_fields:
           cleaned_data[field] = getattr(self.instance, field)

        return cleaned_data

用法,只需定义哪些必须是只读的:

class MyFormWithReadOnlyFields(ReadOnlyFieldsMixin, MyForm):
    readonly_fields = ('field1', 'field2', 'fieldx')
于 2014-02-09T03:02:45.290 回答
4

根据Yamikep 的回答,我找到了一个更好且非常简单的解决方案,它也可以处理ModelMultipleChoiceField字段。

从中删除字段form.cleaned_data会阻止保存字段:

class ReadOnlyFieldsMixin(object):
    readonly_fields = ()

    def __init__(self, *args, **kwargs):
        super(ReadOnlyFieldsMixin, self).__init__(*args, **kwargs)
        for field in (field for name, field in self.fields.iteritems() if
                      name in self.readonly_fields):
            field.widget.attrs['disabled'] = 'true'
            field.required = False

    def clean(self):
        for f in self.readonly_fields:
            self.cleaned_data.pop(f, None)
        return super(ReadOnlyFieldsMixin, self).clean()

用法:

class MyFormWithReadOnlyFields(ReadOnlyFieldsMixin, MyForm):
    readonly_fields = ('field1', 'field2', 'fieldx')
于 2016-04-20T13:46:30.830 回答
4

如果您需要多个只读字段。您可以使用下面给出的任何方法

方法一

class ItemForm(ModelForm):
    readonly = ('sku',)

    def __init__(self, *arg, **kwrg):
        super(ItemForm, self).__init__(*arg, **kwrg)
        for x in self.readonly:
            self.fields[x].widget.attrs['disabled'] = 'disabled'

    def clean(self):
        data = super(ItemForm, self).clean()
        for x in self.readonly:
            data[x] = getattr(self.instance, x)
        return data

方法二

继承方法

class AdvancedModelForm(ModelForm):


    def __init__(self, *arg, **kwrg):
        super(AdvancedModelForm, self).__init__(*arg, **kwrg)
        if hasattr(self, 'readonly'):
            for x in self.readonly:
                self.fields[x].widget.attrs['disabled'] = 'disabled'

    def clean(self):
        data = super(AdvancedModelForm, self).clean()
        if hasattr(self, 'readonly'):
            for x in self.readonly:
                data[x] = getattr(self.instance, x)
        return data


class ItemForm(AdvancedModelForm):
    readonly = ('sku',)
于 2016-08-19T10:13:11.297 回答
4

您可以在小部件中优雅地添加只读:

class SurveyModaForm(forms.ModelForm):
    class Meta:
        model  = Survey
        fields = ['question_no']
        widgets = {
        'question_no':forms.NumberInput(attrs={'class':'form-control','readonly':True}),
        }
于 2020-08-02T14:04:32.783 回答
3

对于 Admin 版本,如果您有多个字段,我认为这是一种更紧凑的方式:

def get_readonly_fields(self, request, obj=None):
    skips = ('sku', 'other_field')
    fields = super(ItemAdmin, self).get_readonly_fields(request, obj)

    if not obj:
        return [field for field in fields if not field in skips]
    return fields
于 2012-06-15T21:44:12.160 回答
3

带有一个通用示例的另外两种(相似)方法:

1)第一种方法 - 删除 save() 方法中的字段,例如(未测试;)):

def save(self, *args, **kwargs):
    for fname in self.readonly_fields:
        if fname in self.cleaned_data:
            del self.cleaned_data[fname]
    return super(<form-name>, self).save(*args,**kwargs)

2)第二种方法 - 在 clean 方法中将字段重置为初始值:

def clean_<fieldname>(self):
    return self.initial[<fieldname>] # or getattr(self.instance, fieldname)

基于第二种方法,我将其概括如下:

from functools                 import partial

class <Form-name>(...):

    def __init__(self, ...):
        ...
        super(<Form-name>, self).__init__(*args, **kwargs)
        ...
        for i, (fname, field) in enumerate(self.fields.iteritems()):
            if fname in self.readonly_fields:
                field.widget.attrs['readonly'] = "readonly"
                field.required = False
                # set clean method to reset value back
                clean_method_name = "clean_%s" % fname
                assert clean_method_name not in dir(self)
                setattr(self, clean_method_name, partial(self._clean_for_readonly_field, fname=fname))

    def _clean_for_readonly_field(self, fname):
        """ will reset value to initial - nothing will be changed 
            needs to be added dynamically - partial, see init_fields
        """
        return self.initial[fname] # or getattr(self.instance, fieldname)
于 2013-11-27T15:40:44.977 回答
2

这是一个稍微复杂的版本,基于christophe31 的回答。它不依赖于“只读”属性。这使得它的问题,比如选择框仍然可以改变和数据选择器仍然弹出,消失了。

相反,它将表单字段小部件包装在只读小部件中,从而使表单仍然有效。原始小部件的内容显示在<span class="hidden"></span>标签内。如果小部件有一个render_readonly()方法,它会将其用作可见文本,否则它会解析原始小部件的 HTML 并尝试猜测最佳表示。

import django.forms.widgets as f
import xml.etree.ElementTree as etree
from django.utils.safestring import mark_safe

def make_readonly(form):
    """
    Makes all fields on the form readonly and prevents it from POST hacks.
    """

    def _get_cleaner(_form, field):
        def clean_field():
            return getattr(_form.instance, field, None)
        return clean_field

    for field_name in form.fields.keys():
        form.fields[field_name].widget = ReadOnlyWidget(
            initial_widget=form.fields[field_name].widget)
        setattr(form, "clean_" + field_name, 
                _get_cleaner(form, field_name))

    form.is_readonly = True

class ReadOnlyWidget(f.Select):
    """
    Renders the content of the initial widget in a hidden <span>. If the
    initial widget has a ``render_readonly()`` method it uses that as display
    text, otherwise it tries to guess by parsing the html of the initial widget.
    """

    def __init__(self, initial_widget, *args, **kwargs):
        self.initial_widget = initial_widget
        super(ReadOnlyWidget, self).__init__(*args, **kwargs)

    def render(self, *args, **kwargs):
        def guess_readonly_text(original_content):
            root = etree.fromstring("<span>%s</span>" % original_content)

            for element in root:
                if element.tag == 'input':
                    return element.get('value')

                if element.tag == 'select':
                    for option in element:
                        if option.get('selected'):
                            return option.text

                if element.tag == 'textarea':
                    return element.text

            return "N/A"

        original_content = self.initial_widget.render(*args, **kwargs)
        try:
            readonly_text = self.initial_widget.render_readonly(*args, **kwargs)
        except AttributeError:
            readonly_text = guess_readonly_text(original_content)

        return mark_safe("""<span class="hidden">%s</span>%s""" % (
            original_content, readonly_text))

# Usage example 1.
self.fields['my_field'].widget = ReadOnlyWidget(self.fields['my_field'].widget)

# Usage example 2.
form = MyForm()
make_readonly(form)
于 2012-09-04T10:50:36.010 回答
2

你可以这样做:

  1. 检查请求是更新还是保存新对象。
  2. 如果请求是更新,则禁用字段sku
  3. 如果请求是添加一个新对象,那么您必须在不禁用该字段的情况下呈现表单sku

这是一个如何做到这一点的例子。

class Item(models.Model):
    sku = models.CharField(max_length=50)
    description = models.CharField(max_length=200)
    added_by = models.ForeignKey(User)


class ItemForm(ModelForm):
    def disable_sku_field(self):
        elf.fields['sku'].widget.attrs['readonly'] = True

    class Meta:
        model = Item
        exclude = ('added_by')

def new_item_view(request):
    if request.method == 'POST':
        form = ItemForm(request.POST)
        # Just create an object or instance of the form.
        # Validate and save
    else:
            form = ItemForm()
    # Render the view

def update_item_view(request):
    if request.method == 'POST':
        form = ItemForm(request.POST)
        # Just create an object or instance of the form.
        # Validate and save
    else:
        form = ItemForm()
        form.disable_sku_field() # call the method that will disable field.

    # Render the view with the form that will have the `sku` field disabled on it.

于 2021-12-20T05:27:29.563 回答
1

这是最简单的方法吗?

就在这样的视图代码中:

def resume_edit(request, r_id):
    .....    
    r = Resume.get.object(pk=r_id)
    resume = ResumeModelForm(instance=r)
    .....
    resume.fields['email'].widget.attrs['readonly'] = True 
    .....
    return render(request, 'resumes/resume.html', context)

它工作正常!

于 2014-02-02T15:44:57.893 回答
1

如果您正在使用Django ver < 1.91.9已添加Field.disabled属性),您可以尝试将以下装饰器添加到您的表单__init__方法中:

def bound_data_readonly(_, initial):
    return initial


def to_python_readonly(field):
    native_to_python = field.to_python

    def to_python_filed(_):
        return native_to_python(field.initial)

    return to_python_filed


def disable_read_only_fields(init_method):

    def init_wrapper(*args, **kwargs):
        self = args[0]
        init_method(*args, **kwargs)
        for field in self.fields.values():
            if field.widget.attrs.get('readonly', None):
                field.widget.attrs['disabled'] = True
                setattr(field, 'bound_data', bound_data_readonly)
                setattr(field, 'to_python', to_python_readonly(field))

    return init_wrapper


class YourForm(forms.ModelForm):

    @disable_read_only_fields
    def __init__(self, *args, **kwargs):
        ...

主要思想是,如果字段是,则readonly不需要任何其他值,除了initial.

PS:别忘了设置yuor_form_field.widget.attrs['readonly'] = True

于 2018-09-03T11:50:30.520 回答
1

今天,我在类似的用例中遇到了完全相同的问题。但是,我不得不处理基于类的视图。基于类的视图允许继承属性和方法,从而更容易以简洁的方式重用代码。

我将通过讨论为用户创建个人资料页面所需的代码来回答您的问题。在此页面上,他们可以更新他们的个人信息。但是,我想在不允许用户更改信息的情况下显示一个电子邮件字段。

是的,我本可以省略电子邮件字段,但我的强迫症不允许这样做。

在下面的示例中,我将表单类与 disabled = True 方法结合使用。此代码在 Django==2.2.7 上测试。


# form class in forms.py

# Alter import User if you have created your own User class with Django default as abstract class.
from .models import User 
# from django.contrib.auth.models import User

# Same goes for these forms.
from django.contrib.auth.forms import UserCreationForm, UserChangeForm


class ProfileChangeForm(UserChangeForm):

    class Meta(UserCreationForm)
        model = User
        fields = ['first_name', 'last_name', 'email',]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['email'].disabled = True

可以看到,指定了所需的用户字段。这些是必须在个人资料页面上显示的字段。如果需要添加其他字段,则必须在 User 类中指定它们,并将属性名称添加到此表单的 Meta 类的字段列表中。

在获得所需的元数据后,调用 __init__ 方法来初始化表单。但是,在此方法中,电子邮件字段参数“已禁用”设置为 True。这样做会改变前端字段的行为,从而导致只读字段即使更改 HTML 代码也无法编辑。参考字段.disabled

为了完成,在下面的示例中可以看到使用表单所需的基于类的视图。


# view class in views.py

from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView, UpdateView
from django.utils.translation import gettext_lazy as _


class ProfileView(LoginRequiredMixin, TemplateView):
    template_name = 'app_name/profile.html'
    model = User


   def get_context_data(self, **kwargs):
      context = super().get_context_data(**kwargs)
      context.update({'user': self.request.user, })
      return context


class UserUpdateView(LoginRequiredMixin, SuccesMessageMixin, UpdateView):
    template_name = 'app_name/update_profile.html'
    model = User
    form_class = ProfileChangeForm
    success_message = _("Successfully updated your personal information")


    def get_success_url(self):
        # Please note, one has to specify a get_absolute_url() in the User class
        # In my case I return:  reverse("app_name:profile")
        return self.request.user.get_absolute_url()


    def get_object(self, **kwargs):
        return self.request.user


    def form_valid(self, form):
        messages.add_message(self.request, messages.INFO, _("Successfully updated your profile"))
        return super().form_valid(form)


ProfileView 类只显示一个 HTML 页面,其中包含有关用户的一些信息。此外,它还包含一个按钮,如果按下该按钮,就会进入由 UserUpdateView 配置的 HTML 页面,即“app_name/update_profile.html”。可以看到,UserUpdateView 拥有两个额外的属性,即“form_class”和“success_message”。

视图知道页面上的每个字段都必须填充来自用户模型的数据。但是,通过引入“form_class”属性,视图不会获得用户字段的默认布局。相反,它被重定向以通过表单类检索字段。这在灵活性方面具有巨大的优势。

通过使用表单类,可以为不同的用户显示具有不同限制的不同字段。如果在模型本身内设置限制,每个用户都会得到相同的待遇。

模板本身并不那么壮观,但可以在下面看到。


# HTML template in 'templates/app_name/update_profile.html' 

{% extends "base.html" %}
{% load static %}
{% load crispy_form_tags %}


{% block content %}


<h1>
    Update your personal information
<h1/>
<div>
    <form class="form-horizontal" method="post" action="{% url 'app_name:update' %}">
        {% csrf_token %} 
        {{ form|crispy }}
        <div class="btn-group">
            <button type="submit" class="btn btn-primary">
                Update
            </button>
        </div>
</div>


{% endblock %}

可以看出,表单标签包含一个包含视图 URL 路由的操作标签。按下更新按钮后,UserUpdateView 被激活,它会验证是否满足所有条件。如果是,则触发 form_valid 方法并添加成功消息。成功更新数据后,用户将返回到 get_success_url 方法中的指定 URL。

下面可以找到允许视图 URL 路由的代码。

# URL routing for views in urls.py

from django.urls import path
from . import views

app_name = 'app_name'

urlpatterns = [
    path('profile/', view=views.ProfileView.as_view(), name='profile'),
    path('update/', view=views.UserUpdateView.as_view(), name='update'),
    ]

你有它。使用表单的基于类的视图的完整实现,因此可以将电子邮件字段更改为只读和禁用。

对于非常详细的示例,我深表歉意。可能有更有效的方法来设计基于类的视图,但这应该可行。当然,我可能对某些事情说错了。我也在学习。如果有人有任何意见或改进,请告诉我!

于 2021-11-09T17:10:53.050 回答
0

如果您使用的是 Django admin,这里是最简单的解决方案。

class ReadonlyFieldsMixin(object):
    def get_readonly_fields(self, request, obj=None):
        if obj:
            return super(ReadonlyFieldsMixin, self).get_readonly_fields(request, obj)
        else:
            return tuple()

class MyAdmin(ReadonlyFieldsMixin, ModelAdmin):
    readonly_fields = ('sku',)
于 2015-03-24T06:37:40.760 回答
0

我认为你最好的选择就是在你的模板中包含 readonly 属性,<span>或者<p>如果它是只读的,而不是将它包含在表单中。

表格用于收集数据,而不是显示它。话虽如此,在readonly小部件中显示和清理 POST 数据的选项是很好的解决方案。

于 2015-04-30T18:15:20.690 回答