Django10.1: ModelForm组件

用上次的图书管理系统作为示例,来了解一下ModelForm

图书管理系统:form版本

图书管理系统:普通版本

数据库类型如下

# 作者表
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>
    添加书籍和修改书籍前端页面
posted @ 2020-07-12 17:50  CatdeXin  阅读(183)  评论(0)    收藏  举报