In una forma Django, come posso rendere un campo di sola lettura (o disabilitato) in modo che non possa essere modificato?


431

In una forma Django, come posso rendere un campo di sola lettura (o disabilitato)?

Quando il modulo viene utilizzato per creare una nuova voce, è necessario abilitare tutti i campi, ma quando il record è in modalità di aggiornamento alcuni campi devono essere di sola lettura.

Ad esempio, quando si crea un nuovo Itemmodello, tutti i campi devono essere modificabili, ma durante l'aggiornamento del record esiste un modo per disabilitare il skucampo in modo che sia visibile, ma non può essere modificato?

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

La lezione può ItemFormessere riutilizzata? Quali modifiche sarebbero necessarie nella classe del modello ItemFormo Item? Dovrei scrivere un'altra classe, " ItemUpdateForm", per aggiornare l'elemento?

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

Vedi anche la domanda SO: Perché i campi modulo di sola lettura in Django sono una cattiva idea? @ stackoverflow.com/questions/2902024 , La risposta accettata (da Daniel Naab) si occupa degli hack POST dannosi.
X10,

Risposte:


422

Come sottolineato in questa risposta , Django 1.9 ha aggiunto l' attributo Field.disabled :

L'argomento booleano disabilitato, se impostato su True, disabilita un campo modulo utilizzando l'attributo HTML disabilitato in modo che non sia modificabile dagli utenti. Anche se un utente manomette il valore del campo inviato al server, verrà ignorato a favore del valore dai dati iniziali del modulo.

Con Django 1.8 e precedenti, per disabilitare l'ingresso sul widget e prevenire gli hack POST dannosi è necessario cancellare l'input oltre a impostare l' readonlyattributo nel campo del modulo:

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

In alternativa, sostituisci if instance and instance.pkcon un'altra condizione che indica che stai modificando. È inoltre possibile impostare l'attributo disabledsul campo di input, anziché readonly.

La clean_skufunzione assicurerà che il readonlyvalore non venga sovrascritto da a POST.

Altrimenti, non esiste un campo modulo Django incorporato che renderà un valore mentre rifiuta i dati di input associati. Se questo è ciò che desideri, dovresti invece crearne uno separato ModelFormche escluda i campi non modificabili e stamparli semplicemente all'interno del tuo modello.


3
Daniel, grazie per aver inviato una risposta. Non mi è chiaro come usare questo codice? questo codice non funzionerebbe allo stesso modo anche per la nuova modalità di aggiornamento? Puoi modificare la tua risposta per fornire esempi su come usarla per i moduli nuovi e di aggiornamento? Grazie.
X10,

8
La chiave dell'esempio di Daniel sta testando il campo .id. Gli oggetti appena creati avranno id == Nessuno. A proposito, uno dei più vecchi biglietti Django aperti riguarda questo problema. Vedi code.djangoproject.com/ticket/342 .
Peter Rowell,

2
@moadeep aggiunge un clean_descriptionmetodo alla classe form.
Daniel Naab,

3
su Linux (Ubuntu 15) / Chrome v45, cambia di sola lettura il puntatore in una "mano disabilitata" ma il campo è quindi cliccabile. con disabilitato funziona come previsto
simone cittadini

7
Questa risposta deve essere aggiornata. Un nuovo argomento sul campo disabledè stato aggiunto in Django 1.9. Se Field.disabledimpostato su True, il valore POST Fieldviene ignorato. Quindi, se si utilizza 1.9, non è necessario eseguire l'override clean, basta impostare disabled = True. Controlla questa risposta.
narendra-choudhary,

174

Django 1.9 ha aggiunto l'attributo Field.disabled: https://docs.djangoproject.com/en/stable/ref/forms/fields/#disabled

L'argomento booleano disabilitato, se impostato su True, disabilita un campo modulo utilizzando l'attributo HTML disabilitato in modo che non sia modificabile dagli utenti. Anche se un utente manomette il valore del campo inviato al server, verrà ignorato a favore del valore dai dati iniziali del modulo.


Niente per 1,8 LTS?
dnit13,

9
qualche idea di come possiamo usarlo su un UpdateView? Come genera i campi dal modello ...
bcsanches

6
Risposta corretta. La mia classe di soluzione MyChangeForm (forms.ModelForm): def __init __ (self, * args, ** kwargs): super (MyChangeForm, self) .__ init __ (* args, ** kwargs) self.fields ['my_field']. Disabled = Vero
Vijay Katam il

8
Questa è una risposta problematica: l'impostazione disabled=Truecauserà la restituzione del modello all'utente con errori di convalida.
Ben

1
Sarebbe fantastico se potessi includere un esempio
geoidesic il

95

L'impostazione readonlysu un widget rende l'input nel browser di sola lettura. L'aggiunta di un clean_skuche restituisce instance.skugarantisce che il valore del campo non cambierà a livello di modulo.

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

