Django 양식에서 편집 할 수 없도록 필드를 읽기 전용 (또는 비활성화)으로 만들려면 어떻게합니까?


430

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을 재사용 할 수 있습니까 ? ItemForm또는 Item모델 클래스 에서 어떤 변경이 필요 합니까? ItemUpdateForm항목을 업데이트하기 위해 다른 클래스 " " 를 작성해야 합니까?

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

SO 질문 : Django의 읽기 전용 양식 필드가 왜 나쁜 생각입니까? @ stackoverflow.com/questions/2902024 , 승인 된 답변 (Daniel Naab)은 악의적 인 POST 해킹을 처리합니다.
X10

답변:


421

이 답변 에서 지적했듯이 Django 1.9는 Field.disabled 속성을 추가했습니다 .

비활성화 된 부울 인수는 True로 설정되면 비활성화 된 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값이에 의해 재정의되지 않도록합니다 POST.

그렇지 않으면 바운드 입력 데이터를 거부하면서 값을 렌더링하는 내장 장고 양식 필드가 없습니다. 원하는 ModelForm경우 편집 할 수없는 필드를 제외한 별도의 필드 를 만들어 템플릿 내부에 인쇄하면됩니다.


3
Daniel, 답변을 게시 해 주셔서 감사합니다. 이 코드를 사용하는 방법이 확실하지 않습니까? 이 코드는 새로운 업데이트 모드에서도 동일하게 작동하지 않습니까? 답변을 편집하여 새 양식 및 업데이트 양식에 사용하는 방법에 대한 예를 제공 할 수 있습니까? 감사.
X10

8
Daniel의 예에서 핵심은 .id 필드를 테스트하는 것입니다. 새로 만든 개체는 id == None을 갖습니다. 그건 그렇고, 가장 오래된 공개 장고 티켓 중 하나는이 문제에 관한 것입니다. code.djangoproject.com/ticket/342를 참조하십시오 .
피터 로웰

2
@moadeep clean_description양식 클래스에 메소드를 추가하십시오 .
Daniel Naab

3
linux (ubuntu 15) / chrome v45에서 읽기 전용은 포인터를 "disabled hand"로 변경하지만 필드를 클릭 할 수 있습니다. 장애인과 함께 그것은 예상대로 작동
simone cittadini

7
이 답변은 업데이트해야합니다. disabledDjango 1.9 에는 새로운 필드 인수 가 추가되었습니다. 경우 Field.disabled로 설정되어 True, 그것에 대해 다음 POST 값은 Field무시됩니다. 당신은 1.9을 사용하는 경우 그래서, 재정의 할 필요가 없습니다 clean단지 설정은 disabled = True. 답변을 확인하십시오 .
narendra-choudhary 2016 년

174

Django 1.9는 Field.disabled 속성을 추가했습니다 : https://docs.djangoproject.com/en/stable/ref/forms/fields/#disabled

비활성화 된 부울 인수는 True로 설정되면 비활성화 된 HTML 속성을 사용하여 양식 필드를 비활성화하여 사용자가 편집 할 수 없도록합니다. 사용자가 서버에 제출 된 필드 값을 변경하더라도 양식의 초기 데이터 값을 위해 무시됩니다.


1.8 LTS에 대한 아무것도?
dnit13

9
UpdateView에서 어떻게 사용할 수 있습니까? 모델에서 필드를 생성 할 때 ...
bcsanches

6
정답. 내 솔루션 클래스 MyChangeForm (forms.ModelForm) : def __init __ (self, * args, ** kwargs) : super (MyChangeForm, self) .__ init __ (* args, ** kwargs) self.fields [ 'my_field']. disabled = 진실
Vijay Katam

8
이는 문제가되는 답변입니다. 설정 disabled=True하면 유효성 검사 오류가 발생하여 모델이 사용자에게 다시 표시됩니다.
Ben

1
예를 포함시킬 수 있다면 정말 좋을 것입니다.
geoidesic

