Django10.1: ModelForm组件
用上次的图书管理系统作为示例,来了解一下ModelForm
数据库类型如下
# 作者表 class Author(models.Model): # 比较常用的信息放到这个表里面 name = models.CharField(max_length=32) age = models.IntegerField() # authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE) # 一对一到AuthorDetail表 生成为表字段之后,会自动变为authorDetail_id这样有一个名称 authorDetail = models.OneToOneField(to='AuthorDetail') # 外键字段 -- 外键字段名_id # foreign+unique def __str__(self): return self.name # 作者详细信息表 class AuthorDetail(models.Model): birthday = models.DateField() # telephone=models.BigIntegerField() telephone = models.CharField(max_length=32) addr = models.CharField(max_length=64) def __str__(self): return self.addr # 出版社表 和 书籍表 是 一对多的关系 class Publish(models.Model): name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() # charfield -- asdfasdf def __str__(self): return self.name # 书籍表 class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) # good = models.IntegerField(default=1) # 点赞数 # comment = models.IntegerField(default=1) # 评论数 publishDate = models.DateField() price = models.DecimalField( max_digits=5, decimal_places=2) # decimal(16,2) publishs = models.ForeignKey(to="Publish") authors = models.ManyToManyField(to='Author',) def __str__(self): return self.title
ModelForm
ModelForm本质是将查到的数据模型字段自动转换为Form类型,来看看示例吧
# ModelForm通过查询models类自动将所有字段转换为form class BookModelForm(forms.ModelForm): class Meta: model = models.Book fields = "__all__" # all 是所有字段 也可以指定字段 # fields = ['title',] def addbooks(request): if request.method == 'GET': book_modelform_obj = BookModelForm() return render(request, 'add_book.html', { 'book_modelform_obj': book_modelform_obj, })
<div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <form action="" method="post" novalidate> {% csrf_token %} {% for book_modelform in book_modelform_obj %} <div class="form-group"> <label for="{{ book_modelform.id_for_label }}">{{ book_modelform.label }}</label> {{ book_modelform }} <span style="color: crimson;font-size: 12px;">{{ book_modelform.errors.0 }}</span> </div> {% endfor %} <button class="btn btn-success pull-right">提交</button> </form> </div> </div> </div>

为modelForm添加样式
class BookModelForm(forms.ModelForm): class Meta: model = models.Book fields = "__all__" # modelForm本质和Form相同 添加样式的方法也相同 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for field in self.fields.values(): field.widget.attrs.update( {"class": "form-control"})

问题:字段名是英文的 出版信息时间类型不对 需要自定义字段名和属性
class BookModelForm(forms.ModelForm): class Meta: model = models.Book fields = "__all__" # 为数据库字段在前端生成自定义标题 labels = { "title":"标题", "publishDate":"出版日期", "price":"价格", "publishs":"出版社", "authors":"作者",} # 为前端字段添加自定义属性 widgets = { "publishDate":forms.widgets.TextInput(attrs={"type":"date"}), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for field in self.fields.values(): field.widget.attrs.update({"class": "form-control"})

前端生成已经解决,下来我们来看一下字段校验吧
# ModelForm通过查询models类自动将所有字段转换为form class BookModelForm(forms.ModelForm): class Meta: model = models.Book fields = "__all__" # 为数据库字段在前端生成自定义标题 labels = { "title":"标题", "publishDate":"出版日期", "price":"价格", "publishs":"出版社", "authors":"作者",} # 为前端字段添加自定义属性 widgets = { "publishDate":forms.widgets.TextInput(attrs={"type":"date"}), } # 自定义错误信息 error_messages = { "title":{"required":"不能为空",}, "publishDate":{"required":"不能为空",}, } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for field in self.fields.values(): field.widget.attrs.update({"class": "form-control"}) def addbooks(request): if request.method == 'GET': book_modelform_obj = BookModelForm() return render(request, 'add_book.html', { 'book_modelform_obj': book_modelform_obj, }) if request.method == 'POST': book_modelform_obj = BookModelForm(request.POST) if book_modelform_obj.is_valid(): # authors = book_modelform_obj.cleaned_data.pop("authors") # new_book = models.Book.objects.create( # **book_modelform_obj.cleaned_data) # new_book.authors.add(*authors) book_modelform_obj.save() # save() modelform提供的一个保存方法 return redirect('showbooks') else: return render(request, 'add_book.html', { 'book_modelform_obj': book_modelform_obj, })