In questo modo è possibile utilizzare il modello (salvataggio non modificato) ed evitare di ottenere l'errore richiesto dal campo.


15
+1 Questo è un ottimo modo per evitare sostituzioni più complicate di save (). Tuttavia, ti consigliamo di effettuare un controllo dell'istanza prima del ritorno (in modalità di commento senza riga nuova): "if self.instance: return self.instance.sku; else: return self.fields ['sku']"
Daniel Naab,

2
Per l'ultima riga, sarebbe return self.cleaned_data['sku']buono o migliore? I documenti sembrano suggerire di utilizzare cleaned_data: "Il valore restituito da questo metodo sostituisce il valore esistente in cleaned_data, quindi deve essere il valore del campo da cleaned_data(anche se questo metodo non lo ha modificato) o un nuovo valore pulito".
pianoJames

67

la risposta di Awalker mi ha aiutato molto!

Ho cambiato il suo esempio per lavorare con Django 1.3, usando get_readonly_fields .

Di solito dovresti dichiarare qualcosa del genere in app/admin.py:

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

Mi sono adattato in questo modo:

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

E funziona benissimo. Ora se aggiungi un elemento, il urlcampo è di lettura-scrittura, ma al momento della modifica diventa di sola lettura.


56

Affinché funzioni in un ForeignKeycampo, è necessario apportare alcune modifiche. Innanzitutto, il SELECT HTMLtag non ha l'attributo readonly. Dobbiamo usare disabled="disabled"invece. Tuttavia, il browser non restituisce i dati del modulo per quel campo. Pertanto, è necessario impostare quel campo in modo che non sia obbligatorio in modo che il campo venga validato correttamente. Abbiamo quindi bisogno di ripristinare il valore su quello che era in precedenza, quindi non è impostato su vuoto.

Quindi per le chiavi esterne dovrai fare qualcosa del tipo:

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)

In questo modo il browser non consentirà all'utente di modificare il campo e sarà sempre POSTlasciato vuoto. Quindi sovrascriviamo il cleanmetodo per impostare il valore del campo in modo che fosse quello originariamente nell'istanza.


Ho provato a usarlo come modulo TabularInline, ma non ci attrssono riuscito perché sono stati condivisi tra widgetistanze e tutti tranne la prima riga, incluso il nuovo aggiunto, reso di sola lettura.
Dhill

Un'ottima soluzione (di aggiornamento)! Sfortunatamente questo e il resto hanno problemi quando ci sono errori di forma poiché tutti i valori "disabilitati" vengono svuotati.
Michael Thompson,

28

Per Django 1.2+, puoi scavalcare il campo in questo modo:

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

6
Ciò non consente neppure la modifica del campo in fase di aggiunta, che è la domanda originale.
Matt S.

Questa è la risposta che sto cercando. Field disablednon fa quello che voglio perché disabilita il campo, ma rimuove anche l'etichetta / rendendolo invisibile.
sivabudh

18

Ho creato una classe MixIn che potresti ereditare per poter aggiungere un campo iterable read_only che disabiliterà e proteggerà i campi nella modifica non prima:

