Python Django Queries ModelForm
▌Introduction
We will make a
create form with ModelForm and post the form to view and save the data into
database.
▋Related articles
▌Environment
▋Python 3.6.2
▋Django 1.8.18
▌Implement
▋Url Pattern
▋urls.py
from app.views import home, productList, productCreate,
productEdit, productRemove
urlpatterns =
[
url(r'^$', home, name='home'),
url(r'^product/(?P<prodtype>\w+)/$', productList, name='productList'),
url(r'^product/create$', productCreate, name='productCreate'),
url(r'^admin/', admin.site.urls),
]
▋ModelForm
Create
productForm.py in your app.
▋productForm.py
from django import forms
from app.models import ProductType, Product
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ['Id', 'ProdType', 'Title' , 'Price']
# exclude =
['Id']
l The ModelForm
class must inherits forms.ModelForm.
l In inner
class: Meta, we have to set
n model: The target
Model
n fields: Included
fields
n exclude: Excluded
fields, optional
The fields will default use the field declaration from
Model: Product,
in models.py.
▋models.py (No need to modify it)
from django.db import models
class Product(models.Model):
Id = models.AutoField(primary_key=True)
Price = models.IntegerField(null=False)
Title = models.CharField(max_length=100, null=False)
ProdType = models.ForeignKey('ProductType', db_column='ProdType', related_name='Products_ProductTypes')
# ...
However, Product.ProdType is a foreign key and we
would like to take Product.ProdType as ModelChoiceField with options
from ProductType.
So we specify the ProdType field like
following, and that we will get this field’s queryset in the form.
from django import forms
from app.models import ProductType, Product
class ProductForm(forms.ModelForm):
ProdType=forms.ModelChoiceField(queryset=ProductType.objects.all(),required=True)
class Meta:
model = Product
fields = ['Id', 'ProdType', 'Title' , 'Price']
# exclude = ['Id']
▋View
We will have two situations in our product-create view.
1. HttpGet:
Create an empty ProductForm instance and place it into the template context for rendering.
Create an empty ProductForm instance and place it into the template context for rendering.
2. HttpPost:
Validate the form data and save it if ok, then redirect to product list page.
Validate the form data and save it if ok, then redirect to product list page.
▋views.py
from django.shortcuts import render
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from app.models import Product
from share.enum import ProductTypeEnum
from app.forms.productForm import ProductForm
#region Product: Create
def productCreate(request):
# create a form instance and populate it with data from the request:
form = ProductForm(request.POST or None)
if request.method == 'POST':
# check whether it's valid:
if form.is_valid():
entity = form.save(commit=False)
entity.save()
prodtypeStr = str(form.cleaned_data["ProdType"].Name.lower())
prodtypeEnum = ProductTypeEnum[prodtypeStr]
return HttpResponseRedirect(reverse('productList', args=[prodtypeEnum.name.lower()]))
else:
pass
else:
form = ProductForm()
return render(request, 'product-create.html', {'form': form})
#endregion
n Notice that form.cleaned_data["ProdType"] will return a ProductType object since Product.ProdType is a foreign key.
return HttpResponseRedirect(reverse('url name', args=['XXXX']))
|
▋Template
▋product-create.html
Remember our expected form layout? Let’s write the
html for it.
<form method="post" autocomplete="off">
<div class="form-group">
<lable for="ProdType"></lable>
<select id="ProdType" name="ProdType" class="custom-select
mb-2 mr-sm-2 mb-sm-0">
<option value="1" selected>Book</option>
<option value="2">Clothes</option>
<option value="3">Toy</option>
</select>
</div>
<div class="form-group">
<label for="Title">Title</label>
<input type="text" id="Title" name="Title" class="form-control">
</div>
<div class="form-group">
<label for="Price">Price</label>
<input type="number" id="Price" name="Price" class="form-control">
</div>
<input type="submit" class="form-control" value="Save" />
</form>
Now modify the ProdType html: <select
id="ProdType"></select>
with ProductForm’s field.
<div class="form-group">
<lable for="ProdType"></lable>
<select id="ProdType" name="ProdType" class="custom-select
mb-2 mr-sm-2 mb-sm-0">
{% for prodtype in
form.ProdType.field.queryset %}
<option value="{{ prodtype.Id }}">{{ prodtype.Name }}</option>
{% endfor %}
</select>
</div>
<form method="post" autocomplete="off">{% csrf_token %}
</form>
Finally add the validation-fail message from backend
and here is the completed version.
{% extends
"base.html" %}
{% block
header %}Product-create{% endblock %}
{% block
content %}
<form method="post" autocomplete="off">{% csrf_token
%}
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ field.name
}}: {{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% endif %}
<div class="form-group">
<lable for="ProdType"></lable>
<select id="ProdType" name="ProdType" class="custom-select
mb-2 mr-sm-2 mb-sm-0">
{% for prodtype in
form.ProdType.field.queryset %}
<option value="{{ prodtype.Id }}">{{ prodtype.Name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="Title">Title</label>
<input type="text" id="Title" name="Title" class="form-control">
</div>
<div class="form-group">
<label for="Price">Price</label>
<input type="number" id="Price" name="Price" class="form-control">
</div>
<input type="submit" class="form-control" value="Save" />
</form>
{% endblock %}
▋Update Product List
template
Don’t forget to update the link in product-list.html.
▋product-list.html (Only show the modified html)
<input type="button" class="btn btn-success" value="Create"
onclick="location.href='{% url 'productCreate' %}'" />
▌Demo
▌Reference
沒有留言:
張貼留言