Django 之 练习4: form 组件


代码目录结构

在这里插入图片描述


逻辑代码

urls.py

from django.contrib import admin
from django.urls import path, re_path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),

    path('book_list/', views.book_list),
    path('book_add/', views.BookAdd.as_view()),
    re_path(r'book_del/(?P<id>\d+)', views.book_del),
    re_path('book_edit/(?P<id>\d+)/', views.BookEdit.as_view()),

    path('author_list/', views.author_list),
    path('author_add/', views.AuthorAdd.as_view()),
    re_path(r'author_del/(?P<id>\d+)', views.author_del),

]


models.py

from django.db import models

# Create your models here.


class Author(models.Model):
    name = models.CharField(max_length=16)
    age = models.IntegerField()
    phone = models.CharField(max_length=16, unique=True)

    class Meta:
        verbose_name = "作者"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Publisher(models.Model):
    name = models.CharField(max_length=16)

    class Meta:
        verbose_name = "出版社"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Book(models.Model):
    title = models.CharField(max_length=32)
    publisher = models.ForeignKey(to="Publisher", on_delete=models.CASCADE)
    authors = models.ManyToManyField(to="Author", related_name="zuopin")

    class Meta:
        verbose_name = "书籍"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title



forms.py(app01)

from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from app01 import models


class BookForm(forms.Form):

    title = forms.CharField(
        max_length=16,
        label="书名",
        # 这里加一个插件是为了往字段中加入 class 属性值, 文字框为 TextInput
        widget=forms.TextInput(
            attrs={
                "class": "form-control"
            }
        )
    )
    publisher = forms.ModelChoiceField(
        queryset=models.Publisher.objects.all(),
        # 单选框为 Select
        widget=forms.Select(
            attrs={
                "class": "form-control"
            }
        )
    )
    authors = forms.ModelMultipleChoiceField(
        queryset=models.Author.objects.all(),
        # 多选框为 SelectMultiple
        widget=forms.SelectMultiple(
            attrs={
                "class": "form-control"
            }
        )
    )

    # 钩子函数(hook) clean_字段
    def clean_title(self):
        # 从处理后的数据中拿到 title 的值
        v = self.cleaned_data.get("title")
        if "alex" in v:
            raise ValidationError("包含敏感词 alex")
        else:
            return v


# 自定义的校验规则函数
def phone_validate(v):
    # 用用户填写的手机号去数据库查找
    is_exist = models.Author.objects.filter(phone=v)
    if is_exist:
        # 如果已经存在, 就不能注册
        raise ValidationError("该手机号已经注册")
    else:
        return v


class AuthorForm(forms.Form):

    name = forms.CharField(
        max_length=16,
        label="姓名",
        widget=forms.TextInput(
            attrs={
                "class": "form-control"
            }
        )
    )

    age = forms.IntegerField(
        required=False,
        initial=18,
        label="年龄",
        widget=forms.TextInput(
            attrs={
                "class": "form-control"
            }
        )
    )

    # 校验手机号唯一且符合手机号格式规则
    phone = forms.CharField(
        min_length=11,
        max_length=11,
        label="手机号",
        widget=forms.TextInput(
            attrs={
                "class": "form-control"
            }
        ),
        validators=[RegexValidator(r'^1[356789]\d{9}$', "手机号格式有误"), phone_validate]
    )

    pwd1 = forms.CharField(
        label="pwd-1",
        widget=forms.PasswordInput(
            attrs={
                "class": "form-control"
            }
        )
    )

    pwd2 = forms.CharField(
        label="pwd-2",
        widget=forms.PasswordInput(
            attrs={
                "class": "form-control"
            }
        )
    )

    # 全局钩子
    def clean(self):
        # 可以取到 cleaned_data 中所有的数据进行对比校验
        pwd1 = self.cleaned_data.get("pwd1")
        pwd2 = self.cleaned_data.get("pwd2")
        if pwd1 != pwd2:
            # self.add_error("字段", "密码和确认密码不一致"), 这个是定义报错信息的位置
            self.add_error("pwd2", "密码不相同")
        else:
            pass


views.py(app01)

from django.shortcuts import render, redirect, HttpResponse
from app01 import models
from django import views
from app01.forms import BookForm, AuthorForm
from django.forms import model_to_dict  # 将模型快速转换为字典


# Create your views here.


def book_list(request):
    data = models.Book.objects.all()
    return render(request, "book_list.html", {"data": data})


class BookAdd(views.View):

    def get(self, request):
        book_obj = BookForm()
        return render(request, "book_add.html", {"book_obj": book_obj})

    def post(self, request):
        # 先实例化
        book_obj = BookForm(request.POST)
        # 检验, 这个是内置的
        if book_obj.is_valid():
            # 先处理多对多字段
            authors = book_obj.cleaned_data.pop("authors")
            # 根据处理之后的数据 cleaned_data 实例化
            book_obj = models.Book.objects.create(**book_obj.cleaned_data)
            # 设置多对多字段的值
            book_obj.authors.set(authors)
            # 返回
            return redirect('/book_list/')
        else:
            return render(request, "book_add.html", locals())