95

readonly위젯을 설정 하면 브라우저의 입력 만 읽기 전용이됩니다. 추가 clean_sku하는 반환하는 instance.sku필드 값이 폼 수준에서 변경되지 않습니다 보장합니다.

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

이렇게하면 모델 (수정되지 않은 저장)을 사용하고 필드 필수 오류가 발생하지 않도록 할 수 있습니다.


15
+1 이것은 더 복잡한 save () 재정의를 피하는 좋은 방법입니다. 그러나 리턴하기 전에 (줄 바꿈없는 주석 모드에서) 인스턴스 확인을 수행하려고합니다. "if self.instance : return self.instance.sku; 그렇지 않으면 : return self.fields [ 'sku']"
Daniel Naab

2
마지막 줄은 return self.cleaned_data['sku']좋을까요? 문서는 사용하는 것이 좋습니다 것 cleaned_data"이 방법의 반환 값의 기존 값을 대체 cleaned_data는 필드의에서 값이어야하므로 cleaned_data(이 방법은 변경하지 않은 경우에도) 새 청소 값입니다."
pianoJames

67

아 워커의 대답 이 많은 도움이되었습니다!

get_readonly_fields 사용하여 장고 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필드가 읽기 / 쓰기가되지만 변경하면 읽기 전용이됩니다.


55

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필드의 값을 인스턴스의 원래 값으로 설정하기 위해 메서드를 재정의합니다 .


에서 형식으로 사용하려고했지만 새로 추가 된 렌더링 된 읽기 전용을 포함하여 첫 번째 행을 제외하고 인스턴스와 인스턴스 가 모두 공유되어 TabularInline실패했습니다 . attrswidget
dhill

훌륭한 (업데이트) 솔루션! 불행히도 이것과 나머지는 모든 "비활성화"값이 비워 져서 폼 오류가있을 때 문제가 발생합니다.
마이클 톰슨

28

Django 1.2 이상에서는 다음과 같이 필드를 무시할 수 있습니다.

sku = forms.CharField(widget = forms.TextInput(attrs={'readonly':'readonly'}))

6
이렇게하면 추가 시간에 필드를 편집 할 수 없으며 이는 원래 질문의 내용입니다.
Matt S.

이것이 내가 찾고있는 대답입니다. Field disabled필드를 비활성화하기 때문에 내가 원하는 것을하지 않지만 레이블을 제거하고 보이지 않게합니다.
sivabudh 2016 년

18

상속되지 않은 MixIn 클래스를 작성하여 첫 번째 편집에서 필드를 비활성화하고 보호하는 read_only iterable 필드를 추가 할 수 있습니다.

