W jaki sposób w formularzu Django mogę ustawić pole tylko do odczytu (lub wyłączone)?
Gdy formularz jest używany do utworzenia nowego wpisu, wszystkie pola powinny być włączone - ale gdy rekord jest w trybie aktualizacji, niektóre pola muszą być tylko do odczytu.
Na przykład podczas tworzenia nowego Item
modelu wszystkie pola muszą być edytowalne, ale czy podczas aktualizacji rekordu istnieje sposób na wyłączenie sku
pola, aby było widoczne, ale nie można go edytować?
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
Czy klasa może ItemForm
być ponownie wykorzystana? Jakie zmiany byłyby wymagane w klasie ItemForm
lub Item
modelu? Czy muszę napisać inną klasę „ ItemUpdateForm
”, aby zaktualizować element?
def update_item_view(request):
if request.method == 'POST':
form = ItemUpdateForm(request.POST)
# Validate and save
else:
form = ItemUpdateForm()
Odpowiedzi:
Jak wskazano w tej odpowiedzi , Django 1.9 dodał atrybut Field.disabled :
W wersji Django 1.8 i wcześniejszych, aby wyłączyć wpis w widżecie i zapobiec złośliwym włamaniom POST, oprócz ustawienia
readonly
atrybutu w polu formularza należy wyczyścić dane wejściowe :Lub zastąp
if instance and instance.pk
innym warunkiem wskazującym, że edytujesz. Możesz także ustawić atrybutdisabled
w polu wejściowym zamiastreadonly
.clean_sku
Funkcja zapewnia, żereadonly
wartość ta nie będzie przesłonięta przezPOST
.W przeciwnym razie nie ma wbudowanego pola formularza Django, które wyświetla wartość podczas odrzucania powiązanych danych wejściowych. Jeśli tego właśnie chcesz, powinieneś zamiast tego utworzyć osobne pole,
ModelForm
które wyklucza nieedytowalne pola, i po prostu wydrukować je w szablonie.źródło
clean_description
metodę do klasy formularza.disabled
Django 1.9 dodano nowy argument pola . JeśliField.disabled
jest ustawiony naTrue
, wówczas wartość POSTField
jest ignorowana. Więc jeśli używasz 1.9, nie musisz zmieniaćclean
, po prostu ustawdisabled = True
. Sprawdź tę odpowiedź.Django 1.9 dodał atrybut Field.disabled: https://docs.djangoproject.com/en/stable/ref/forms/fields/#disabled
źródło
disabled=True
spowoduje, że model zostanie odesłany do użytkownika z błędami sprawdzania poprawności.Ustawienie
readonly
widżetu powoduje, że dane wejściowe w przeglądarce są tylko do odczytu. Dodanieclean_sku
zwracanej wartościinstance.sku
gwarantuje, że wartość pola nie zmieni się na poziomie formularza.W ten sposób możesz użyć modelu (niezmodyfikowanego zapisu) i uniknąć błędu wymaganego w polu.
źródło
return self.cleaned_data['sku']
tak dobry, czy lepszy? W docs wydają się sugerować przy użyciucleaned_data
: „Wartość zwracana tej metody zastępuje istniejącą wartośćcleaned_data
, więc musi to być wartość pola zcleaned_data
(nawet jeśli ta metoda nie go zmienić) lub nowy oczyszczony wartość.”odpowiedź awalkera bardzo mi pomogła!
Zmieniłem jego przykład do pracy z Django 1.3, używając get_readonly_fields .
Zwykle powinieneś zadeklarować coś takiego w
app/admin.py
:Dostosowałem w ten sposób:
I działa dobrze. Teraz, jeśli dodasz element,
url
pole jest do odczytu-zapisu, ale po zmianie staje się tylko do odczytu.źródło
Aby ta funkcja działała w
ForeignKey
polu, należy wprowadzić kilka zmian. Po pierwsze,SELECT HTML
znacznik nie ma atrybutu „tylko do odczytu”.disabled="disabled"
Zamiast tego musimy użyć . Jednak przeglądarka nie wysyła z powrotem żadnych danych formularza dla tego pola. Musimy więc ustawić to pole tak, aby nie było wymagane, aby pole było poprawnie sprawdzane. Następnie musimy zresetować wartość z powrotem do poprzedniej, aby nie była pusta.Tak więc dla kluczy obcych będziesz musiał zrobić coś takiego:
W ten sposób przeglądarka nie pozwoli użytkownikowi zmienić pola i zawsze
POST
pozostanie pusta. Następnie zastępujemyclean
metodę, aby ustawić wartość pola na pierwotną w instancji.źródło
TabularInline
, ale nie powiodło się, ponieważattrs
zostały udostępnione międzywidget
instancjami i wszystkimi oprócz pierwszego wiersza, w tym nowo dodanego, renderowanego tylko do odczytu.W przypadku Django 1.2+ możesz zastąpić to pole w następujący sposób:
źródło
Field
disabled
nie robi tego, co chcę, ponieważ wyłącza pole, ale także usuwa etykietę / czyni ją niewidoczną.Zrobiłem klasę MixIn, którą możesz odziedziczyć, aby móc dodać iterowalne pole read_only, które wyłączy i zabezpieczy pola przy pierwszej edycji:
(Na podstawie odpowiedzi Daniela i Muhuka)
źródło
Właśnie utworzyłem możliwie najprostszy widget dla pola tylko do odczytu - tak naprawdę nie rozumiem, dlaczego formularze jeszcze tego nie mają:
W formie:
Bardzo proste - i daje mi tylko efekt. Przydatny w zestawie z wieloma wartościami tylko do odczytu. Oczywiście - możesz też być nieco bardziej sprytny i dać mu div z attrs, abyś mógł do niego dodawać klasy.
źródło
unicode(value)
Być może zrób to w zamian. Zakładając, że unicode dunder jest rozsądne, wtedy byś to dostał.Natknąłem się na podobny problem. Wygląda na to, że udało mi się go rozwiązać, definiując metodę „get_readonly_fields” w mojej klasie ModelAdmin.
Coś takiego:
Fajną rzeczą jest to, że
obj
podczas dodawania nowego elementu będzie to Brak lub będzie to obiekt edytowany podczas zmiany istniejącego elementu.get_readonly_display jest udokumentowany tutaj: http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#modeladmin-methods
źródło
Jedną z prostych opcji jest po prostu wpisanie
form.instance.fieldName
szablonu zamiastform.fieldName
.źródło
verbos_name
lublabel
pola? Jak mogę wyświetlić etykietę `w szablonie django? @alzclarkeJak to zrobić z Django 1.11:
źródło
Jako przydatny dodatek do postu Humphrey'a miałem pewne problemy z django-reversion, ponieważ nadal rejestrował wyłączone pola jako „zmienione”. Poniższy kod rozwiązuje problem.
źródło
Ponieważ nie mogę jeszcze komentować ( rozwiązanie muhuka ), odpowiem jako osobna odpowiedź. Oto kompletny przykład kodu, który działał dla mnie:
źródło
Jeszcze raz zaproponuję jeszcze jedno rozwiązanie :) Użyłem kodu Humphreya , więc to jest oparte na tym.
Jednak wystąpiły problemy z polem będącym
ModelChoiceField
. Wszystko działałoby na pierwsze żądanie. Jednak jeśli zestaw formularzy próbował dodać nowy element i nie udało się sprawdzić poprawności, coś poszło nie tak z „istniejącymi” formularzami, w którychSELECTED
opcja była resetowana do wartości domyślnej---------
.W każdym razie nie mogłem wymyślić, jak to naprawić. Zamiast tego (i myślę, że w rzeczywistości jest to czystsze w formularzu), stworzyłem pola
HiddenInputField()
. Oznacza to po prostu, że musisz wykonać trochę więcej pracy w szablonie.Naprawiłem więc uproszczenie formularza:
Następnie w szablonie musisz wykonać ręczne zapętlenie zestawu formularzy .
W takim przypadku zrobiłbyś coś takiego w szablonie:
To działało trochę lepiej dla mnie i przy mniejszej manipulacji formą.
źródło
Miałem ten sam problem, więc stworzyłem Mixin, który wydaje się działać w moich przypadkach użycia.
Sposób użycia, po prostu określ, które z nich mają być tylko do odczytu:
źródło
'collections.OrderedDict' object has no attribute 'iteritems'
jeśli potrzebujesz wielu pól tylko do odczytu. możesz użyć dowolnej z poniższych metod
metoda 1
metoda 2
metoda dziedziczenia
źródło
Dwa kolejne (podobne) podejścia z jednym uogólnionym przykładem:
1) pierwsze podejście - usunięcie pola w metodzie save (), np. (Nie testowane;)):
2) drugie podejście - zresetuj pole do wartości początkowej w czystej metodzie:
W oparciu o drugie podejście uogólniłem to w następujący sposób:
źródło
W przypadku wersji administracyjnej uważam, że jest to bardziej kompaktowy sposób, jeśli masz więcej niż jedno pole:
źródło
Na podstawie odpowiedzi Yamikepa znalazłem lepsze i bardzo proste rozwiązanie, które obsługuje również
ModelMultipleChoiceField
pola.Usunięcie pola
form.cleaned_data
zapobiega zapisywaniu pól:Stosowanie:
źródło
Oto nieco bardziej zaangażowana wersja, oparta na odpowiedzi Christophe31 . Nie opiera się na atrybucie „tylko do odczytu”. To sprawia, że jego problemy, takie jak zaznaczanie pól, które wciąż są zmienne, a okna danych wciąż się pojawiają, znikają.
Zamiast tego zawija widżet pól formularza w widżecie tylko do odczytu, dzięki czemu formularz nadal jest sprawdzany. Zawartość oryginalnego widżetu jest wyświetlana wewnątrz
<span class="hidden"></span>
tagów. Jeśli widget marender_readonly()
metodę, używa go jako widocznego tekstu, w przeciwnym razie analizuje HTML oryginalnego widgetu i próbuje odgadnąć najlepszą reprezentację.źródło
Czy to najprostszy sposób?
Bezpośrednio w kodzie widoku coś takiego:
To działa dobrze!
źródło
W wersji django 1.9+
możesz użyć argumentu Fields disabled, aby wyłączyć pole. np. W poniższym fragmencie kodu z pliku forms.py, wyłączyłem pole kod_ pracownika
Odwołanie https://docs.djangoproject.com/en/2.0/ref/forms/fields/#disabled
źródło
Jeśli pracujesz z
Django ver < 1.9
(1.9
dodanoField.disabled
atrybut), możesz spróbować dodać następujący dekorator do__init__
metody formularza :Główną ideą jest to, że jeśli pole jest
readonly
, nie potrzebujesz żadnej innej wartości opróczinitial
.PS: Nie zapomnij ustawić
yuor_form_field.widget.attrs['readonly'] = True
źródło
Jeśli używasz administratora Django, oto najprostsze rozwiązanie.
źródło
Myślę, że najlepszą opcją byłoby włączenie atrybutu tylko do odczytu w szablonie renderowanym w
<span>
lub<p>
raczej niż włączenie go w formularzu, jeśli jest „tylko do odczytu”.Formularze służą do gromadzenia danych, a nie ich wyświetlania. To powiedziawszy, opcje wyświetlania w
readonly
widżecie i przeszukiwania danych POST są świetnymi rozwiązaniami.źródło