def book_del(request, id):
    models.Book.objects.filter(id=id).first().delete()
    return redirect("/book_list/")


class BookEdit(views.View):

    def get(self, request, id):
        ret = models.Book.objects.filter(id=id).first()
        # model_to_dict 方法可以将 orm 对象快速转换为字典
        book_obj = BookForm(model_to_dict(ret))
        return render(request, "book_edit.html", locals())

    def post(self, request, id):
        query_ret = models.Book.objects.filter(id=id).first()
        book_obj = BookForm(request.POST)
        if book_obj.is_valid():
            query_ret.title = book_obj.cleaned_data.get("title")
            query_ret.publisher_id = book_obj.cleaned_data.get("publisher")
            query_ret.save()
            query_ret.authors.set(book_obj.cleaned_data.get("authors"))
            return redirect("/book_list/")
        else:
            return render(request, "book_edit.html", locals())




def author_list(request):
    data = models.Author.objects.all()
    return render(request, "author_list.html", {"data": data})


class AuthorAdd(views.View):

    def get(self, request):
        author_obj = AuthorForm()
        return render(request, "author_add.html", {"author_obj": author_obj})

    def post(self, request):
        author_obj = AuthorForm(request.POST)
        if author_obj.is_valid():
            models.Author.objects.create(**author_obj.cleaned_data)
            return redirect("/author_list/")
        else:
            return render(request, "author_add.html", locals())


def author_del(request, id):
    models.Author.objects.filter(id=id).first().delete()
    return redirect("/author_list/")


class AuthorEdit(views.View):

    def get(self, request):
        pass

    def post(self, request):
        pass


template

author_add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加作者</title>

    <link href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post" autocomplete="off" novalidate>
                {% csrf_token %}
                {% for foo in author_obj %}
                    <label for="{{ foo.id_for_label }}">{{ foo.label }}</label>
                    {{ foo }}
                    <p style="color: red">{{ foo.errors.0 }}</p>
                {% endfor %}
                <input type="submit" class="btn btn-success" value="提交">
            </form>
        </div>
    </div>
</div>

</body>
</html>


author_list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>书籍列表</title>

     <link href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

<h1>作者列表</h1>

<a href="/author_add/">添加作者</a>

<table class="table table-striped">
    <thead>
        <tr>
            <td>序号</td>
            <td>姓名</td>
            <td>年龄</td>
            <td>手机号</td>
            <td>操作</td>
        </tr>
    </thead>
    <tbody>
    {% for foo in data %}
        <tr>
        <td>{{ forloop.counter }}</td>
        <td>{{ foo.name }}</td>
        <td>{{ foo.age }}</td>
        <td>{{ foo.phone }}</td>
        <td><a href="/author_edit/{{ foo.id }}/">编辑</a> <a href="">删除</a></td>
        </tr>
    {% endfor %}
    </tbody>
</table>
</body>
</html>


book_add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加书籍</title>

    <link href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
        <form action="" method="post" novalidate autocomplete="off">  <!-- 不检验, 关闭补全提示 -->
            {% csrf_token %}
            {% for foo in book_obj %}
            <div class="form-group">
                <!-- id_for_label 和 label 都是内置的方法 -->
                <label for="{{ foo.id_for_label }}">{{ foo.label }}</label>
                {{ foo }}
                <!-- 这里加了一行错误提示, 错误信息由 post 方法返回 -->
                <p style="color: red">{{ foo.errors.0 }}</p>
            </div>
            {% endfor %}
            <input type="submit" value="提交" class="btn btn-success">
        </form>
        </div>
    </div>
</div>

</form>
</body>
</html>


book_edit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>编辑书籍</title>

    <link href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post" novalidate autocomplete="off">
                {% csrf_token %}
                {% for foo in book_obj %}
                    <label for="{{ foo.id_for_label }}">{{ foo.label }}</label>
                    {{ foo }}
                    <p style="color: red">{{ foo.errors.0 }}</p>
                {% endfor %}
                <input type="submit" class="btn btn-success" value="提交">
            </form>
        </div>
    </div>
</div>

</body>
</html>


book_list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>书籍列表</title>

    <link href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>


<h1>书籍列表</h1>

<a href="/book_add/">添加书籍</a>

<table class="table table-striped">
    <thead>
    <tr>
        <td>序号</td>
        <td>书名</td>
        <td>作者</td>
        <td>出版社</td>
        <td>操作</td>
    </tr>
    </thead>
    <tbody>
    {% for foo in data %}
        <tr>
            <td>{{ forloop.counter }}</td>
            <td>{{ foo.title }}</td>
            <td>
                {% for datum in foo.authors.all %}
                    {{ datum }}
                {% endfor %}
            </td>
            <td>{{ foo.publisher.name }}</td>
            <td><a href="/book_edit/{{ foo.id }}/">编辑</a> <a href="/book_del/{{ foo.id }}">删除</a></td>
        </tr>
    {% endfor %}
    </tbody>
</table>

</body>
</html>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章