Django formunda, bir alanı düzenlenememesi için nasıl salt okunur (veya devre dışı) yapabilirim?


431

Django formunda, bir alanı salt okunur (veya devre dışı bırakılmış) hale nasıl getirebilirim?

Form yeni bir giriş oluşturmak için kullanılırken tüm alanların etkinleştirilmesi gerekir - ancak kayıt güncelleme modundayken bazı alanların salt okunur olması gerekir.

Örneğin, yeni bir Itemmodel oluştururken , tüm alanların düzenlenebilir olması gerekir, ancak kaydı güncellerken skualanı görünür hale getirmek, ancak düzenlenememek için devre dışı bırakmanın bir yolu var mı?

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

Sınıf ItemFormyeniden kullanılabilir mi? ItemFormVeya Itemmodel sınıfında ne gibi değişiklikler yapılması gerekir ? ItemUpdateFormÖğeyi güncellemek için başka bir sınıf, " " yazmam gerekir mi?

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

Ayrıca bkz. SO sorusu: Django'daki salt okunur form alanları neden kötü bir fikir? @ stackoverflow.com/questions/2902024 , Kabul edilen cevap (Daniel Naab tarafından) kötü niyetli POST saldırılarıyla ilgilenir.
X10

Yanıtlar:


422

İçinde sivri dışarı olarak bu cevap , Django 1.9 ekledi Field.disabled niteliğini:

Devre dışı bırakılan boole bağımsız değişkeni, True olarak ayarlandığında, devre dışı bırakılmış HTML özniteliğini kullanan bir form alanını devre dışı bırakır, böylece kullanıcılar tarafından düzenlenemez. Bir kullanıcı alanın sunucuya gönderilen değerini değiştirse bile, formun ilk verilerindeki değer lehine yok sayılır.

Django 1.8 ve önceki sürümlerinde, pencere aracındaki girişi devre dışı bırakmak ve kötü amaçlı POST saldırılarını önlemek readonlyiçin, form alanında özniteliği ayarlamanın yanı sıra girdiyi fırçalamanız gerekir :

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

Veya, düzenlediğinizi if instance and instance.pkbelirten başka bir koşulla değiştirin . Özniteliği disabled, yerine giriş alanında da ayarlayabilirsiniz readonly.

clean_skuFonksiyon sağlayacaktır readonlydeğeri tarafından geçersiz kılınmış olmayacaktır POST.

Aksi takdirde, bağlı giriş verilerini reddederken değer oluşturacak yerleşik bir Django form alanı yoktur. İstediğiniz buysa, bunun yerine ModelFormdüzenlenemeyen alanları dışlayan ayrı bir sayfa oluşturmanız ve bunları şablonunuzun içine yazdırmanız gerekir.


3
Daniel, Yanıt gönderdiğin için teşekkürler. Bu kodun nasıl kullanılacağı açık değil mi? Bu kod yeni güncelleme modu için de aynı şekilde çalışmaz mı? Cevabınızı yeni ve güncelleme formları için nasıl kullanacağınıza ilişkin örnekler vermek için düzenleyebilir misiniz? Teşekkürler.
X10

8
Daniel örneğinin anahtarı .id alanını test etmektir. Yeni oluşturulan nesnelerde id == Yok olur. Bu arada, en eski açık Django biletlerinden biri bu konu hakkında. Bkz. Code.djangoproject.com/ticket/342 .
Peter Rowell

2
@moadeep clean_descriptionform sınıfına bir yöntem ekler .
Daniel Naab

3
linux (ubuntu 15) / chrome v45 üzerinde, işaretçiyi salt okunur bir "devre dışı bırakılmış el" olarak değiştirir, ancak alan tıklanabilir. devre dışı ile beklendiği gibi çalışıyor
simone cittadini

7
Bu cevabın güncellenmesi gerekiyor. disabledDjango 1.9'a yeni bir alan argümanı eklenir. Olarak Field.disabledayarlanırsa True, bunun için POST değeri Fieldyok sayılır. Yani 1.9 kullanıyorsanız, geçersiz kılmanıza gerek yok clean, sadece ayarlayın disabled = True. Bu cevabı kontrol edin .
narendra-choudhary

