Django之ModelForm

12345huangchun 2019-01-16 原文

  在前面有篇博客,我写了一个叫forms组件的东西,可以帮助我们完成校验数据、渲染标签功能和在前端页面局部刷新功能,功能封装的已经很好了,当时已经很开心了。但万万没想到,还有比它功能更强大的东西。forms组件只能渲染出type=text类型的标签,而且还要我们写无数多个字段,然后跟上校验条件,用forms组件做编辑页面时,还要手动的把编辑的对象的每一个值写入标签的value,这些等等虽然相较没用forms组件之前更方便了,但跟ModelForm比起来,都显得苍白无力,把ModelForm吹了那么久,现在就让我们来见识见识ModelForm的强大。

  不管是用什么,首先都得有模型类吧,创建模型类是没有变化的,这是往库里创建表的必有步骤,肯定是变不的。

  models.py

  1. from django.db import models
  2. # Create your models here.
  3. class Book(models.Model):
  4. name=models.CharField(max_length=15,verbose_name='名字')
  5. price=models.IntegerField(verbose_name='价格')
  6. pub_date=models.DateTimeField(verbose_name='出版时间')
  7. publish = models.ForeignKey('Publish', on_delete=models.CASCADE,verbose_name='出版社')
  8. author=models.ManyToManyField('Author',db_table='book_author',verbose_name='作者')
  9. class Meta:
  10. db_table='Book'
  11. verbose_name='书籍'
  12. def __str__(self):
  13. return self.name
  14. class Publish(models.Model):
  15. name=models.CharField(max_length=15,verbose_name='名字')
  16. addr=models.CharField(max_length=15,verbose_name='地址')
  17. phone=models.IntegerField(verbose_name='电话号码')
  18. class Meta:
  19. db_table='Publish'
  20. verbose_name='出版社'
  21. def __str__(self):
  22. return self.name
  23. class Author(models.Model):
  24. name=models.CharField(max_length=15,verbose_name='名字')
  25. age=models.IntegerField(verbose_name='年龄')
  26. author_info=models.OneToOneField('Author_Info',on_delete=models.CASCADE,verbose_name='详情')
  27. class Meta:
  28. db_table='Author'
  29. verbose_name='作者'
  30. def __str__(self):
  31. return self.name
  32. class Author_Info(models.Model):
  33. gf_name=models.CharField(max_length=10,verbose_name='女朋友名字')
  34. telephone=models.IntegerField(verbose_name='电话号码')
  35. ShenFenZheng=models.IntegerField(verbose_name='身份证号')
  36. class Meta:
  37. db_table='Author_Info'
  38. verbose_name='作者详情'
  39. def __str__(self):
  40. return str(self.ShenFenZheng)
  1. from django import forms
  2. from django.forms import widgets as wid
  3. class BookModelForm(forms.ModelForm):
  4. class Meta:
  5. model=models.Book #这相当于给Book模型类创建的
  6. # fields=["title","price"]
  7. # exclude = ["title"]
  8. fields="__all__" #这是要校验的字段,现在表示所有字段校验,上面两种写法也可以。
  9. widgets={
  10. "name":wid.TextInput(attrs={"class":"form-control"}),
  11. "price":wid.TextInput(attrs={"class":"form-control"})
  12. } #这是对用ModelForm生成标签的属性修改
  13. error_messages={
  14. "name":{"required":"该字段不能为空"}
  15. } #这是修改错误信息的显示样式
  16. labels={
  17. "name":"书籍名称"
  18. }
  19. def clean_title(self): #也可以定义钩子
  20. val=self.cleaned_data.get("title")
  21. if val.startswith("xxx"):
  22. return val
  23. else:
  24. raise ValidationError("必须以xxx开头!")

  ModelForm校验数据和forms组件是一样,用is_valid()按照校验规则来校验,错误的信息会放在form.errors里面。

  views.py

  1. def addbook(request):
  2. if request.method=="POST":
  3. form=BookModelForm(request.POST)
  4. if form.is_valid():
  5. form.save() #当数据校验通过后,我们不用写什么create,只需要写上这一句,就完成在表中创建一条记录。
  6. return redirect("/books/")
  7. else:
  8. return render(request, 'addbook.html', locals())
  9. else:
  10. # form=BookForm() # forms组件
  11. form=BookModelForm() # modelforms组件
  12. return render(request,'addbook.html',locals())

  add.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <link rel="stylesheet" href="/static/css/bootstrap.css">
  7. <script src="/static/jquery-3.3.1.js"></script>
  8. <script src="/static/js/bootstrap.js"></script>
  9. <style>
  10. .outer{
  11. margin-top: 200px;
  12. }
  13. .title{
  14. margin-bottom: 50px;
  15. }
  16. ul{
  17. list-style: none;
  18. margin: 0;
  19. padding: 0;
  20. }
  21. .left{
  22. position: fixed;
  23. left: 0;
  24. top: 20px;
  25. }
  26. </style>
  27. </head>
  28. <body>
  29. <div class="left">
  30. <div class="panel panel-primary">
  31. <div class="panel-heading">
  32. <h3 class="panel-title">操作栏</h3>
  33. </div>
  34. <div class="panel-body">
  35. <div>
  36. <a href="{% url 'app01_publish_add' %}?next={{ url }}" class="">添加出版社</a>
  37. </div>
  38. <div>
  39. <a href="" class="">添加作者</a>
  40. </div>
  41. </div>
  42. </div>
  43. </div>
  44. <div class="container outer">
  45. <div class="row">
  46. <div class="col-md-6 col-md-offset-3">
  47. <div style="color: blue;font-size: 50px;text-align: center;font-family: 华文隶书" class="title">添加{{ zw_name }}</div>
  48. <form action="" method="post" novalidate>
  49. {% csrf_token %}
  50. {% for field in form %}
  51. <div class="form-group ">
  52. <label for="id_{{ field.name }}">{{ field.label }}</label>
  53. {{ field }}<span style="color: red">{{field.errors }}</span>
  54. </div>
  55. {% endfor %}
  56. <button class="submit btn btn-info pull-right">提交</button>
  57. </form>
  58. </div>
  59. </div>
  60. </div>
  61. <script>
  62. $('input,select').addClass('form-control');
  63. </script>
  64. </body>
  65. </html>

  其实从代码层面上讲,做add校验和标签渲染没多大区别,但在前端页面上看是有区别的,forms组件只能渲染成type=text的input标签,多于一对多和多对多的字段就无能为力了,还得自己去写。但ModelForm就不一样了,它会把你的一对多的字段渲染成单选的select标签,把多对多的字段渲染成多选的select标签,这样就相当方便了。如下图:

  ModelForm可以渲染select标签,它在编辑页面还有更强大的功能,你只需把一个模型类的对象传给他,他就可以帮你把对象每个值取出来,然后赋予标签的value,在更新数据时也不用写update了,用save()就搞定了。这就解决了我们要手动的去把要编辑的对象每个字段的值取出来放入标签中。

  views.py

  1. def editbook(request,edit_book_id):
  2. edit_book = models.Book.objects.filter(pk=edit_book_id).first()
  3. if request.method=="POST":
  4. form = BookModelForm(request.POST,instance=edit_book)
  5. if form.is_valid():
  6. form.save() #在这里用save()的前提是校验的时候你把要编辑的对象传给ModelForm的instance参数了,不然就相当于重新创建一条表记录
  7. return redirect("/books/")
  8. else:
  9. return render(request, 'editbook.html', locals())
  10. else:
  11. form=BookModelForm(instance=edit_book) #要把编辑的对象传给ModelForm的instance参数
  12. return render(request,'editbook.html',locals())

  edit.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <link rel="stylesheet" href="/static/css/bootstrap.css">
  7. <script src="/static/jquery-3.3.1.js"></script>
  8. <script src="/static/js/bootstrap.js"></script>
  9. <style>
  10. .outer{
  11. margin-top: 200px;
  12. }
  13. .title{
  14. margin-bottom: 50px;
  15. }
  16. ul{
  17. list-style: none;
  18. margin: 0;
  19. padding: 0;
  20. }
  21. .left{
  22. position: fixed;
  23. left: 0;
  24. top: 20px;
  25. }
  26. </style>
  27. </head>
  28. <body>
  29. <div class="left">
  30. <div class="panel panel-primary">
  31. <div class="panel-heading">
  32. <h3 class="panel-title">操作栏</h3>
  33. </div>
  34. <div class="panel-body">
  35. <div>
  36. <a href="{% url 'app01_publish_add' %}?next={{ url }}" class="">添加出版社</a>
  37. </div>
  38. <div>
  39. <a href="" class="">添加作者</a>
  40. </div>
  41. </div>
  42. </div>
  43. </div>
  44. <div class="container outer">
  45. <div class="row">
  46. <div class="col-md-6 col-md-offset-3">
  47. <div style="color: blue;font-size: 50px;text-align: center;font-family: 华文隶书" class="title">编辑{{ zw_name }}</div>
  48. <form action="" method="post" novalidate>
  49. {% csrf_token %}
  50. {% for field in form %}
  51. <div class="form-group ">
  52. <label for="id_{{ field.name }}">{{ field.label }}</label>
  53. {{ field }}<span style="color: red">{{field.errors }}</span>
  54. </div>
  55. {% endfor %}
  56. <button class="submit btn btn-info pull-right">提交</button>
  57. </form>
  58. </div>
  59. </div>
  60. </div>
  61. <script>
  62. $('input,select').addClass('form-control');
  63. </script>
  64. </body>
  65. </html>

 

  结果:

 

   总之啊,ModelForm是相当的好用,一直以来,我的叫法应该都有问题,我一直把forms组件下的Form叫成forms组件,之前写的Form和今天写的ModelForm都属于forms组件,大家请原谅我。

