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>

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