(다니엘과 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')

11

방금 읽기 전용 필드에 가장 간단한 위젯을 만들었습니다. 양식에 아직이없는 이유는 모르겠습니다.

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를 제공하여 클래스를 추가 할 수 있습니다.


2
섹시 해 보이지만 외래 키를 처리하는 방법은 무엇입니까?
andilabs

unicode(value)아마 그 대가로 그것을 확인 하십시오. 유니 코드 던더가 합리적이라고 가정하면 얻을 수 있습니다.
Danny Staple

외래 키의 경우 "model"속성을 추가하고 "get (value)"를 사용해야합니다. 내 요점
shadi

10

비슷한 문제가 발생했습니다. ModelAdmin 클래스에서 "get_readonly_fields"메소드를 정의하여 해결할 수있는 것 같습니다.

이 같은:

# 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는 여기에 문서화되어 있습니다 : http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#modeladmin-methods


6

간단한 옵션 중 하나는 form.instance.fieldName대신 템플릿을 입력 하는 것입니다 form.fieldName.


그리고 방법에 대한 verbos_name또는 label필드의? django 템플릿에서`label을 어떻게 표시합니까? @alzclarke
고래 52Hz

6

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

이것은 정면에서만 차단됩니다. 어느 쪽이든 우회 할 수 있습니다. 민감한 데이터를 사용하는 경우 보안 문제가 발생합니다
Sarath Ak

안전합니다. 또한 Django> = 1.10 이후 백엔드에서 차단됩니다. docs.djangoproject.com/en/1.10/ref/forms/fields/…
timdiels

5

Humphrey의 post에 유용한 추가 기능으로 , 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)

5

아직 언급 할 수 없으므로 ( muhuk 's solution ) 별도의 답변으로 답변 드리겠습니다. 이것은 나를 위해 일한 완전한 코드 예제입니다.

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

5

다시 한번, 나는 하나의 해결책을 더 제공 할 것입니다 :) Humphrey의 코드를 사용하고있었습니다. 하고 있었기 때문에 이것에 기초합니다.

그러나 필드가에 문제가 발생했습니다 ModelChoiceField. 첫 번째 요청에서 모든 것이 작동합니다. 그러나 양식 세트가 새 항목을 추가하려고 시도하고 유효성 검증에 실패한 경우 SELECTED옵션이 기본값으로 재설정 되는 "기존"양식에 문제가 발생했습니다 ---------.

어쨌든, 나는 그것을 고치는 방법을 알 수 없었다. 대신에 (그리고 나는 이것이 실제로 형태가 더 깨끗하다고 ​​생각합니다 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()

그런 다음 템플릿에서 양식 세트를 수동으로 반복 해야합니다 .

따라서이 경우 템플릿에서 다음과 같은 작업을 수행합니다.

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

이것은 나를 위해 조금 더 잘 작동하고 양식 조작이 적습니다.


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

나는 그것이 내가 제안한 내 믹스 인보 다 조금 더 읽기 쉽다고 생각합니다. 이러한 청소는 유효성 검사 오류를 발생시키지 않기 때문에 더욱 효율적일 것입니다.
christophe31

오류가 발생합니다 :'collections.OrderedDict' object has no attribute 'iteritems'
geoidesic

4

여러 개의 읽기 전용 필드가 필요한 경우 아래에 주어진 방법 중 하나를 사용할 수 있습니다

방법 1

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

방법 2

상속 방법

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',)

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) 두 번째 접근법-깨끗한 방법으로 필드를 초기 값으로 재설정하십시오.

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)

3

관리자 버전의 경우 필드가 두 개 이상인 경우 더 간단한 방법이라고 생각합니다.

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

3

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

2

다음은 christophe31의 답변 에 따라 약간 더 관련된 버전 입니다. "readonly"속성에 의존하지 않습니다. 이것은 선택 상자가 여전히 변경 가능하고 데이터 선택기가 여전히 팝업되는 것처럼 문제를 해결합니다.

대신, 양식 필드 위젯을 읽기 전용 위젯으로 랩핑하여 양식을 여전히 유효성 검증합니다. 원래 위젯의 컨텐츠는 <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)

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)

잘 작동합니다!


1

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/2.0/ref/forms/fields/#disabled


1

속성 을 추가 한 상태 Django ver < 1.9에서 작업중인 경우 양식 메소드에 다음 데코레이터를 추가 할 수 있습니다 .1.9Field.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):
        ...

주요 아이디어는 field가 if을 readonly제외한 다른 값이 필요하지 않다는 것 initial입니다.

추신 : 잊지 말아주세요 yuor_form_field.widget.attrs['readonly'] = True


0

Django 관리자를 사용하는 경우 가장 간단한 해결책은 다음과 같습니다.

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',)

0

나는 당신의 최선의 선택은 단지 렌더링 템플릿에서 읽기 전용 속성을 포함하는 것입니다 생각 <span>이나 <p>보다는 읽기 전용 인 경우 양식에 포함.

양식은 데이터를 표시하기위한 것이 아니라 데이터를 수집하기위한 것입니다. 즉, readonly위젯 에 표시하고 POST 데이터를 제거 하는 옵션 은 훌륭한 솔루션입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.