API för formulär¶
Om detta dokument
Detta dokument täcker de hårda detaljerna i Djangos formulär-API. Du bör läsa introduktion till att arbeta med formulär först.
Inbundna och obundna formulär¶
En instans av Form
är antingen bunden till en uppsättning data eller obunden.
Om det är bundet till en uppsättning data, kan det validera dessa data och rendera formuläret som HTML med de data som visas i HTML.
Om det är unbound kan det inte göra validering (eftersom det inte finns några data att validera!), men det kan fortfarande återge det tomma formuläret som HTML.
För att skapa en obunden Form
-instans instansierar du klassen:
>>> f = ContactForm()
För att binda data till ett formulär skickar du data som en ordbok som första parameter till din Form
-klass konstruktör:
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... }
>>> f = ContactForm(data)
I den här ordlistan är nycklarna fältnamnen, som motsvarar attributen i din klass Form
. Värdena är de data som du försöker validera. Dessa kommer vanligtvis att vara strängar, men det finns inget krav på att de ska vara strängar; typen av data du skickar beror på Field
, som vi kommer att se om ett ögonblick.
- Form.is_bound¶
Om du behöver skilja mellan bundna och obundna formulärinstanser vid körning, kontrollera värdet på formulärets attribut is_bound
:
>>> f = ContactForm()
>>> f.is_bound
False
>>> f = ContactForm({"subject": "hello"})
>>> f.is_bound
True
Observera att om du skickar en tom ordbok skapas ett bundet formulär med tomma data:
>>> f = ContactForm({})
>>> f.is_bound
True
Om du har en bunden Form
-instans och vill ändra data på något sätt, eller om du vill binda en obunden Form
-instans till vissa data, skapar du en annan Form
-instans. Det finns inget sätt att ändra data i en Form
-instans. När en Form
-instans har skapats bör du betrakta dess data som oföränderliga, oavsett om den har data eller inte.
Använda formulär för att validera data¶
- Form.clean()¶
Implementera en clean()
-metod på din Form
när du måste lägga till anpassad validering för fält som är beroende av varandra. Se Rengöring och validering av fält som är beroende av varandra för exempel på användning.
- Form.is_valid()¶
Den primära uppgiften för ett Form
-objekt är att validera data. Med en bunden Form
-instans anropar du is_valid()
-metoden för att köra validering och returnera en boolesk som anger om data var giltiga:
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
True
Låt oss prova med några ogiltiga data. I det här fallet är ”ämne” tomt (ett fel, eftersom alla fält är obligatoriska som standard) och ”avsändare” är inte en giltig e-postadress:
>>> data = {
... "subject": "",
... "message": "Hi there",
... "sender": "invalid email address",
... "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
False
- Form.errors¶
Få tillgång till attributet errors
för att få en ordlista med felmeddelanden:
>>> f.errors
{'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']}
I den här ordlistan är nycklarna fältnamnen och värdena listor med strängar som representerar felmeddelandena. Felmeddelandena lagras i listor eftersom ett fält kan ha flera felmeddelanden.
Du kan komma åt errors
utan att först behöva anropa is_valid()
. Formulärets data kommer att valideras första gången du antingen anropar is_valid()
eller använder errors
.
Valideringsrutinerna kommer bara att anropas en gång, oavsett hur många gånger du använder errors
eller anropar is_valid()
. Detta innebär att om valideringen har bieffekter, kommer dessa bieffekter bara att utlösas en gång.
- Form.errors.as_data()¶
Returnerar ett dict
som mappar fält till deras ursprungliga ValidationError
-instanser.
>>> f.errors.as_data()
{'sender': [ValidationError(['Enter a valid email address.'])],
'subject': [ValidationError(['This field is required.'])]}
Använd den här metoden när du behöver identifiera ett fel med hjälp av dess ”kod”. Detta möjliggör saker som att skriva om felmeddelandet eller skriva anpassad logik i en vy när ett visst fel finns. Den kan också användas för att serialisera felen i ett anpassat format (t.ex. XML); till exempel as_json()
förlitar sig på as_data()
.
Behovet av metoden as_data()
beror på bakåtkompatibilitet. Tidigare förlorades ValidationError
-instanser så snart deras renderade felmeddelanden lades till i Form.errors
-ordlistan. Helst skulle Form.errors
ha lagrat ValidationError
-instanser och metoder med ett as_
-prefix skulle kunna rendera dem, men det måste göras tvärtom för att inte bryta kod som förväntar sig renderade felmeddelanden i Form.errors
.
- Form.errors.as_json(escape_html=False)¶
Returnerar felen serialiserade som JSON.
>>> f.errors.as_json()
{"sender": [{"message": "Enter a valid email address.", "code": "invalid"}],
"subject": [{"message": "This field is required.", "code": "required"}]}
Som standard escapar inte as_json()
sin utdata. Om du använder den för något som AJAX-förfrågningar till en formulärvy där klienten tolkar svaret och infogar fel på sidan, vill du vara säker på att undkomma resultaten på klientsidan för att undvika risken för en cross-site scripting-attack. Du kan göra detta i JavaScript med element.textContent = errorText
eller med jQuerys $(el).text(errorText)
(snarare än dess .html()
-funktion).
Om du av någon anledning inte vill använda escaping på klientsidan kan du också ställa in escape_html=True
och felmeddelanden kommer att escapas så att du kan använda dem direkt i HTML.
- Form.errors.get_json_data(escape_html=False)¶
Returnerar felen som en ordbok som är lämplig för serialisering till JSON. Form.errors.as_json()
returnerar serialiserad JSON, medan detta returnerar feldata innan den serialiseras.
Parametern escape_html
fungerar på det sätt som beskrivs i Form.errors.as_json()
.
- Form.add_error(field, error)¶
Denna metod gör det möjligt att lägga till fel i specifika fält inom metoden Form.clean()
, eller helt utanför formuläret, t.ex. från en vy.
Argumentet field
är namnet på det fält som felen ska läggas till i. Om dess värde är None
kommer felet att behandlas som ett icke-fältfel som returneras av Form.non_field_errors()
.
Argumentet error
kan vara en sträng, eller helst en instans av ValidationError
. Se Upphävande av ValidationError för bästa praxis vid definition av formulärfel.
Observera att Form.add_error()
automatiskt tar bort det relevanta fältet från cleaned_data
.
- Form.has_error(field, code=None)¶
Denna metod returnerar en boolean som anger om ett fält har ett fel med en specifik fel-”kod”. Om code
är None
returneras True
om fältet innehåller några fel alls.
För att kontrollera fel som inte är fält använder du NON_FIELD_ERRORS
som parametern field
.
- Form.non_field_errors()¶
Den här metoden returnerar listan över fel från Form.errors
som inte är associerade med ett visst fält. Detta inkluderar ValidationError
som tas upp i Form.clean()
och fel som läggs till med Form.add_error(None, "...")
.
Beteende för obundna formulär¶
Det är meningslöst att validera ett formulär utan data, men så här går det till när formuläret är obundet:
>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}
Initiala formvärden¶
- Form.initial¶
Använd initial
för att ange det initiala värdet för formulärfält vid körning. Du kanske t.ex. vill fylla i fältet username
med användarnamnet för den aktuella sessionen.
För att åstadkomma detta använder du argumentet initial
till en Form
. Detta argument, om det anges, bör vara en ordbok som mappar fältnamn till initiala värden. Inkludera bara de fält för vilka du anger ett initialt värde; det är inte nödvändigt att inkludera alla fält i ditt formulär. Exempelvis:
>>> f = ContactForm(initial={"subject": "Hi there!"})
Dessa värden visas endast för obundna formulär och de används inte som reservvärden om ett visst värde inte anges.
Om en Field
definierar initial
och du inkluderar initial
när du instansierar Form
, så kommer den senare initial
att ha företräde. I det här exemplet anges initial
både på fältnivå och på formulärinstansnivå, och den senare får företräde:
>>> from django import forms
>>> class CommentForm(forms.Form):
... name = forms.CharField(initial="class")
... url = forms.URLField()
... comment = forms.CharField()
...
>>> f = CommentForm(initial={"name": "instance"}, auto_id=False)
>>> print(f)
<div>Name:<input type="text" name="name" value="instance" required></div>
<div>Url:<input type="url" name="url" required></div>
<div>Comment:<input type="text" name="comment" required></div>
- Form.get_initial_for_field(field, field_name)¶
Returnerar de initiala uppgifterna för ett formulärfält. Den hämtar data från Form.initial
om den finns, annars försöker den Field.initial
. Kallbara värden utvärderas.
Det rekommenderas att använda BoundField.initial
framför get_initial_for_field()
eftersom BoundField.initial
har ett enklare gränssnitt. Dessutom, till skillnad från get_initial_for_field()
, cachar BoundField.initial
sina värden. Detta är användbart särskilt när man hanterar anropbara filer vars returvärden kan ändras (t.ex. datetime.now
eller uuid.uuid4
):
>>> import uuid
>>> class UUIDCommentForm(CommentForm):
... identifier = forms.UUIDField(initial=uuid.uuid4)
...
>>> f = UUIDCommentForm()
>>> f.get_initial_for_field(f.fields["identifier"], "identifier")
UUID('972ca9e4-7bfe-4f5b-af7d-07b3aa306334')
>>> f.get_initial_for_field(f.fields["identifier"], "identifier")
UUID('1b411fab-844e-4dec-bd4f-e9b0495f04d0')
>>> # Using BoundField.initial, for comparison
>>> f["identifier"].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
>>> f["identifier"].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
Kontroll av vilka formulärdata som har ändrats¶
- Form.has_changed()¶
Använd metoden has_changed()
på ditt Form
när du behöver kontrollera om formulärdata har ändrats från de ursprungliga data.
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... }
>>> f = ContactForm(data, initial=data)
>>> f.has_changed()
False
När formuläret skickas in rekonstruerar vi det och tillhandahåller originaldata så att jämförelsen kan göras:
>>> f = ContactForm(request.POST, initial=data)
>>> f.has_changed()
has_changed()
blir True
om data från request.POST
skiljer sig från vad som angavs i initial
eller False
annars. Resultatet beräknas genom att anropa Field.has_changed()
för varje fält i formuläret.
- Form.changed_data¶
Attributet changed_data
returnerar en lista med namnen på de fält vars värden i formulärets bundna data (vanligtvis request.POST
) skiljer sig från vad som angavs i initial
. Det returnerar en tom lista om inga data skiljer sig åt.
>>> f = ContactForm(request.POST, initial=data)
>>> if f.has_changed():
... print("The following fields changed: %s" % ", ".join(f.changed_data))
...
>>> f.changed_data
['subject', 'message']
Åtkomst till fälten från formuläret¶
- Form.fields¶
Du kan komma åt fälten i Form
-instansen från dess fields
-attribut:
>>> for row in f.fields.values():
... print(row)
...
<django.forms.fields.CharField object at 0x7ffaac632510>
<django.forms.fields.URLField object at 0x7ffaac632f90>
<django.forms.fields.CharField object at 0x7ffaac3aa050>
>>> f.fields["name"]
<django.forms.fields.CharField object at 0x7ffaac6324d0>
Du kan ändra fältet och BoundField
i Form
-instansen för att ändra hur det presenteras i formuläret:
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
>>> f["subject"].label = "Topic"
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Topic:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
Tänk på att inte ändra attributet base_fields
eftersom denna ändring kommer att påverka alla efterföljande ContactForm
-instanser inom samma Python-process:
>>> f.base_fields["subject"].label_suffix = "?"
>>> another_f = ContactForm(auto_id=False)
>>> another_f.as_div().split("</div>")[0]
'<div><label for="id_subject">Subject?</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
Tillgång till ”rena” data¶
- Form.cleaned_data¶
Varje fält i en Form
-klass ansvarar inte bara för att validera data utan också för att ”rensa” dem - normalisera dem till ett enhetligt format. Det här är en bra funktion eftersom det gör att data för ett visst fält kan matas in på många olika sätt och alltid resultera i ett enhetligt resultat.
Till exempel: normaliserar DateField
indata till ett Python-objekt av typen datetime.date
. Oavsett om du skickar en sträng i formatet '1994-07-15'
, ett datetime.date
-objekt eller ett antal andra format, kommer DateField
alltid att normalisera det till ett datetime.date
-objekt så länge det är giltigt.
När du har skapat en Form
-instans med en uppsättning data och validerat den, kan du komma åt de rena data via dess cleaned_data
-attribut:
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}
Observera att alla textbaserade fält - t.ex. CharField
eller EmailField
- alltid omvandlar inmatningen till en sträng. Vi kommer att täcka kodningsimplikationerna senare i detta dokument.
Om dina data inte valideras innehåller ordlistan cleaned_data
endast de giltiga fälten:
>>> data = {
... "subject": "",
... "message": "Hi there",
... "sender": "invalid email address",
... "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
False
>>> f.cleaned_data
{'cc_myself': True, 'message': 'Hi there'}
cleaned_data
kommer alltid bara att innehålla en nyckel för fält som definieras i Form
, även om du skickar extra data när du definierar Form
. I det här exemplet skickar vi en massa extra fält till konstruktören ContactForm
, men cleaned_data
innehåller bara formulärets fält:
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... "extra_field_1": "foo",
... "extra_field_2": "bar",
... "extra_field_3": "baz",
... }
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data # Doesn't contain extra_field_1, etc.
{'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}
När Form
är giltigt kommer cleaned_data
att innehålla en nyckel och ett värde för alla dess fält, även om data inte innehöll ett värde för vissa valfria fält. I det här exemplet innehåller dataordboken inte något värde för fältet nick_name
, men cleaned_data
innehåller det, med ett tomt värde:
>>> from django import forms
>>> class OptionalPersonForm(forms.Form):
... first_name = forms.CharField()
... last_name = forms.CharField()
... nick_name = forms.CharField(required=False)
...
>>> data = {"first_name": "John", "last_name": "Lennon"}
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'nick_name': '', 'first_name': 'John', 'last_name': 'Lennon'}
I exemplet ovan sätts värdet cleaned_data
för nick_name
till en tom sträng, eftersom nick_name
är en CharField
och CharField
behandlar tomma värden som en tom sträng. Varje fälttyp vet vad dess ”tomma” värde är - t.ex. för DateField
är det None
istället för den tomma strängen. För fullständig information om varje fälts beteende i det här fallet, se anmärkningen ”Tomt värde” för varje fält i avsnittet Inbyggda Field-klasser nedan.
Du kan skriva kod för att utföra validering för vissa formulärfält (baserat på deras namn) eller för formuläret som helhet (med hänsyn till kombinationer av olika fält). Mer information om detta finns i Validering av formulär och fält.
Utmatning av formulär som HTML¶
Den andra uppgiften för ett Form
-objekt är att rendera sig själv som HTML. För att göra det, print
det:
>>> f = ContactForm()
>>> print(f)
<div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject"></div>
<div><label for="id_message">Message:</label><input type="text" name="message" required id="id_message"></div>
<div><label for="id_sender">Sender:</label><input type="email" name="sender" required id="id_sender"></div>
<div><label for="id_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_cc_myself"></div>
Om formuläret är bundet till data kommer HTML-utdata att innehålla dessa data på lämpligt sätt. Om ett fält t.ex. representeras av en <input type="text">
, kommer data att finnas i attributet value
. Om ett fält representeras av en <input type="checkbox">
, kommer HTML-texten att innehålla checked
om så är lämpligt:
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> print(f)
<div><label for="id_subject">Subject:</label><input type="text" name="subject" value="hello" maxlength="100" required id="id_subject"></div>
<div><label for="id_message">Message:</label><input type="text" name="message" value="Hi there" required id="id_message"></div>
<div><label for="id_sender">Sender:</label><input type="email" name="sender" value="foo@example.com" required id="id_sender"></div>
<div><label for="id_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_cc_myself" checked></div>
Denna standardutskrift omsluter varje fält med en <div>
. Lägg märke till följande:
För flexibilitetens skull innehåller utdata inte taggarna<form>```` och
``</form> eller taggen ``<input type="submit">
. Det är ditt jobb att göra det.Varje fälttyp har en standard HTML-representation.
CharField
representeras av en<input type="text">
ochEmailField
av en<input type="email">
.BooleanField(null=False)
representeras av en<input type="checkbox">
. Observera att detta bara är förnuftiga standardvärden; du kan ange vilken HTML som ska användas för ett visst fält genom att använda widgets, som vi förklarar strax.HTML-namnet för varje tagg hämtas direkt från attributnamnet i klassen ”ContactForm”.
Textetiketten för varje fält - t.ex.
'Subject:'
,'Message:'
och'Cc myself:'
genereras från fältnamnet genom att alla understreck omvandlas till mellanslag och första bokstaven skrivs med versaler. Observera återigen att detta bara är förnuftiga standardvärden; du kan också ange etiketter manuellt.Varje textetikett omges av en HTML-tagg
<label>
, som pekar på lämpligt formulärfält via dessid
. Dessid
genereras i sin tur genom att fältnamnet kompletteras med'id_
. Attributenid
och taggarna<label>
inkluderas i utdata som standard, för att följa bästa praxis, men du kan ändra detta beteende.Utdata använder HTML5-syntax, med
<!DOCTYPE html>
som mål. Exempelvis används booleska attribut somchecked
i stället för XHTML-stilenchecked='checked'
.
Även om <div>
är standardutmatningsstilen när du skriver ut
ett formulär kan du anpassa utmatningen genom att använda din egen formulärmall som kan ställas in för hela webbplatsen, per formulär eller per instans. Se återanvändbara-formulär-mallar.
Standard rendering¶
Standardrenderingen när du printar
ett formulär använder följande metoder och attribut.
template_name
¶
- Form.template_name¶
Namnet på den mall som återges om formuläret omvandlas till en sträng, t.ex. via print(form)
eller i en mall via {{ form }}
.
Som standard en egenskap som returnerar värdet av renderingsprogrammets form_template_name
. Du kan ställa in det som ett strängmallnamn för att åsidosätta det för en viss formulärklass.
render()`
¶
- Form.render(template_name=None, context=None, renderer=None)¶
Renderingsmetoden anropas av __str__
samt metoderna Form.as_div()
, Form.as_table()
, Form.as_p()
och Form.as_ul()
. Alla argument är valfria och standardvärdena är:
template_name
:Form.template_name
context
: Värde som returneras avForm.get_context()
renderer
: Värde som returneras avForm.default_renderer
Genom att skicka template_name
kan du anpassa den mall som används för bara ett enda anrop.
get_context()`
¶
- Form.get_context()¶
Returnerar mallkontexten för rendering av formuläret.
Den tillgängliga kontexten är:
”Formulär”: Det bundna formuläret.
fält
: Alla bundna fält, utom de dolda fälten.hidden_fields
: Alla dolda bundna fält.fel
: Alla formulärfel som inte är fältrelaterade eller som är relaterade till dolda fält.
template_name_label
¶
- Form.template_name_label¶
Den mall som används för att rendera ett fälts <label>
, används vid anrop av BoundField.label_tag()
/legend_tag()
. Kan ändras per formulär genom att åsidosätta detta attribut eller mer generellt genom att åsidosätta standardmallen, se även Åsidosätta inbyggda formulärmallar.
Utmatningsstilar¶
Det rekommenderade tillvägagångssättet för att ändra formulärets utmatningsstil är att ange en anpassad formulärmall antingen för hela webbplatsen, per formulär eller per instans. Se Återanvändbara formulärmallar för exempel.
Följande hjälpfunktioner tillhandahålls för bakåtkompatibilitet och är en proxy till Form.render()
som skickar ett visst värde för template_name
.
Observera
Av de mallar och utdatastilar som tillhandahålls av ramverket rekommenderas standardmallen as_div()
framför versionerna as_p()
, as_table()
och as_ul()
eftersom mallen implementerar <fieldset>
och <legend>
för att gruppera relaterade indata och är lättare att navigera i för skärmläsaranvändare.
Varje helper parar ihop en formulärmetod med ett attribut som anger det lämpliga mallnamnet.
as_div()`
¶
- Form.template_name_div¶
Den mall som används av as_div()
. Standard: 'django/forms/div.html'
.
- Form.as_div()¶
as_div()
renderar formuläret som en serie av <div>
element, där varje <div>
innehåller ett fält, t.ex:
>>> f = ContactForm()
>>> f.as_div()
… ger HTML som:
<div>
<label for="id_subject">Subject:</label>
<input type="text" name="subject" maxlength="100" required id="id_subject">
</div>
<div>
<label for="id_message">Message:</label>
<input type="text" name="message" required id="id_message">
</div>
<div>
<label for="id_sender">Sender:</label>
<input type="email" name="sender" required id="id_sender">
</div>
<div>
<label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself">
</div>
as_p()`
¶
- Form.template_name_p¶
Den mall som används av as_p()
. Standard: 'django/forms/p.html'
.
- Form.as_p()¶
as_p()
återger formuläret som en serie <p>
taggar, där varje <p>
innehåller ett fält:
>>> f = ContactForm()
>>> f.as_p()
'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" required></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>'
>>> print(f.as_p())
<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p>
<p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></p>
<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>
as_ul()`
¶
- Form.template_name_ul¶
Den mall som används av as_ul()
. Standard: 'django/forms/ul.html'
.
- Form.as_ul()¶
as_ul()
renderar formuläret som en serie av <li>
taggar, med varje <li>
som innehåller ett fält. Den inkluderar *inte*<ul>```` eller ``,</ul> så att du kan ange HTML-attribut på ``<ul>
för flexibilitet:
>>> f = ContactForm()
>>> f.as_ul()
'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>'
>>> print(f.as_ul())
<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>
<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>
<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>
as_table()`
¶
- Form.template_name_table¶
Den mall som används av as_table()
. Standard: 'django/forms/table.html'
.
- Form.as_table()¶
as_table()
återger formuläret som en HTML <table>
:
>>> f = ContactForm()
>>> f.as_table()
'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>'
>>> print(f.as_table())
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>
Styling av nödvändiga eller felaktiga formulärrader¶
- Form.error_css_class¶
- Form.required_css_class¶
Det är ganska vanligt att formatera formulärrader och fält som är obligatoriska eller har fel. Du kanske till exempel vill presentera obligatoriska formulärrader i fetstil och markera fel i rött.
Klassen Form
har ett par krokar som du kan använda för att lägga till class
-attribut till obligatoriska rader eller till rader med fel: ställ in attributen Form.error_css_class
och/eller Form.required_css_class
:
from django import forms
class ContactForm(forms.Form):
error_css_class = "error"
required_css_class = "required"
# ... and the rest of your fields here
När du har gjort det kommer raderna att få klasserna "error"
och/eller "required"
, efter behov. HTML kommer att se ut ungefär som:
>>> f = ContactForm(data)
>>> print(f)
<div class="required"><label for="id_subject" class="required">Subject:</label> ...
<div class="required"><label for="id_message" class="required">Message:</label> ...
<div class="required"><label for="id_sender" class="required">Sender:</label> ...
<div><label for="id_cc_myself">Cc myself:</label> ...
>>> f["subject"].label_tag()
<label class="required" for="id_subject">Subject:</label>
>>> f["subject"].legend_tag()
<legend class="required" for="id_subject">Subject:</legend>
>>> f["subject"].label_tag(attrs={"class": "foo"})
<label for="id_subject" class="foo required">Subject:</label>
>>> f["subject"].legend_tag(attrs={"class": "foo"})
<legend for="id_subject" class="foo required">Subject:</legend>
Du kan ytterligare modifiera återgivningen av formulärrader genom att använda en custom BoundField.
Konfigurera återgivningen av widgetar i ett formulär¶
- Form.default_renderer¶
Anger vilken renderer som ska användas för formuläret. Standardvärdet är None
, vilket innebär att standardrenderingsprogrammet som anges i inställningen FORM_RENDERER
används.
Du kan ange detta som ett klassattribut när du deklarerar ditt formulär eller använda argumentet renderer
i Form.__init__()
. Till exempel:
from django import forms
class MyForm(forms.Form):
default_renderer = MyRenderer()
eller:
form = MyForm(renderer=MyRenderer())
Anmärkningar om fältbeställning¶
I genvägarna as_p()
, as_ul()
och as_table()
visas fälten i den ordning som du definierar dem i formulärklassen. I exemplet ContactForm
är fälten definierade i ordningen subject
, message
, sender
, cc_myself
. Om du vill ändra ordningen på HTML-utdata ändrar du den ordning i vilken fälten listas i klassen.
Det finns flera andra sätt att skräddarsy beställningen:
- Form.field_order¶
Som standard är Form.field_order=None
, vilket innebär att den ordning som du definierar fälten i formulärklassen behålls. Om field_order
är en lista med fältnamn ordnas fälten enligt listan och återstående fält läggs till enligt standardordningen. Okända fältnamn i listan ignoreras. Detta gör det möjligt att inaktivera ett fält i en underklass genom att ställa in det på None
utan att behöva omdefiniera ordningen.
Du kan också använda argumentet Form.field_order
till en Form
för att åsidosätta fältordningen. Om en Form
definierar field_order
och du inkluderar field_order
när du instansierar Form
, så kommer den senare field_order
att ha företräde.
- Form.order_fields(field_order)¶
Du kan omorganisera fälten när som helst med hjälp av order_fields()
med en lista över fältnamn som i field_order
.
Hur fel visas¶
Om du renderar ett bundet Form
-objekt, kommer renderingen automatiskt att köra formulärets validering om det inte redan har skett, och HTML-utmatningen kommer att innehålla valideringsfelen som en <ul class="errorlist">
.
Följande:
>>> data = {
... "subject": "",
... "message": "Hi there",
... "sender": "invalid email address",
... "cc_myself": True,
... }
>>> ContactForm(data).as_div()
… ger HTML som:
<div>
<label for="id_subject">Subject:</label>
<ul class="errorlist" id="id_subject_error"><li>This field is required.</li></ul>
<input type="text" name="subject" maxlength="100" required aria-invalid="true" aria-describedby="id_subject_error" id="id_subject">
</div>
<div>
<label for="id_message">Message:</label>
<textarea name="message" cols="40" rows="10" required id="id_message">Hi there</textarea>
</div>
<div>
<label for="id_sender">Sender:</label>
<ul class="errorlist" id="id_sender_error"><li>Enter a valid email address.</li></ul>
<input type="email" name="sender" value="invalid email address" maxlength="320" required aria-invalid="true" aria-describedby="id_sender_error" id="id_sender">
</div>
<div>
<label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself" checked>
</div>
Djangos standardformulärsmallar kommer att associera valideringsfel med deras inmatning genom att använda HTML-attributet aria-describedby
när fältet har ett auto_id
och en anpassad aria-describedby
inte tillhandahålls. Om ett anpassat aria-describedby
anges när widgeten definieras kommer detta att åsidosätta standardvärdet.
Om widgeten återges i en <fieldset>
läggs aria-describedby
till i detta element, annars läggs det till i widgetens HTML-element (t.ex. <input>
).
aria-describedby
lades till för att associera fel med dess input.
Anpassa formatet för fellistan¶
- class ErrorList(initlist=None, error_class=None, renderer=None, field_id=None)[source]¶
Som standard använder formulär
django.forms.utils.ErrorList
för att formatera valideringsfel.ErrorList
är ett listliknande objekt därinitlist
är listan över fel. Dessutom har denna klass följande attribut och metoder.Changed in Django 5.2:Argumentet
field_id
har lagts till.- error_class¶
De CSS-klasser som ska användas vid rendering av fellistan. Alla angivna klasser läggs till i standardklassen
errorlist
.
- renderer¶
Anger vilken renderer som ska användas för
ErrorList
. Standardvärdet ärNone
vilket innebär att standardrenderaren som anges i inställningenFORM_RENDERER`
används.
- field_id¶
- New in Django 5.2.
Ett
id
för det fält som felen avser. Detta gör att ett HTML-attributid
kan läggas till i felmallen och är användbart för att associera felen med fältet. Standardmallen använder formatetid="{{ field_id }}_error"
och ett värde tillhandahålls avForm.add_error()
med hjälp av fältetsauto_id
.
- template_name¶
Namnet på den mall som används vid anrop av
__str__
ellerrender()
. Som standard är detta'django/forms/errors/list/default.html'
som är en proxy för mallen'ul.html'
.
- template_name_text¶
Namnet på den mall som används vid anrop av
as_text()
. Som standard är detta'django/forms/errors/list/text.html'
. Den här mallen återger felen som en lista med punkter.
- template_name_ul¶
Namnet på den mall som används vid anrop av
as_ul()
. Som standard är detta'django/forms/errors/list/ul.html'
. Denna mall återger felen i<li>
taggar med en omslags<ul>
med CSS-klasserna som definieras averror_class
.
- get_context()[source]¶
Returnerar kontext för återgivning av fel i en mall.
Den tillgängliga kontexten är:
errors
: En lista över fel.error_class
: En sträng med CSS-klasser.
- render(template_name=None, context=None, renderer=None)¶
Renderingsmetoden anropas av
__str__
samt av metodenas_ul`()
.Alla argument är valfria och kommer att användas som standard:
template_name
: Värde som returneras avtemplate_name
context
: Värde som returneras avget_context()
renderer
: Värde som returneras avrenderer
- as_text()¶
Renderar fellistan med hjälp av den mall som definieras av
template_name_text
.
- as_ul()¶
Renderar fellistan med hjälp av den mall som definieras av
template_name_ul
.
Om du vill anpassa återgivningen av fel kan detta uppnås genom att åsidosätta attributet
template_name
eller mer allmänt genom att åsidosätta standardmallen, se även Åsidosätta inbyggda formulärmallar.
Mer detaljerad utdata¶
Metoderna as_p()
, as_ul()
och as_table()
är genvägar - de är inte det enda sättet som ett formulärobjekt kan visas på.
- class BoundField[source]¶
Används för att visa HTML eller åtkomstattribut för ett enskilt fält i en
Form
-instans.Metoden
__str__()
för detta objekt visar HTML för detta fält.Du kan använda
Form.bound_field_class
ochField.bound_field_class
för att ange en annanBoundField
-klass per formulär respektive per fält.Se Anpassa BoundField för exempel på åsidosättande av en
BoundField
.
Om du vill hämta ett enskilt BoundField
använder du syntaxen för ordboksuppslagning i formuläret med fältets namn som nyckel:
>>> form = ContactForm()
>>> print(form["subject"])
<input id="id_subject" type="text" name="subject" maxlength="100" required>
För att hämta alla BoundField
-objekt, iterera formuläret:
>>> form = ContactForm()
>>> for boundfield in form:
... print(boundfield)
...
<input id="id_subject" type="text" name="subject" maxlength="100" required>
<input type="text" name="message" id="id_message" required>
<input type="email" name="sender" id="id_sender" required>
<input type="checkbox" name="cc_myself" id="id_cc_myself">
Den fältspecifika utmatningen följer formulärobjektets inställning auto_id
:
>>> f = ContactForm(auto_id=False)
>>> print(f["message"])
<input type="text" name="message" required>
>>> f = ContactForm(auto_id="id_%s")
>>> print(f["message"])
<input type="text" name="message" id="id_message" required>
Attribut för BoundField
¶
- BoundField.aria_describedby[source]¶
- New in Django 5.2.
Returnerar en
aria-describedby
-referens för att associera ett fält med dess hjälptext och fel. ReturnerarNone
omaria-describedby
är inställt iWidget.attrs
för att bevara det användardefinierade attributet när formuläret renderas.
- BoundField.auto_id[source]¶
HTML ID-attributet för denna
BoundField
. Returnerar en tom sträng omForm.auto_id
ärFalse
.
- BoundField.data[source]¶
Denna egenskap returnerar data för denna
BoundField
som extraherats av widgetensvalue_from_datadict()
-metod, ellerNone
om den inte gavs:>>> unbound_form = ContactForm() >>> print(unbound_form["subject"].data) None >>> bound_form = ContactForm(data={"subject": "My Subject"}) >>> print(bound_form["subject"].data) My Subject
- BoundField.errors[source]¶
Ett listliknande objekt som visas som en HTML
<ul class="errorlist">
när det skrivs ut:>>> data = {"subject": "hi", "message": "", "sender": "", "cc_myself": ""} >>> f = ContactForm(data, auto_id=False) >>> print(f["message"]) <input type="text" name="message" required aria-invalid="true"> >>> f["message"].errors ['This field is required.'] >>> print(f["message"].errors) <ul class="errorlist"><li>This field is required.</li></ul> >>> f["subject"].errors [] >>> print(f["subject"].errors) >>> str(f["subject"].errors) ''
Vid rendering av ett fält med fel kommer
aria-invalid="true"
att ställas in på fältets widget för att indikera att det finns ett fel för skärmläsaranvändare.
- BoundField.field¶
Formulärets
Field
-instans från den formulärklass som dennaBoundField
omsluter.
- BoundField.form¶
Den
Form
-instans som dennaBoundField
är bunden till.
- BoundField.html_name¶
Det namn som kommer att användas i widgetens HTML-attribut
name
. Det tar hänsyn till formuläretprefix
.
- BoundField.id_for_label[source]¶
Använd den här egenskapen för att återge fältets ID. Till exempel: om du manuellt konstruerar en
<label>
i din mall (trots attlabel_tag()
/legend_tag()
gör detta åt dig):<label for="{{ form.my_field.id_for_label }}">...</label>{{ my_field }}
Som standard kommer detta att vara fältets namn med prefixet
id_
(”id_my_field
” i exemplet ovan). Du kan ändra ID genom att ställa inattrs
på fältets widget. Till exempel:, om du deklarerar ett fält så här:my_field = forms.CharField(widget=forms.TextInput(attrs={"id": "myFIELD"}))
och med hjälp av mallen ovan, skulle rendera något liknande:
<label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" required>
- BoundField.initial[source]¶
Använd
BoundField.initial
för att hämta initialdata för ett formulärfält. Den hämtar data frånForm.initial
om den finns, annars försöker denField.initial
. Kallbara värden utvärderas. Se Initiala formvärden för fler exempel.BoundField.initial
cachar sitt returvärde, vilket är användbart särskilt när man har att göra med anropbara filer vars returvärden kan ändras (t.ex.datetime.now
elleruuid.uuid4
):>>> from datetime import datetime >>> class DatedCommentForm(CommentForm): ... created = forms.DateTimeField(initial=datetime.now) ... >>> f = DatedCommentForm() >>> f["created"].initial datetime.datetime(2021, 7, 27, 9, 5, 54) >>> f["created"].initial datetime.datetime(2021, 7, 27, 9, 5, 54)
Att använda
BoundField.initial
rekommenderas framförget_initial_for_field()
.
Returnerar
True
om widgeten i dennaBoundField
är dold.
- BoundField.label¶
Fältets
label
. Detta används ilabel_tag()
/legend_tag()
.
- BoundField.name¶
Namnet på detta fält i formuläret:
>>> f = ContactForm() >>> print(f["subject"].name) subject >>> print(f["message"].name) message
- BoundField.template_name[source]¶
Namnet på den mall som återges med
BoundField.as_field_group()
.En egenskap som returnerar värdet av
template_name
om det är inställt på annat sättfield_template_name
.
- BoundField.use_fieldset[source]¶
Returnerar värdet på attributet
use_fieldset
för denna BoundField-widget.
- BoundField.widget_type[source]¶
Returnerar det gemena klassnamnet på det omslutna fältets widget, med eventuella efterföljande
input
ellerwidget
borttagna. Detta kan användas när man bygger formulär där layouten är beroende av widget-typen. Exempelvis:{% for field in form %} {% if field.widget_type == 'checkbox' %} # render one way {% else %} # render another way {% endif %} {% endfor %}
Metoder för BoundField
¶
- BoundField.as_field_group()¶
Renderar fältet med hjälp av
BoundField.render()
med standardvärden som renderarBoundField
, inklusive dess etikett, hjälptext och fel med hjälp av mallenstemplate_name
om den är inställd annarsfield_template_name
Returnerar en HTML-sträng för att representera detta som en
<input type="hidden">
.**kwargs
skickas tillas_widget()
.Denna metod används främst internt. Du bör använda en widget istället.
- BoundField.as_widget(widget=None, attrs=None, only_initial=False)[source]¶
Renderar fältet genom att rendera den widget som angetts och lägga till eventuella HTML-attribut som angetts som
attrs
. Om ingen widget anges kommer fältets standardwidget att användas.only_initial
används av Django internals och bör inte ställas in explicit.
- BoundField.css_classes(extra_classes=None)[source]¶
När du använder Djangos renderingsgenvägar används CSS-klasser för att ange obligatoriska formulärfält eller fält som innehåller fel. Om du manuellt renderar ett formulär kan du komma åt dessa CSS-klasser med hjälp av metoden
css_classes
:>>> f = ContactForm(data={"message": ""}) >>> f["message"].css_classes() 'required'
Om du vill tillhandahålla ytterligare klasser utöver de fel- och required-klasser som kan krävas, kan du ange dessa klasser som ett argument:
>>> f = ContactForm(data={"message": ""}) >>> f["message"].css_classes("foo bar") 'foo bar required'
- BoundField.get_context()[source]¶
Returnerar mallkontexten för rendering av fältet. Den tillgängliga kontexten är
field
som är instansen för det bundna fältet.
- BoundField.label_tag(contents=None, attrs=None, label_suffix=None, tag=None)[source]¶
Skapar en etikett för formulärfältet med hjälp av den mall som anges av
Form.template_name_label
.Den tillgängliga kontexten är:
field
: Denna instans avBoundField
.innehåll
: Som standard en konkatenerad sträng avBoundField.label
ochForm.label_suffix
(ellerField.label_suffix
, om inställt). Detta kan åsidosättas med argumentencontents
ochlabel_suffix
.attrs
: Endict
som innehållerfor
,Form.required_css_class
ochid
.id
genereras av fältets widgetattrs
ellerBoundField.auto_id
. Ytterligare attribut kan anges med argumentetattrs
.use_tag
: En boolean som ärTrue
om etiketten har ettid
. OmFalse
utelämnastaggen
i standardmallen.tag
: En valfri sträng för att anpassa taggen, standard ärlabel
.
Tips
I din mall är
field
en instans avBoundField
. Därför kommerfield.field
åtBoundField.field
som är det fält du deklarerar, t.ex.forms.CharField
.För att separat rendera etikett-taggen för ett formulärfält kan du anropa dess metod
label_tag()
:>>> f = ContactForm(data={"message": ""}) >>> print(f["message"].label_tag()) <label for="id_message">Message:</label>
Om du vill anpassa renderingen kan du göra det genom att åsidosätta attributet
Form.template_name_label
eller mer allmänt genom att åsidosätta standardmallen, se även Åsidosätta inbyggda formulärmallar.
- BoundField.legend_tag(contents=None, attrs=None, label_suffix=None)[source]¶
Anropar
label_tag()
medtag='legend'
för att rendera etiketten med<legend>
taggar. Detta är användbart vid rendering av radio och flera kryssrutor widgets där<legend>
kan vara mer lämpligt än en<label>
.
- BoundField.render(template_name=None, context=None, renderer=None)¶
Renderingsmetoden anropas av
as_field_group
. Alla argument är valfria och används som standard:template_name
:BoundField.template_name
kontext
: Värde som returneras avBoundField.get_context()
renderer
: Värde som returneras avForm.default_renderer
Genom att skicka
template_name
kan du anpassa den mall som används för bara ett enda anrop.
- BoundField.value()[source]¶
Använd den här metoden för att återge fältets råvärde så som det skulle återges av en
Widget
:>>> initial = {"subject": "welcome"} >>> unbound_form = ContactForm(initial=initial) >>> bound_form = ContactForm(data={"subject": "hi"}, initial=initial) >>> print(unbound_form["subject"].value()) welcome >>> print(bound_form["subject"].value()) hi
Anpassa BoundField
¶
- Form.bound_field_class¶
Definiera en anpassad BoundField
-klass som ska användas när formuläret renderas. Detta har företräde framför BaseRenderer.bound_field_class
på projektnivå (tillsammans med en anpassad FORM_RENDERER
), men kan åsidosättas av Field.bound_field_class
på fältnivå.
Om den inte definieras som en klassvariabel kan bound_field_class
ställas in via argumentet bound_field_class
i konstruktören Form
eller Field
.
Av kompatibilitetsskäl kan ett anpassat formulärfält fortfarande åsidosätta Field.get_bound_field()
för att använda en anpassad klass, även om något av de tidigare alternativen är att föredra.
Du kanske vill använda en anpassad BoundField
om du behöver komma åt ytterligare information om ett formulärfält i en mall och det inte räcker att använda en underklass av Field
.
Om du till exempel har en GPSCoordinatesField
och vill kunna få tillgång till ytterligare information om koordinaterna i en mall, kan detta implementeras enligt följande:
class GPSCoordinatesBoundField(BoundField):
@property
def country(self):
"""
Return the country the coordinates lie in or None if it can't be
determined.
"""
value = self.value()
if value:
return get_country_from_coordinates(value)
else:
return None
class GPSCoordinatesField(Field):
bound_field_class = GPSCoordinatesBoundField
Nu kan du få tillgång till landet i en mall med {{ form.coordinates.country }}
.
Du kanske också vill anpassa standardrenderingen av formulärfältsmallen. Du kan t.ex. åsidosätta BoundField.label_tag()
för att lägga till en anpassad klass:
class StyledLabelBoundField(BoundField):
def label_tag(self, contents=None, attrs=None, label_suffix=None, tag=None):
attrs = attrs or {}
attrs["class"] = "wide"
return super().label_tag(contents, attrs, label_suffix, tag)
class UserForm(forms.Form):
bound_field_class = StyledLabelBoundField
name = CharField()
Detta skulle uppdatera standardrenderingen av formuläret:
>>> f = UserForm()
>>> print(f["name"].label_tag)
<label for="id_name" class="wide">Name:</label>
För att lägga till en CSS-klass till det omslutande HTML-elementet för alla fält kan en BoundField
åsidosättas för att returnera en annan samling CSS-klasser:
class WrappedBoundField(BoundField):
def css_classes(self, extra_classes=None):
parent_css_classes = super().css_classes(extra_classes)
return f"field-class {parent_css_classes}".strip()
class UserForm(forms.Form):
bound_field_class = WrappedBoundField
name = CharField()
Detta skulle uppdatera formulärets rendering enligt följande:
>>> f = UserForm()
>>> print(f)
<div class="field-class"><label for="id_name">Name:</label><input type="text" name="name" required id="id_name"></div>
Alternativt, för att åsidosätta klassen BoundField
på projektnivå, kan BaseRenderer.bound_field_class
definieras på en anpassad FORM_RENDERER
:
mysite/renderers.py
¶from django.forms.renderers import DjangoTemplates
from .forms import CustomBoundField
class CustomRenderer(DjangoTemplates):
bound_field_class = CustomBoundField
`ettings.py`
¶FORM_RENDERER = "mysite.renderers.CustomRenderer"
Binder uppladdade filer till ett formulär¶
Att hantera formulär som har fälten FileField
och ImageField
är lite mer komplicerat än ett vanligt formulär.
För det första, för att ladda upp filer måste du se till att ditt <form>
element korrekt definierar enctype
som "multipart/form-data"
:
<form enctype="multipart/form-data" method="post" action="/foo/">
För det andra måste du binda filinformationen när du använder formuläret. Fildata hanteras separat från normal formulärdata, så när ditt formulär innehåller en FileField
och ImageField
måste du ange ett andra argument när du binder ditt formulär. Så om vi utökar vårt ContactForm så att det innehåller en ImageField
som heter mugshot
, måste vi binda de fildata som innehåller mugshot-bilden:
# Bound form with an image field
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... }
>>> file_data = {"mugshot": SimpleUploadedFile("face.jpg", b"file data")}
>>> f = ContactFormWithMugshot(data, file_data)
I praktiken anger du vanligtvis request.FILES
som källa för fildata (precis som du använder request.POST
som källa för formulärdata):
# Bound form with an image field, data from the request
>>> f = ContactFormWithMugshot(request.POST, request.FILES)
Att konstruera ett obundet formulär är samma sak som alltid - utelämna både formulärdata och fildata:
# Unbound form with an image field
>>> f = ContactFormWithMugshot()
Testning av formulär med flera delar¶
- Form.is_multipart()¶
Om du skriver återanvändbara vyer eller mallar kanske du inte vet i förväg om ditt formulär är ett flerdelat formulär eller inte. Metoden is_multipart()
talar om för dig om formuläret kräver multipart-kodning för inlämning:
>>> f = ContactFormWithMugshot()
>>> f.is_multipart()
True
Här är ett exempel på hur du kan använda detta i en mall:
{% if form.is_multipart %}
<form enctype="multipart/form-data" method="post" action="/foo/">
{% else %}
<form method="post" action="/foo/">
{% endif %}
{{ form }}
</form>
Underklassificering av formulär¶
Om du har flera Form
-klasser som delar fält kan du använda subklassning för att ta bort redundans.
När du subklassar en anpassad Form
-klass kommer den resulterande subklassen att innehålla alla fält i den eller de överordnade klasserna, följt av de fält som du definierar i subklassen.
I det här exemplet innehåller ContactFormWithPriority
alla fält från ContactForm
, plus ytterligare ett fält, priority
. Fälten i ContactForm
är ordnade först:
>>> class ContactFormWithPriority(ContactForm):
... priority = forms.CharField()
...
>>> f = ContactFormWithPriority(auto_id=False)
>>> print(f)
<div>Subject:<input type="text" name="subject" maxlength="100" required></div>
<div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
<div>Sender:<input type="email" name="sender" required></div>
<div>Cc myself:<input type="checkbox" name="cc_myself"></div>
<div>Priority:<input type="text" name="priority" required></div>
Det är möjligt att subklassa flera formulär och behandla formulär som mixins. I det här exemplet är BeatleForm
en underklass till både PersonForm
och InstrumentForm
(i den ordningen), och dess fältlista innehåller fälten från de överordnade klasserna:
>>> from django import forms
>>> class PersonForm(forms.Form):
... first_name = forms.CharField()
... last_name = forms.CharField()
...
>>> class InstrumentForm(forms.Form):
... instrument = forms.CharField()
...
>>> class BeatleForm(InstrumentForm, PersonForm):
... haircut_type = forms.CharField()
...
>>> b = BeatleForm(auto_id=False)
>>> print(b)
<div>First name:<input type="text" name="first_name" required></div>
<div>Last name:<input type="text" name="last_name" required></div>
<div>Instrument:<input type="text" name="instrument" required></div>
<div>Haircut type:<input type="text" name="haircut_type" required></div>
Det är möjligt att deklarativt ta bort ett Field
som ärvts från en överordnad klass genom att ställa in namnet på fältet till None
i underklassen. Ett exempel:
>>> from django import forms
>>> class ParentForm(forms.Form):
... name = forms.CharField()
... age = forms.IntegerField()
...
>>> class ChildForm(ParentForm):
... name = None
...
>>> list(ChildForm().fields)
['age']
Prefix för former¶
- Form.prefix¶
Du kan lägga in flera Django formulär i en <form>
tagg. För att ge varje Form
sitt eget namnområde, använd nyckelordsargumentet prefix
:
>>> mother = PersonForm(prefix="mother")
>>> father = PersonForm(prefix="father")
>>> print(mother)
<div><label for="id_mother-first_name">First name:</label><input type="text" name="mother-first_name" required id="id_mother-first_name"></div>
<div><label for="id_mother-last_name">Last name:</label><input type="text" name="mother-last_name" required id="id_mother-last_name"></div>
>>> print(father)
<div><label for="id_father-first_name">First name:</label><input type="text" name="father-first_name" required id="id_father-first_name"></div>
<div><label for="id_father-last_name">Last name:</label><input type="text" name="father-last_name" required id="id_father-last_name"></div>
Prefixet kan också anges på formulärklassen:
>>> class PersonForm(forms.Form):
... ...
... prefix = "person"
...