174

Django 1.9, Field.disabled özelliğini ekledi: https://docs.djangoproject.com/en/stable/ref/forms/fields/#disabled

Devre dışı bırakılan boole bağımsız değişkeni, True olarak ayarlandığında, devre dışı bırakılmış HTML özniteliğini kullanan bir form alanını devre dışı bırakır, böylece kullanıcılar tarafından düzenlenemez. Bir kullanıcı alanın sunucuya gönderilen değerini değiştirse bile, formun ilk verilerindeki değer lehine yok sayılır.


1.8 LTS için bir şey yok mu?
dnit13

9
bunu bir UpdateView'da nasıl kullanabileceğimize dair bir fikrin var mı? Modelden alanları oluştururken ...
bcsanches

6
Doğru cevap. Çözüm sınıfım MyChangeForm (forms.ModelForm): def __init __ (self, * args, ** kwargs): super (MyChangeForm, self) .__ init __ (* args, ** kwargs) self.fields ['my_field']. Devre dışı = Doğru
Vijay Katam

8
Bu sorunlu bir yanıttır - disabled=Truemodelin doğrulama hatalarıyla kullanıcıya geri tükenmesine neden olur.
Ben

1
Bir örnek
ekleyebilirseniz

95

readonlyBir widget üzerinde ayar yapmak, tarayıcıdaki girdiyi salt okunur yapar. Geri clean_skudönen bir eklemek instance.sku, alan değerinin form düzeyinde değişmemesini sağlar.

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

Bu şekilde, modelin (değiştirilmemiş kaydetme) özelliğini kullanabilir ve alan için gerekli hataların alınmasını önleyebilirsiniz.


15
+1 Bu, daha karmaşık kaydetme () geçersiz kılmalarını önlemenin harika bir yoludur. Ancak, dönüşten önce örnek kontrolü yapmak istersiniz (satırsonu içermeyen yorum modunda): "eğer self.instance: return self.instance.sku; else: return self.fields ['sku']"
Daniel Naab25

2
Son satır için, return self.cleaned_data['sku']iyi veya daha iyi olurdu ? Docs kullanarak önermek görünüyor cleaned_data: "Bu yöntemin dönüş değeri mevcut değerinin yerini cleaned_datao alanın gelen değeri olmalıdır, böylece cleaned_data(bu yöntem o değişmedi bile) veya yeni temizlenmiş bir değer."
pianoJames

67

awalker'in cevabı bana çok yardımcı oldu!

Django 1.3 ile çalışmak için örneğini get_readonly_fields kullanarak değiştirdim .

Genellikle böyle bir şey beyan etmelisiniz app/admin.py:

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

Bu şekilde adapte oldum:

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

Ve iyi çalışıyor. Şimdi bir Öğe eklerseniz, urlalan okuma-yazma olur, ancak değiştiğinde salt okunur hale gelir.


56

Bunun bir ForeignKeyalanda çalışmasını sağlamak için birkaç değişiklik yapılması gerekir. İlk olarak, SELECT HTMLetiket salt okunur özniteliğine sahip değildir. Kullanmamız gerekdisabled="disabled"Bunun yerine . Ancak, tarayıcı o alan için herhangi bir form verisi göndermez. Bu nedenle, alanın doğru şekilde doğrulanması için bu alanı zorunlu olmayacak şekilde ayarlamamız gerekir. Daha sonra, değeri boş olarak ayarlanmaması için eski değerine sıfırlamamız gerekir.

Yani yabancı anahtarlar için şöyle bir şey yapmanız gerekecek:

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)

Bu şekilde tarayıcı kullanıcının alanı değiştirmesine izin vermez ve her zaman POSTboş bırakılır. Daha sonra cleanalanın değerini örnekte orijinal olarak ayarlamak için yöntemi geçersiz kılıyoruz.


Form olarak kullanmaya çalıştım TabularInline, ancak örnekler attrsarasında widgetve yeni eklenenler de dahil olmak üzere ilk satır dışındaki tüm satırlar arasında salt okunur hale getirildiğinden başarısız oldum .
dhill