(Basato sulle risposte di Daniel e 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

Ho appena creato il widget più semplice possibile per un campo di sola lettura - non vedo davvero perché i moduli non lo abbiano già:

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

Nella forma:

my_read_only = CharField(widget=ReadOnlyWidget())

Molto semplice - e mi dà solo output. Comodo in un formset con un sacco di valori di sola lettura. Certo, potresti anche essere un po 'più intelligente e fare un div con gli attr in modo da poter aggiungere lezioni ad esso.


2
Sembra sexy, ma come gestire la chiave esterna?
andilabs

Renderlo unicode(value)nel ritorno invece forse. Supponendo che il dunder Unicode sia ragionevole, lo otterresti.
Danny Staple,

Per le chiavi esterne, dovrai aggiungere un attributo "modello" e utilizzare "get (valore)". Check my gist
shadi

10

Ho riscontrato un problema simile. Sembra che sono stato in grado di risolverlo definendo un metodo "get_readonly_fields" nella mia classe ModelAdmin.

Qualcosa come questo:

# In the admin.py file

class ItemAdmin(admin.ModelAdmin):

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

La cosa bella è che objsarà Nessuno quando si aggiunge un nuovo Articolo, o sarà l'oggetto in fase di modifica quando si modifica un Articolo esistente.

get_readonly_display è documentato qui: http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#modeladmin-methods


6

Un'opzione semplice è semplicemente digitare form.instance.fieldNameil modello anziché form.fieldName.


E che dire del campo verbos_nameo label? Come posso mostrare l'etichetta `nel modello django? @alzclarke
Whale 52Hz

6

Come lo faccio con 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

questo bloccherà solo dal fronte. chiunque può bypassare. questo creerà un problema di sicurezza se lo fai su dati sensibili
Sarath Ak

É sicuro; si blocca anche nel back-end poiché Django> = 1.10 docs.djangoproject.com/en/1.10/ref/forms/fields/…
timdiels

5

Come utile aggiunta al post di Humphrey , ho avuto alcuni problemi con il django-reversion, perché registrava ancora i campi disabilitati come "modificati". Il codice seguente risolve il problema.

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

Dato che non posso ancora commentare ( la soluzione di muhuk ), risponderò come risposta separata. Questo è un esempio di codice completo, che ha funzionato per me:

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

5

Ancora una volta, sto per offrire un'altra soluzione :) Stavo usando il codice di Humphrey , quindi questo si basa su quello.

Tuttavia, ho riscontrato problemi con il campo essendo a ModelChoiceField. Tutto funzionerebbe alla prima richiesta. Tuttavia, se il formset ha tentato di aggiungere un nuovo elemento e non è riuscito a convalidare, qualcosa andava storto con i moduli "esistenti" in cui l' SELECTEDopzione veniva ripristinata al valore predefinito--------- .

Comunque, non sono riuscito a capire come risolverlo. Quindi invece (e penso che questo sia in realtà più pulito nella forma), ho creato i campiHiddenInputField() . Questo significa solo che devi fare un po 'più di lavoro nel modello.

Quindi la soluzione per me era semplificare il modulo:

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

E poi nel modello, dovrai eseguire un ciclo manuale del formset .

Quindi, in questo caso, faresti qualcosa del genere nel modello:

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

Questo ha funzionato un po 'meglio per me e con meno manipolazione della forma.


4

Stavo riscontrando lo stesso problema, quindi ho creato un Mixin che sembra funzionare per i miei casi d'uso.

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

Utilizzo, basta definire quali devono essere letti solo:

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

Suppongo che sia un po 'più leggibile del mio mixin che ho suggerito qui. Ancora probabilmente più efficiente, poiché quelle pulizie non generano errori di convalida ...
christophe31

'collections.OrderedDict' object has no attribute 'iteritems'
Viene visualizzato

4

se hai bisogno di più campi di sola lettura, puoi utilizzare uno dei metodi indicati di seguito

metodo 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

metodo 2

metodo di eredità

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

Altri due approcci (simili) con un esempio generalizzato:

1) primo approccio - rimozione del campo nel metodo save (), ad es. (Non testato;)):

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) secondo approccio: reimpostare il campo sul valore iniziale con metodo pulito:

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

Sulla base del secondo approccio l'ho generalizzato in questo modo:

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

Per la versione Admin, penso che questo sia un modo più compatto se hai più di un campo:

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

Sulla base della risposta di Yamikep , ho trovato una soluzione migliore e molto semplice che gestisce ancheModelMultipleChoiceField campi.

La rimozione di un campo form.cleaned_dataimpedisce di salvare i campi:

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

Uso:

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

2

Ecco una versione leggermente più complessa, basata sulla risposta di christophe31 . Non si basa sull'attributo "sola lettura". Questo fa sì che i suoi problemi, come le caselle di selezione ancora modificabili e i datapicker che spuntano ancora, scompaiano.

Al contrario, avvolge il widget dei campi modulo in un widget di sola lettura, rendendo così il modulo ancora valido. Il contenuto del widget originale viene visualizzato all'interno dei <span class="hidden"></span>tag. Se il widget ha un render_readonly()metodo, lo utilizza come testo visibile, altrimenti analizza l'HTML del widget originale e cerca di indovinare la rappresentazione migliore.

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

È questo il modo più semplice?

Proprio in una vista codice qualcosa del genere:

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)

Funziona benissimo!


1

Per django 1.9+
È possibile utilizzare l'argomento Fields disabled per disabilitare il campo. ad es. nel seguente frammento di codice dal file forms.py, ho disabilitato il campo employee_code

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

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


1

Se stai lavorando con Django ver < 1.9(l' attributo 1.9ha aggiunto Field.disabled) potresti provare ad aggiungere il seguente decoratore al tuo __init__metodo di modulo :

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

L'idea principale è che se il campo è readonlynon è necessario alcun altro valore tranne initial.

PS: non dimenticare di impostare yuor_form_field.widget.attrs['readonly'] = True


0

Se stai usando l'amministratore di Django, ecco la soluzione più semplice.

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

Penso che la tua migliore opzione sarebbe solo quella di includere l'attributo readonly nel tuo modello reso in <span>o <p>piuttosto che includerlo nel modulo se è di sola lettura.

I moduli servono per raccogliere dati, non visualizzarli. Detto questo, le opzioni per visualizzare in un readonlywidget e cancellare i dati POST sono ottime soluzioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.