发表于 2019-01-16 21:23 W的一天 阅读() 评论() 编辑 收藏

 

版权声明:本文为12345huangchun原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/12345huangchun/p/10279483.html

Django之ModelForm的更多相关文章

随机推荐

  1. 成功填坑! Java引入QQ登录时,AccessToken [accessToken=, expireIn=];

    主要就是会一直进入下面这一行,也就是accessTokenObj.getAccessToken().equal […]...

  2. 51单片机创建PDF文件

    PDF文件有特定的格式要求,本以为.TXT与.PDF之间可以相互转换,只需要修改后缀名就可以了,然而事实并非如 […]...

  3. Zabbix实战-简易教程–拓扑图(Maps)

       一、拓扑图(Maps)  二话不说,有图有真相,先看看效果,再详细讲解配置过程: 图1:全国网络质量图 […]...

  4. Mybatis学习系列(1) –– 入门简介

    MyBatis简介 Mybatis是Apache的一个Java开开源项目,是一个支持动态Sql语句的持久层框架 […]...

  5. git学习记录

    git 学习笔记 (gitlab搭建自己服务器上的远程仓库,稍后研究) 1、pwd : 命令用于显示当前目录 […]...

  6. 【Go】string 优化误区及建议

    原文链接: https://blog.thinkeridea.com/201902/go/string_ye_ […]...

  7. 致一岁以下的产品经理-简历这样写

    简历是生命之光!没有TA就没有面试邀请,就没有面试,就没有新的工作,就没有高工资!所以咱们聊聊0-1岁的产品同 […]...

  8. 自定义损失函数 度量函数

    转:http://blog.itpub.net/31545819/viewspace-2215108/ 介绍 […]...

展开目录

目录导航