Harika (güncelleme) bir çözüm! Ne yazık ki bu ve geri kalanı, tüm "devre dışı" değerler boşaldıkça form hataları olduğunda sorun yaşıyor.
Michael Thompson

28

Django 1.2+ için, alanı aşağıdaki gibi geçersiz kılabilirsiniz:

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

6
Bu, alanın ekleme zamanında düzenlenmesine izin vermez, bu da orijinal sorunun ne olduğudur.
Matt S.

Aradığım cevap bu. Field disabledistediğim şeyi yapmaz çünkü alanı devre dışı bırakır, aynı zamanda etiketi kaldırır / görünmez yapar.
sivabudh

18

İlk olmayan düzenlemede alanları devre dışı bırakacak ve güvenli hale getirecek bir read_only yinelenebilir alan eklemek için devralınabilecek bir MixIn sınıfı yaptım:

(Daniel ve Muhuk'un cevaplarına dayanarak)

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

Ben sadece bir salt okunur alan için mümkün olan en basit widget yarattım - Gerçekten formlar neden zaten bu yok görmüyorum:

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

Şeklinde:

my_read_only = CharField(widget=ReadOnlyWidget())

Çok basit - ve sadece çıktı alır. Bir sürü salt okunur değere sahip bir form kümesinde kullanışlı. Tabii ki - biraz daha zeki olabilir ve attrs ile bir div verebilirsiniz, böylece sınıflara ekleyebilirsiniz.


2
Seksi görünüyor, ama yabancı anahtar nasıl ele alınır?
andilabs

Emin olun unicode(value)yerine belki karşılığında. Unicode şimşek mantıklı olduğunu varsayarsak, bunu elde edersiniz.
Danny Staple

Yabancı anahtarlar için bir "model" özelliği eklemeniz ve "get (value)" kullanmanız gerekir. Benim gist
shadi

10

Benzer bir sorunla karşılaştım. ModelAdmin sınıfımda bir "get_readonly_fields" yöntemi tanımlayarak çözebildim.

Bunun gibi bir şey:

# In the admin.py file

class ItemAdmin(admin.ModelAdmin):

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

Güzel bir şey, objyeni bir Öğe eklediğinizde Hiçbiri veya varolan bir Öğe değiştirilirken düzenlenen nesne olacaktır.

get_readonly_display burada belgelenmiştir: http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#modeladmin-methods


6

Basit bir seçenek, sadece form.instance.fieldNameşablon yerine yazmaktır form.fieldName.


Peki verbos_nameya labelalan ne olacak ? Django şablonunda `etiketini nasıl gösterebilirim? @alzclarke
Balina 52Hz

6

Django 1.11 ile nasıl yaparım:

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

bu sadece önlenmeyi engelleyecektir. herhangi biri atlayabilir. hassas veriler üzerinde çalışıyorsanız bu bir güvenlik sorunu yaratacaktır
Sarath Ak

Güvenli; Django> = 1.10 olduğundan
timdiels

5

Humphrey'nin gönderisine yararlı bir ek olarak , django-reversion ile ilgili bazı sorunlar yaşadım, çünkü hala devre dışı bırakılan alanları 'değişti' olarak kaydetti. Aşağıdaki kod sorunu giderir.

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

Henüz yorumlayamadığım için ( muhuk'un çözümü ), ayrı bir cevap olarak cevap vereceğim. Bu benim için çalışan tam bir kod örneğidir:

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

5

Yine, bir çözüm daha sunacağım :) Humphrey kodunu kullanıyordum , bu yüzden buna dayanıyor.

Ancak, alanın a ModelChoiceField. Her şey ilk istek üzerine çalışır. Ancak, form kümesi yeni bir öğe eklemeye çalıştı ve doğrulama başarısız olursa, SELECTEDseçeneğin varsayılana sıfırlandığı "mevcut" formlarda bir sorun oluştu ---------.

Her neyse, bunu nasıl düzeltebileceğimi bilemedim. Bunun yerine, (ve bence bu aslında formda daha temiz), alanları yaptım HiddenInputField(). Bu, şablonda biraz daha fazla iş yapmanız gerektiği anlamına gelir.

Benim için düzeltme, Formu basitleştirmekti:

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

Ve sonra şablonda, form kümesinin manuel döngüsünü yapmanız gerekir .

Yani, bu durumda şablonda böyle bir şey yaparsınız:

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

Bu benim için biraz daha iyi ve daha az form manipülasyonu ile çalıştı.


4

Aynı soruna giriyordum, bu yüzden kullanım durumlarımda işe yarayan bir Mixin oluşturdum.

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

Kullanım, sadece hangilerinin okunması gerektiğini tanımlayın:

class MyFormWithReadOnlyFields(ReadOnlyFieldsMixin, MyForm):
    readonly_fields = ('field1', 'field2', 'fieldx')

Sanırım burada önerdiğim kendi karışımımdan biraz daha okunabilir. Bu temizlemeler doğrulama hatalarını
christophe31

Bir hata alıyorum:'collections.OrderedDict' object has no attribute 'iteritems'
geoidesic

4

Birden fazla salt okunur alana ihtiyacınız varsa. aşağıda verilen yöntemlerden herhangi birini kullanabilirsiniz

Yöntem 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

yöntem 2

kalıtım yöntemi

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

Genelleştirilmiş bir örnekle iki (benzer) yaklaşım daha:

1) ilk yaklaşım - save () yöntemindeki alanı kaldırmak, örneğin (test edilmemiştir;)):

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) ikinci yaklaşım - temiz yöntemde alanı başlangıç ​​değerine sıfırlayın:

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

İkinci yaklaşıma dayanarak şöyle genelleştirdim:

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

Yönetici sürümü için, birden fazla alanınız varsa bunun daha kompakt bir yol olduğunu düşünüyorum:

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'in cevabına dayanarak, ModelMultipleChoiceFieldalanları da ele alan daha iyi ve çok basit bir çözüm buldum .

Alanın kaldırılması, form.cleaned_dataalanların kaydedilmesini önler:

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

Kullanımı:

class MyFormWithReadOnlyFields(ReadOnlyFieldsMixin, MyForm):
    readonly_fields = ('field1', 'field2', 'fieldx')

2

İşte christophe31'in cevabına dayanan biraz daha ilgili bir sürüm . "Salt okunur" özelliğine dayanmaz. Bu, seçim kutularının hala değiştirilebilir olması ve veri toplayıcıların hala ortaya çıkması gibi sorunlarını ortadan kaldırıyor.

Bunun yerine, form alanları widget'ını salt okunur bir widget'a sararak formu hala doğrular. Orijinal pencere öğesinin içeriği <span class="hidden"></span>etiketlerin içinde görüntülenir . Widget, render_readonly()görünür metin olarak bir yöntem kullanıyorsa, aksi takdirde orijinal widget'ın HTML'sini ayrıştırır ve en iyi temsili tahmin etmeye çalışır.

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

Bu en basit yol mu?

Tam bir görünüm kodu şöyle bir şey:

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)

İyi çalışıyor!


1

Django 1.9+
için Alanı devre dışı bırakmak için Alanlar devre dışı bağımsız değişkenini kullanabilirsiniz. örn. aşağıdaki form pasajından kod pasajında, worker_code alanını devre dışı bıraktım

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

Referans https://docs.djangoproject.com/en/2.0/ref/forms/fields/#disabled


1

Form yönteminize çalışıyorsanız Django ver < 1.9( 1.9özelliği ekledi Field.disabled) form __init__yönteminize aşağıdaki dekoratörü eklemeyi deneyebilirsiniz :

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

Ana fikir, eğer alan ise readonlybaşka bir değere ihtiyacınız olmamasıdır initial.

Not: Ayarlamayı unutmayın yuor_form_field.widget.attrs['readonly'] = True


0

Django admin kullanıyorsanız, işte en basit çözüm.

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

En iyi seçeneğinizin şablonunuzda salt okunur özniteliği bir <span>veya<p> ziyade salt okunur ise şeklinde dahil.

Formlar veri görüntülemek içindir, görüntülemek için değildir. Bununla birlikte, bir readonlywidget'ta görüntüleme ve POST verilerini fırçalama seçenekleri iyi çözümlerdir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.