自定义字段
- modelForm是将model类中的字段转化为Form 但是 约束不够 比如不能设置最小值约束
- 这个时候我们可以自定义字段
- 自定义字段会顶替掉model中转换的字段 所以我们需要给自定字段中手动添加各种功能
- 示例:
class BookModelForm(forms.ModelForm): title = forms.CharField( label="书名", max_length=32, min_length=18, error_messages={ "required": "不能为空", "min_length":"最小18位" }) class Meta: model = models.Book fields = "__all__"
model的修改字段
- 添加字段做到了生成字段和校验字段 修改书籍modelform也可以做到
def editbooks(request, book_id): book_obj = models.Book.objects.filter(pk=book_id) book_obj=book_obj.first() if request.method == 'GET': # 在BookModelForm中加入instance=XXX # 会给前端生成的字段中生成value book_modelform_obj = BookModelForm(instance=book_obj) return render(request, 'add_book.html', { "book_modelform_obj": book_modelform_obj, }) else: # 在BookModelForm(request.POST)中加入instance=book_obj时 # save 是 updata 操作 # 如果不添加 save 是 create 操作 book_modelform_obj = BookModelForm(request.POST,instance=book_obj) if book_modelform_obj.is_valid(): book_modelform_obj.save() return redirect('showbooks') else: return render(request, 'add_book.html', { 'book_modelform_obj': book_modelform_obj, })

ModelForm到这里就结束了 我们看一下整体的代码吧
数据库依旧是上面的数据
- views.py
视图函数代码from django.shortcuts import redirect, render from libry import models from django import forms # ModelForm通过查询models类自动将所有字段转换为form class BookModelForm(forms.ModelForm): class Meta: model = models.Book fields = "__all__" # 为数据库字段在前端生成自定义标题 labels = { "title": "标题", "publishDate": "出版日期", "price": "价格", "publishs": "出版社", "authors": "作者", } # 为前端字段添加自定义属性 widgets = { "publishDate": forms.widgets.TextInput(attrs={"type": "date"}), } # 自定义错误信息 error_messages = { "title": { "required": "不能为空", "min_length": "最小18位", "max_length":"最大18" }, "publishDate": { "required": "不能为空", }, } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for field in self.fields.values(): field.widget.attrs.update({"class": "form-control"}) # 添加书籍 def addbooks(request): if request.method == 'GET': book_modelform_obj = BookModelForm() return render(request, 'open_book.html', { 'book_modelform_obj': book_modelform_obj, "title": "添加书籍", }) if request.method == 'POST': book_modelform_obj = BookModelForm(request.POST) if book_modelform_obj.is_valid(): book_modelform_obj.save() return redirect('showbooks') else: return render(request, 'open_book.html', { 'book_modelform_obj': book_modelform_obj, "title": "添加书籍", }) # 修改书籍 def editbooks(request, book_id): book_obj = models.Book.objects.filter(pk=book_id) book_obj=book_obj.first() if request.method == 'GET': book_modelform_obj = BookModelForm(instance=book_obj) return render(request, 'open_book.html', { "book_modelform_obj": book_modelform_obj, "title": "修改书籍", }) else: book_modelform_obj = BookModelForm(request.POST,instance=book_obj) if book_modelform_obj.is_valid(): book_modelform_obj.save() return redirect('showbooks') else: return render(request, 'open_book.html', { 'book_modelform_obj': book_modelform_obj, "title": "修改书籍", }) def showbooks(request): all_books = models.Book.objects.all() return render(request, 'showbooks.html', {'all_books': all_books}) def deletebooks(request, book_id): models.Book.objects.filter(pk=book_id).delete() return redirect('showbooks')
- urls.py
路由代码from django.conf.urls import url from libry import views urlpatterns = [ url(r'^admin/', admin.site.urls), # 查看所有书籍 url(r'^$', views.showbooks, name='showbooks'), # 添加书籍 url(r'^addbooks/', views.addbooks, name='addbooks'), # 编辑书籍 url(r'^editbooks/(\d+)/', views.editbooks, name='editbooks'), # 删除书籍 url(r'^deletebooks/(\d+)/', views.deletebooks, name='deletebooks'), ]
- open_book.html
添加书籍和修改书籍前端页面{% load static %} <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{ title }}</title> <link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet"> </head> <body> <h1>{{ title }}</h1> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <form action="" method="post" novalidate> {% csrf_token %} {% for book_modelform in book_modelform_obj %} <div class="form-group"> <label for="{{ book_modelform.id_for_label }}">{{ book_modelform.label }}</label> {{ book_modelform }} <span style="color: crimson;font-size: 12px;">{{ book_modelform.errors.0 }}</span> </div> {% endfor %} <button class="btn btn-success pull-right">提交</button> </form> </div> </div> </div> </body> </html>

浙公网安备 33010602011771号