Django
vormen
Zoeken…
ModelForm Voorbeeld
Maak een ModelForm van een bestaande ModelForm
, door ModelForm
:
from django import forms
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['item', 'order_date', 'customer', 'status']
Een Django-formulier helemaal opnieuw definiëren (met widgets)
Formulieren kunnen op een vergelijkbare manier als modellen worden gedefinieerd door django.forms.Form
.
Verschillende CharField
zijn beschikbaar zoals CharField
, URLField
, IntegerField
, etc.
Het definiëren van een eenvoudig contactformulier is hieronder te zien:
from django import forms
class ContactForm(forms.Form):
contact_name = forms.CharField(
label="Your name", required=True,
widget=forms.TextInput(attrs={'class': 'form-control'}))
contact_email = forms.EmailField(
label="Your Email Address", required=True,
widget=forms.TextInput(attrs={'class': 'form-control'}))
content = forms.CharField(
label="Your Message", required=True,
widget=forms.Textarea(attrs={'class': 'form-control'}))
Widget is de weergave van Django van HTML-tags voor gebruikersinvoer en kan worden gebruikt om aangepaste HTML voor formuliervelden weer te geven (bijvoorbeeld: hier wordt een tekstvak weergegeven voor de inhoudinvoer)
attrs
zijn attributen die als zodanig naar de gerenderde html voor het formulier worden gekopieerd.
Bijv .: content.render("name", "Your Name")
geeft
<input title="Your name" type="text" name="name" value="Your Name" class="form-control" />
Het veld op basis van voorwaarde van een modelformulier verwijderen uit views.py
Als we een model hebben als volgt,
from django.db import models
from django.contrib.auth.models import User
class UserModuleProfile(models.Model):
user = models.OneToOneField(User)
expired = models.DateTimeField()
admin = models.BooleanField(default=False)
employee_id = models.CharField(max_length=50)
organisation_name = models.ForeignKey('Organizations', on_delete=models.PROTECT)
country = models.CharField(max_length=100)
position = models.CharField(max_length=100)
def __str__(self):
return self.user
En een modelformulier dat dit model als volgt gebruikt,
from .models import UserModuleProfile, from django.contrib.auth.models import User
from django import forms
class UserProfileForm(forms.ModelForm):
admin = forms.BooleanField(label="Make this User Admin",widget=forms.CheckboxInput(),required=False)
employee_id = forms.CharField(label="Employee Id ")
organisation_name = forms.ModelChoiceField(label='Organisation Name',required=True,queryset=Organizations.objects.all(),empty_label="Select an Organization")
country = forms.CharField(label="Country")
position = forms.CharField(label="Position")
class Meta:
model = UserModuleProfile
fields = ('admin','employee_id','organisation_name','country','position',)
def __init__(self, *args, **kwargs):
admin_check = kwargs.pop('admin_check', False)
super(UserProfileForm, self).__init__(*args, **kwargs)
if not admin_check:
del self.fields['admin']
Merk op dat ik onder de Meta-klasse in formulier een init- functie heb toegevoegd die we kunnen gebruiken tijdens het initialiseren van het formulier vanuit views.py om een formulierveld (of enkele andere acties) te verwijderen. Ik zal dit later uitleggen.
Dit formulier kan dus worden gebruikt voor gebruikersregistratiedoeleinden en we willen alle velden die zijn gedefinieerd in de Meta-klasse van het formulier. Maar wat als we hetzelfde formulier willen gebruiken wanneer we de gebruiker bewerken, maar als we dat niet doen, willen we het admin-veld van het formulier niet weergeven?
We kunnen eenvoudig een extra argument verzenden wanneer we het formulier initialiseren op basis van enige logica en het admin-veld uit de backend verwijderen.
def edit_profile(request,user_id):
context = RequestContext(request)
user = get_object_or_404(User, id=user_id)
profile = get_object_or_404(UserModuleProfile, user_id=user_id)
admin_check = False
if request.user.is_superuser:
admin_check = True
# If it's a HTTP POST, we're interested in processing form data.
if request.method == 'POST':
# Attempt to grab information from the raw form information.
profile_form = UserProfileForm(data=request.POST,instance=profile,admin_check=admin_check)
# If the form is valid...
if profile_form.is_valid():
form_bool = request.POST.get("admin", "xxx")
if form_bool == "xxx":
form_bool_value = False
else:
form_bool_value = True
profile = profile_form.save(commit=False)
profile.user = user
profile.admin = form_bool_value
profile.save()
edited = True
else:
print profile_form.errors
# Not a HTTP POST, so we render our form using ModelForm instance.
# These forms will be blank, ready for user input.
else:
profile_form = UserProfileForm(instance = profile,admin_check=admin_check)
return render_to_response(
'usermodule/edit_user.html',
{'id':user_id, 'profile_form': profile_form, 'edited': edited, 'user':user},
context)
Zoals u kunt zien, heb ik hier een eenvoudig bewerkingsvoorbeeld getoond met behulp van het formulier dat we eerder hebben gemaakt. Merk op dat ik bij het initialiseren van het formulier een extra variabele admin_check
heb doorgegeven die True
of False
.
profile_form = UserProfileForm(instance = profile,admin_check=admin_check)
Als je nu het formulier opmerkt dat we eerder schreven, kun je zien dat we in de init proberen de admin_check
parameter te vangen die we hier doorgeven. Als de waarde False is, verwijderen we eenvoudigweg het admin
veld uit het formulier en gebruiken we het. En aangezien dit een modelformulier admin veld kon niet null in het model zijn, controleren we eenvoudig of het formulier post admin veld in het formulier post had, zo niet stellen we het in op de False
in de view code in de volgende code van de view.
form_bool = request.POST.get("admin", "xxx")
if form_bool == "xxx":
form_bool_value = False
else:
form_bool_value = True
Bestandsuploads met Django-formulieren
Allereerst moeten we MEDIA_ROOT
en MEDIA_URL
aan ons bestand settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
Ook hier werkt u met ImageField
, dus onthoud in dergelijke gevallen dat u Pillow-bibliotheek pip install pillow
( pip install pillow
). Anders heb je een dergelijke fout:
ImportError: No module named PIL
Pillow is een vork van PIL, de Python Imaging Library, die niet langer wordt onderhouden. Kussen is achterwaarts compatibel met PIL.
Django wordt geleverd met twee formuliervelden om bestanden naar de server te uploaden, FileField
en ImageField
, het volgende is een voorbeeld van het gebruik van deze twee velden in ons formulier
forms.py:
from django import forms
class UploadDocumentForm(forms.Form):
file = forms.FileField()
image = forms.ImageField()
views.py:
from django.shortcuts import render
from .forms import UploadDocumentForm
def upload_doc(request):
form = UploadDocumentForm()
if request.method == 'POST':
form = UploadDocumentForm(request.POST, request.FILES) # Do not forget to add: request.FILES
if form.is_valid():
# Do something with our files or simply save them
# if saved, our files would be located in media/ folder under the project's base folder
form.save()
return render(request, 'upload_doc.html', locals())
upload_doc.html:
<html>
<head>File Uploads</head>
<body>
<form enctype="multipart/form-data" action="" method="post"> <!-- Do not forget to add: enctype="multipart/form-data" -->
{% csrf_token %}
{{ form }}
<input type="submit" value="Save">
</form>
</body>
</html>
Validatie van velden en vastleggen op model (e-mail van gebruiker wijzigen)
Er zijn al formulieren in Django geïmplementeerd om het gebruikerswachtwoord te wijzigen, een voorbeeld is SetPasswordForm .
Er zijn echter geen formulieren om de e-mail van de gebruiker te wijzigen en ik denk dat het volgende voorbeeld belangrijk is om te begrijpen hoe u een formulier correct gebruikt.
In het volgende voorbeeld worden de volgende controles uitgevoerd:
- E-mail is namelijk veranderd - erg handig als u de e-mail moet valideren of de e-mailchimp moet bijwerken;
- Zowel e-mail als bevestigings-e-mail zijn hetzelfde - het formulier heeft twee velden voor e-mail, dus de update is minder foutgevoelig.
En uiteindelijk slaat het de nieuwe e-mail op in het gebruikersobject (werkt de e-mail van de gebruiker bij). Merk op dat de methode __init__()
een gebruikersobject vereist.
class EmailChangeForm(forms.Form):
"""
A form that lets a user change set their email while checking for a change in the
e-mail.
"""
error_messages = {
'email_mismatch': _("The two email addresses fields didn't match."),
'not_changed': _("The email address is the same as the one already defined."),
}
new_email1 = forms.EmailField(
label=_("New email address"),
widget=forms.EmailInput,
)
new_email2 = forms.EmailField(
label=_("New email address confirmation"),
widget=forms.EmailInput,
)
def __init__(self, user, *args, **kwargs):
self.user = user
super(EmailChangeForm, self).__init__(*args, **kwargs)
def clean_new_email1(self):
old_email = self.user.email
new_email1 = self.cleaned_data.get('new_email1')
if new_email1 and old_email:
if new_email1 == old_email:
raise forms.ValidationError(
self.error_messages['not_changed'],
code='not_changed',
)
return new_email1
def clean_new_email2(self):
new_email1 = self.cleaned_data.get('new_email1')
new_email2 = self.cleaned_data.get('new_email2')
if new_email1 and new_email2:
if new_email1 != new_email2:
raise forms.ValidationError(
self.error_messages['email_mismatch'],
code='email_mismatch',
)
return new_email2
def save(self, commit=True):
email = self.cleaned_data["new_email1"]
self.user.email = email
if commit:
self.user.save()
return self.user
def email_change(request):
form = EmailChangeForm()
if request.method=='POST':
form = Email_Change_Form(user,request.POST)
if form.is_valid():
if request.user.is_authenticated:
if form.cleaned_data['email1'] == form.cleaned_data['email2']:
user = request.user
u = User.objects.get(username=user)
# get the proper user
u.email = form.cleaned_data['email1']
u.save()
return HttpResponseRedirect("/accounts/profile/")
else:
return render_to_response("email_change.html", {'form':form},
context_instance=RequestContext(request))