Django - ModelForm
一、原生form
https://www.cnblogs.com/yuanchenqi/articles/7614921.html
案例:
步骤:
1.models.py ...
makemigrations
migrate
from django.db import models # Create your models here. class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) # 999999.99 date = models.DateField() publish = models.ForeignKey("Publish",on_delete=models.CASCADE) authors = models.ManyToManyField("Author") def __str__(self): return self.title class Publish(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name
2.admin.py
from django.contrib import admin # Register your models here. from .models import * admin.site.register(Book) admin.site.register(Publish) admin.site.register(Author)
3.createsuperuser
yuan yuan1234
1.addbook:(getlist)
...
publish_id = request.POST.get('publish_id')
auhtor_pk_list = request.POST.getlist('auhtor_pk_list') # ['1', '2']
book_obj = Book.objects.create(title=title,price=price,date=date,publish_id=publish_id)
book_obj.authors.add(*auhtor_pk_list)
2.editbook:(set)
...
<p>价格 <input type="text" name="price" value="{{ edit_book.price }}"></p>
{% if author in edit_book.authors.all %}
<option selected value="{{ author.pk }}">{{ author.name }}</option>
{% else %}
<option value="{{ author.pk }}">{{ author.name }}</option>
{% endif %}
...
ret = Book.objects.filter(pk=edit_book_id).update(title=title, price=price, date=date, publish_id=publish_id)
print('ret---', ret) # 1
book_obj = Book.objects.filter(pk=edit_book_id).first()
print('book_obj---', book_obj) # 对象
book_obj.authors.set(auhtor_pk_list)
4.code
from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('books/', views.books), path('book/add/', views.addbook), re_path('book/edit/(\d+)', views.editbook), ]
from django.shortcuts import render,HttpResponse,redirect # Create your views here. from .models import * def books(request): book_list = Book.objects.all() return render(request,'books.html',locals()) def addbook(request): if request.method == 'POST': title = request.POST.get('title') price = request.POST.get('price') date = request.POST.get('date') publish_id = request.POST.get('publish_id') auhtor_pk_list = request.POST.getlist('auhtor_pk_list') # ['1', '2'] print(auhtor_pk_list) book_obj = Book.objects.create(title=title,price=price,date=date,publish_id=publish_id) book_obj.authors.add(*auhtor_pk_list) return redirect('/books/') publish_list = Publish.objects.all() author_list= Author.objects.all() return render(request,'add.html',locals()) def editbook(request, edit_book_id): if request.method == 'POST': title = request.POST.get('title') price = request.POST.get('price') date = request.POST.get('date') publish_id = request.POST.get('publish_id') auhtor_pk_list = request.POST.getlist('auhtor_pk_list') # ['1', '2'] print(auhtor_pk_list) ret = Book.objects.filter(pk=edit_book_id).update(title=title, price=price, date=date, publish_id=publish_id) print('ret---', ret) # 1 book_obj = Book.objects.filter(pk=edit_book_id).first() print('book_obj---', book_obj) # 对象 book_obj.authors.set(auhtor_pk_list) return redirect('/books/') edit_book = Book.objects.filter(pk=edit_book_id).first() publish_list = Publish.objects.all() author_list = Author.objects.all() return render(request, 'edit.html', locals())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>books</title> </head> <body> <a href="/book/add/"><button>添加书籍</button></a> <hr> <table border="1"> {% for book in book_list %} <tr> <td>{{ book.title }}</td> <td>{{ book.price }}</td> <td>{{ book.date|date:'Y-m-d' }}</td> <td>{{ book.publish.name}}</td> <td> {% for author in book.authors.all %} {{ author.name }} {% endfor %} </td> <td><a href="/book/edit/{{ book.pk }}">编辑</a></td> </tr> {% endfor %} </table> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>添加页面</h3> <form action="" method="post"> {% csrf_token %} <p>书籍名称 <input type="text" name="title"></p> <p>价格 <input type="text" name="price"></p> <p>日期 <input type="date" name="date"></p> <p>出版社 <select name="publish_id" id=""> {% for publish in publish_list %} <option value="{{ publish.pk }}">{{ publish.name }}</option> {% endfor %} </select> </p> <p>作者 <select name="auhtor_pk_list" id="" multiple> {% for author in author_list %} <option value="{{ author.pk }}">{{ author.name }}</option> {% endfor %} </select> </p> <input type="submit"> </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>编辑页面</h3> <form action="" method="post"> {% csrf_token %} <p>书籍名称 <input type="text" name="title" value="{{ edit_book.title}}"></p> <p>价格 <input type="text" name="price" value="{{ edit_book.price }}"></p> <p>日期 <input type="date" name="date" value="{{ edit_book.date|date:'Y-m-d' }}"></p> <p>出版社 <select name="publish_id" id=""> {% for publish in publish_list %} {% if edit_book.publish == publish %} <option selected value="{{ publish.pk }}">{{ publish.name }}</option> {% else %} <option value="{{ publish.pk }}">{{ publish.name }}</option> {% endif %} {% endfor %} </select> </p> <p>作者 <select name="auhtor_pk_list" id="" multiple> {% for author in author_list %} {% if author in edit_book.authors.all %} <option selected value="{{ author.pk }}">{{ author.name }}</option> {% else %} <option value="{{ author.pk }}">{{ author.name }}</option> {% endif %} {% endfor %} </select> </p> <input type="submit"> </form> </body> </html>
二、form组件
https://www.cnblogs.com/yuanchenqi/articles/7614921.html
https://www.cnblogs.com/wupeiqi/articles/6144178.html
针对form表单设计form组件
ChoiceField(Field)
ModelChoiceField(ChoiceField)
ModelMultipleChoiceField(ModelChoiceField)
添加,编辑,用form组件!
from django import forms
from django.forms import widgets
class BookForm(forms.Form):
title = forms.CharField(max_length=32,label='书籍名称',
error_messages={'required':'不能为空'},
)
price = forms.DecimalField(max_digits=8,decimal_places=2,label='价格')
date = forms.DateField(label='日期',
widget=widgets.TextInput(attrs={'type':'date'})
)
# gender = forms.ChoiceField(choices=((1,'男'),(2,'女'),(3,'其他'))) # 与sql没关系
# publish = forms.ChoiceField(choices=Publish.objects.all().values_list('pk','name'))
publish = forms.ModelChoiceField(queryset=Publish.objects.all(),label='出版社')
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all(),label='作者')
注意点:
1.
book_obj = Book.objects.create(title=title,price=price,date=date,publish=publish)
book_obj.authors.add(*authors)
2.
edit_book = Book.objects.filter(pk=edit_book_id).first()
form = BookForm(initial={"title":edit_book.title,"price":edit_book.price,
"date":edit_book.date,"publish":edit_book.publish,
'authors':edit_book.authors.all()})
3.
Book.objects.filter(pk=edit_book_id).update(title=title, price=price, date=date, publish=publish)
book_obj = Book.objects.filter(pk=edit_book_id).first()
book_obj.authors.set(authors)
4.
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div>
{{ field.label }}
{{ field }}
{{ field.errors.0 }}
</div>
{% endfor %}
<input type="submit">
</form>
form组件能做的事情:
1.能渲染页面
2.能做校验用
3.拿到错误信息显示
from django.shortcuts import render,HttpResponse,redirect # Create your views here. from .models import * from django import forms from django.forms import widgets class BookForm(forms.Form): title = forms.CharField(max_length=32,label='书籍名称', error_messages={'required':'不能为空'}, ) price = forms.DecimalField(max_digits=8,decimal_places=2,label='价格') date = forms.DateField(label='日期', widget=widgets.TextInput(attrs={'type':'date'}) ) # gender = forms.ChoiceField(choices=((1,'男'),(2,'女'),(3,'其他'))) # publish = forms.ChoiceField(choices=Publish.objects.all().values_list('pk','name')) publish = forms.ModelChoiceField(queryset=Publish.objects.all(),label='出版社') authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all(),label='作者') def books(request): book_list = Book.objects.all() return render(request,'books.html',locals()) def addbook(request): form = BookForm() if request.method == 'POST': form = BookForm(request.POST) if form.is_valid(): print(form.cleaned_data) """ clean_date: {'title': '书1', 'price': Decimal('1111'), 'date': datetime.date(2018, 6, 7), 'publish': <Publish: 香蕉出版社>, # 对象 'authors': <QuerySet [<Author: alex>, <Author: egon>]>} """ title = form.cleaned_data.get('title') price = form.cleaned_data.get('price') date = form.cleaned_data.get('date') publish = form.cleaned_data.get('publish') authors = form.cleaned_data.get('authors') book_obj = Book.objects.create(title=title,price=price,date=date,publish=publish) book_obj.authors.add(*authors) return redirect('/books/') return render(request,'add.html',locals()) def editbook(request, edit_book_id): edit_book = Book.objects.filter(pk=edit_book_id).first() form = BookForm(initial={"title":edit_book.title,"price":edit_book.price, "date":edit_book.date,"publish":edit_book.publish, 'authors':edit_book.authors.all()}) if request.method == 'POST': form = BookForm(request.POST) if form.is_valid(): title = form.cleaned_data.get('title') price = form.cleaned_data.get('price') date = form.cleaned_data.get('date') publish = form.cleaned_data.get('publish') authors = form.cleaned_data.get('authors') Book.objects.filter(pk=edit_book_id).update(title=title, price=price, date=date, publish=publish) book_obj = Book.objects.filter(pk=edit_book_id).first() book_obj.authors.set(authors) return redirect('/books/') return render(request, 'edit.html', locals())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>添加页面</h3> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div> {{ field.label }} {{ field }} {{ field.errors.0 }} </div> {% endfor %} <input type="submit"> </form> </body> </html> ------------------------------------- <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>编辑页面</h3> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div> {{ field.label }} {{ field }} {{ field.errors.0 }} </div> {% endfor %} <input type="submit"> </form> </body> </html>
三、modelform
https://www.cnblogs.com/yuanchenqi/articles/7614921.html
https://www.cnblogs.com/yuanchenqi/articles/8034442.html
注意点:
1.modelform 组件
中间转换的组件, 不用自己去写form组件。
将模型表转换成, 具体的form组件。
2.fields
class BookForm(ModelForm):
class Meta:
model = Book
fields = "__all__" # 对所有字段转换
# fields = ['title','price']
3.一对多,多对多,不用考虑!
form = BookForm(request.POST)
if form.is_valid():
form.save()
return redirect('/books/')
4.BookForm(instance=edit_book) # 接收一个对象
form = BookForm(request.POST,instance=edit_book)
if form.is_valid():
form.save()
return redirect('/books/')
5.create、update
form = BookForm(request.POST) # create
if form.is_valid():
form.save() # form.model.objects.create(request.POST)
form = BookForm(request.POST,instance=edit_book) # update
if form.is_valid():
form.save() # edit_book.update(request.POST)
6.{% include 'form.html' %}
form.html:
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
{{ field.label }}
{{ field }}
<small><span class="pull-right text-danger has-error">{{ field.errors.0 }}</span></small>
</div>
{% endfor %}
<input type="submit">
</form>
7.models.py
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2) # 999999.99
date = models.DateField()
publish = models.ForeignKey("Publish",on_delete=models.CASCADE)
authors = models.ManyToManyField("Author")
models.CharFiled()
models.EmailField() # 为什么,不写charField? 因为在使用 modelForm 时,可以校验!!这时EmailField才有意义!
eg:
models.URLField
models.UUIDField
views.py
from django.shortcuts import render,HttpResponse,redirect # Create your views here. from .models import * from django.forms import ModelForm from django.forms import widgets as wid # 因为重名,所以起个别名! wid_text = wid.TextInput(attrs={'class':'form-control'}) required_msg = {'required':'不能为空'} class BookForm(ModelForm): class Meta: model = Book fields = "__all__" # 对所有字段转换 # fields = ['title','price'] labels = {"title":"书籍名称","price":"价格","date":"日期","publish":"出版社","authors":"作者"} widgets = { 'title':wid_text, 'price':wid_text, 'date':wid.TextInput(attrs={'class':'form-control','type':'date'}), 'publish':wid.Select(attrs={'class':'form-control'}), 'authors':wid.SelectMultiple(attrs={'class':'form-control'}) } error_messages = { 'title':required_msg, 'price':required_msg, 'date':{'required':'不能为空','invalid':'格式错误'}, 'publish':required_msg, 'authors':required_msg, } def books(request): book_list = Book.objects.all() return render(request,'books.html',locals()) def addbook(request): form = BookForm() if request.method == 'POST': form = BookForm(request.POST) if form.is_valid(): form.save() # form.model.objects.create(request.POST) return redirect('/books/') return render(request,'add.html',locals()) def editbook(request, edit_book_id): edit_book = Book.objects.filter(pk=edit_book_id).first() form = BookForm(instance=edit_book) if request.method == 'POST': form = BookForm(request.POST,instance=edit_book) if form.is_valid(): form.save() # edit_book.update(request.POST) return redirect('/books/') return render(request, 'edit.html', locals())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <h3>添加页面</h3> <div class="row"> <div class="col-md-4 col-md-offset-1"> {% include 'form.html' %} </div> </div> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <h3>编辑页面</h3> <div class="row"> <div class="col-md-4 col-md-offset-1"> {% include 'form.html' %} </div> </div> </body> </html>
form.html
<form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div class="form-group"> {{ field.label }} {{ field }} <small><span class="pull-right text-danger has-error">{{ field.errors.0 }}</span></small> </div> {% endfor %} <input type="submit"> </form>
from django.shortcuts import render,HttpResponse,redirect from django.forms import ModelForm # Create your views here. from app01 import models def test(request): # model_form = models.Student model_form = models.Student.objects.all() return render(request,'test.html',{'model_form':model_form}) class StudentList(ModelForm): class Meta: model = models.Student #对应的Model中的类 fields = "__all__" #字段,如果是__all__,就是表示列出所有的字段 exclude = None #排除的字段 labels = None #提示信息 help_texts = None #帮助提示信息 widgets = None #自定义插件 error_messages = None #自定义错误信息 #error_messages用法: error_messages = { 'name':{'required':"用户名不能为空",}, 'age':{'required':"年龄不能为空",}, } #widgets用法,比如把输入用户名的input框给为Textarea #首先得导入模块 from django.forms import widgets as wid #因为重名,所以起个别名 widgets = { "name":wid.Textarea } #labels,自定义在前端显示的名字 labels= { "name":"用户名" } def student(request): if request.method == 'GET': student_list = StudentList() return render(request,'student.html',{'student_list':student_list}) else: student_list = StudentList(request.POST) if student_list.is_valid(): student_list.save() return render(request,'student.html',{'student_list':student_list}) def student_edit(request,pk): obj = models.Student.objects.filter(pk=pk).first() if not obj: return redirect('test') if request.method == "GET": student_list = StudentList(instance=obj) return render(request,'student_edit.html',{'student_list':student_list}) else: student_list = StudentList(request.POST,instance=obj) if student_list.is_valid(): student_list.save() return render(request,'student_edit.html',{'student_list':student_list})
https://www.cnblogs.com/yuanchenqi/articles/8034442.html
四、前端form表单,后台form组件
前端手写一个form表单,后台使用form组件,进行校验,也是可以的!!
注意: <p>名称 <input type="text" name="title"></p> 和 title = forms.CharField()
views.py
from django import forms class BookForms(forms.Form): title = forms.CharField() price = forms.FloatField() def addbook(request): form = BookForms() if request.method == 'POST': form = BookForms(request.POST) # form = BookForm({'title':'php','price':111,'xxx':'egon'}) if form.is_valid(): print('clean_data',form.cleaned_data) # clean_data {'title': '水浒传', 'price': 123.0} else: print('error',form.errors) return render(request,'addbook.html',locals())
addbook.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>添加书籍</h3> <form action="" method="post" novalidate> {% csrf_token %} <p>名称 <input type="text" name="title"></p> <p>价格 <input type="text" name="price"></p> <p>xxx <input type="text" name="xxx"></p> <input type="submit"> </form> <form action="" method="post" novalidate> {% csrf_token %} {{ form.as_p }} {{ form.as_table }} {{ form.as_ul }} <input type="submit"> </form> </body> </html>
五、补充 - 请求流程
说明:
django 请求流程图--流程最重要!
http协议
请求协议:请求首行,请求头,请求体!
响应协议: 响应首行,响应头,响应体!
我们发给浏览器的响应体(html)是一堆 str 浏览器解析(html)才能看到数据!
render 对templates 模板渲染!
没有模板 就 httpresponse 返回str
打开文件 捕获是否模板语法,嵌入{{}} 数据 返回 html(str) response
只要到了 中间件 交给浏览器的 一定已经是一些 html(str)