django 練習(xí)壳坪,分頁舶得,form 表單驗證

django 寫的一個在網(wǎng)頁上對學(xué)生信息進行操作,用到了ajax爽蝴,jquery操作表格等沐批,還有 bootstrap,和 font-awesome(圖標(biāo))蝎亚,這些框架寫好了各種各樣的網(wǎng)頁元素珠插,用起來十分的方便,
下面是效果圖颖对,


#models.py 文件 的建表信息
from django.db import models

# Create your models here.

class Classes(models.Model):
    title = models.CharField(max_length=32)
    m = models.ManyToManyField("Teacher")

class Teacher(models.Model):
    name = models.CharField(max_length=32)

class Student(models.Model):
    username = models.CharField(max_length=32)
    age = models.IntegerField()
    gender = models.NullBooleanField()
    cs = models.ForeignKey("Classes",on_delete=models.CASCADE)

路由分發(fā)文件捻撑,

# urls.py 路由文件
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path("students.html/", views.students),
    path("add_student/", views.add_student),
    path("del_students/", views.del_students),
    path("edit_student/", views.edit_student),

]

這個是視圖函數(shù)文件,處理URL分發(fā)的事件

# views.py 文件
from django.shortcuts import render
from django.shortcuts import HttpResponse
from app01 import models
import json
# Create your views here.

def students(request):
    all_students = models.Student.objects.all()
    all_classes = models.Classes.objects.all()
    return render(request, "students.html",{
        "all_students": all_students,
        "all_classes": all_classes,
    })

def add_student(request):
    response = {'status':True,"message":None,"nid":None}
    try:
        username = request.POST.get("username")
        age = request.POST.get("age")
        gender = request.POST.get("gender")
        cls_id = request.POST.get("cls_id")
        print(username,age,gender,cls_id)
        obj = models.Student.objects.create(
            username=username,
            age=age,
            gender=gender,
            cs_id=cls_id,
        )
        response["nid"] = obj.id
    except Exception as e:
        response["status"] = False
        response["message"] = "用戶輸入錯誤"
    import json
    response_json = json.dumps(response)
    return HttpResponse(response_json)

def del_students(request):
    if request.method == "POST":
        response = {"status":True}
        try:
            nid = request.POST.get("nid")
            models.Student.objects.filter(id=nid).delete()
        except Exception as e:
            response["status"] = False
        response_ret = json.dumps(response)
        return HttpResponse(response_ret)

def edit_student(request):
    response = {'code':1000, 'message': None}
    if request.method == "POST":
        try:
            nid = request.POST.get("nid")
            username = request.POST.get("username")
            age = request.POST.get("age")
            gender = request.POST.get("gender")
            cs_id = request.POST.get("cls_id")
            print(nid,username,age,gender,cs_id)
            models.Student.objects.filter(id=nid).update(
                username=username,
                age=age,
                gender=gender,
                cs_id=cs_id,
            )
        except Exception as e:
            response["code"] = 1001
            response["message"] = str(e)

        return HttpResponse(json.dumps(response))

下面這個是主文件了缤底,就只有一個html文件顾患,主要通信都是用ajax

# 這個是 student.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css">
    <link rel="stylesheet" href="/static/plugins/font-awesome/css/font-awesome.css">
    <style>
        .aa {
            font-size: 20px;
            margin-right: 20px;
        }

        .mybtn {
            width: 80px;
            font-size: 20px;
        }
    </style>
</head>
<body class="container">
<a class="btn btn-success mybtn" id="myadd">添加</a>
<table class="table table-hover">
    <thead>
    <tr>
        <th>ID</th>
        <th>姓名</th>
        <th>年齡</th>
        <th>性別</th>
        <th>班級</th>
        <th>操作</th>
    </tr>
    </thead>
    <tbody id="tb">
    {% for foo in all_students %}
        <tr nid="{{ foo.id }}">
            <td na="nid">{{ foo.id }}</td>
            <td na="username">{{ foo.username }}</td>
            <td na="age">{{ foo.age }}</td>
            {% if foo.gender %}
                <td na="gender">男</td>
            {% else %}
                <td na="gender">女</td>
            {% endif %}

            <td na="cs_id" cls_id="{{ foo.cs.id }}">{{ foo.cs.title }}</td>
            <td>
                <a class="aa glyphicon glyphicon-remove" aria-hidden="true"></a>
                <a class="fa fa-spoon fa-2x edit-row" aria-hidden="true"></a>
            </td>
        </tr>
    {% endfor %}
    </tbody>
</table>


<!-- Moda 添加框 -->
<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="myModalLabel">創(chuàng)建學(xué)生</h4>
            </div>
            <div class="modal-body">
                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="username" class="col-sm-2 control-label">姓名</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" id="username" placeholder="姓名" name="username">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="age" class="col-sm-2 control-label">年齡</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" id="age" placeholder="年齡" name="age">
                        </div>
                    </div>

                    <div class="form-group">
                        <label for="age" class="col-sm-2 control-label">性別</label>
                        <div class="col-sm-10">
                            <div class="radio">
                                <label>
                                    <input type="radio" name="gender" value="1">
                                    男
                                </label>
                            </div>
                            <div class="radio">
                                <label>
                                    <input type="radio" name="gender" value="0">
                                    女
                                </label>
                            </div>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="age" class="col-sm-2 control-label">班級</label>
                        <div class="col-sm-10">
                            <select class="form-control" name="cls_id" id="sele">
                                {% for foo in all_classes %}
                                    <option value="{{ foo.id }}">{{ foo.title }}</option>
                                {% endfor %}
                            </select>
                        </div>
                    </div>
                </form>


            </div>
            <div class="modal-footer">
                <span style="color: red" id="error"></span>
                <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
                <button type="button" class="btn btn-primary" id="save">保存</button>
            </div>
        </div>
    </div>
</div>

<!-- Modal 刪除框-->
<div class="modal fade" id="delModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="myModalLabel">是否刪除學(xué)生信息?</h4>
            </div>
            <div class="modal-body">
                <form class="form-horizontal">
                    <h3>=========<input type="hidden" id="nid"></h3>
                </form>
            </div>
            <div class="modal-footer">
                <span style="color: red" id="error"></span>
                <button type="button" class="btn btn-info" data-dismiss="modal">取消</button>
                <button type="button" class="btn btn-danger" id="delComfirm">確定</button>
            </div>
        </div>
    </div>
</div>

<!-- Modal 編輯框-->
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="myModalLabel">編輯學(xué)生信息</h4>
            </div>
            <div class="modal-body">
                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="username" class="col-sm-2 control-label">姓名</label>
                        <div class="col-sm-10">
                            <input type="hidden" name="nid">
                            <input type="text" class="form-control" placeholder="姓名" name="username">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="age" class="col-sm-2 control-label">年齡</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" placeholder="年齡" name="age">
                        </div>
                    </div>

                    <div class="form-group">
                        <label for="age" class="col-sm-2 control-label">性別</label>
                        <div class="col-sm-10">
                            <div class="radio">
                                <label>
                                    <input type="radio" name="gender" value="1">
                                    男
                                </label>
                            </div>
                            <div class="radio">
                                <label>
                                    <input type="radio" name="gender" value="0">
                                    女
                                </label>
                            </div>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="age" class="col-sm-2 control-label">班級</label>
                        <div class="col-sm-10">
                            <select class="form-control" name="cls_id" id="sele">
                                {% for foo in all_classes %}
                                    <option value="{{ foo.id }}">{{ foo.title }}</option>
                                {% endfor %}
                            </select>
                        </div>
                    </div>
                </form>


            </div>
            <div class="modal-footer">
                <span style="color: red" id="error"></span>
                <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
                <button type="button" class="btn btn-primary editConfirm" id="save">保存</button>
            </div>
        </div>
    </div>
</div>



<script src="/static/js/jquery-3.3.1.min.js"></script>
<script src="/static/plugins/bootstrap/js/bootstrap.js"></script>

<script>
    $(function () { //當(dāng)頁面加載完成后給按鈕綁定事件
        bindEvent();
        getData();
        delEvent();
        delConfirm();
        editEvent();
        editConfirm();
    });

    function delConfirm() { //刪除確定按鈕个唧,確定刪除就只需要把對應(yīng)的id發(fā)送到后臺就行了
        $("#delComfirm").click(function () { // 給刪除框的確定按鈕綁定事件江解,
            nid = $("#nid").val();
            console.log(nid);
            $.ajax({
                url: "/del_students/",
                type: "POST",
                data: {"nid":nid},
                success:function (arg) {
                    ret = JSON.parse(arg);  // server 發(fā)過來的就是json字符串
                    if(ret.status){
                        $('tr[nid="'+nid+'"]').remove(); // 不刷新頁面用js移除刪除的tr
                        $("#delModal").modal("hide");
                    }else{
                        alert("刪除失敗")
                    }
                }
            })
        })
    }

    function bindEvent() {
        $("#myadd").click(function () {
            $("#addModal").modal("show"); // 給頁面上的添加按鈕綁定事件,為顯示添加框
        })
    }

    function getData() { // 獲取輸入框的值徙歼,并用ajax發(fā)送到后臺
        var postData = {};
        $("#save").click(function () {
            $("#addModal").find("input,select").each(function () { //找到所有的input 犁河,select框
                var n = $(this).attr("name");
                if(n == "gender"){ // gender 的 radio 單選框要處理一下,而select不必處理魄梯,會直接取到選定的值
                    if($(this).prop("checked")){ //選中的為 true
                        var v = $(this).val();
                        postData[n] = v;
                    }
                }else{
                    var v = $(this).val();
                    postData[n] = v;
                }
            });
            console.log(postData); // 所有的數(shù)據(jù)都在字典內(nèi)了桨螺,

            $.ajax({
                url: "/add_student/",
                type: "POST",
                data: postData,
                success:function (arg) {
                    message = JSON.parse(arg);
                    console.log(message);
                    if(message["status"]){
                        // window.location.reload(); // 刷新頁面
                        create_table(postData,message["nid"]); // 不刷新頁面就要自己用js建一個個td拼成一個tr,添加到table
                        $("#addModal").modal("hide"); // 添加完畢就讓添加框消失酿秸,
                    }else{
                        $("#error").html(message["message"]) //出錯就會有提示信息出現(xiàn)在按鈕旁邊灭翔,看圖片
                    }
                }
            })
        });
    }

    function create_table(postData, nid) { // 創(chuàng)建一個一個標(biāo)簽,拼接起來
        var tr_ele = document.createElement("tr");
        $(tr_ele).attr('nid',nid);

        var td_id = document.createElement("td");
        td_id.innerHTML = nid;
        $(tr_ele).append(td_id);

        var td_user = document.createElement("td");
        td_user.innerHTML = postData["username"];
        $(tr_ele).append(td_user);

        var td_age = document.createElement("td");
        td_age.innerHTML = postData["age"];
        $(tr_ele).append(td_age);

        var td_gender = document.createElement("td");
        if(postData["gender"]==0) {
            var gend = "女";
        }else{
            var gend = "男"
        }
        td_gender.innerHTML = gend;
        $(tr_ele).append(td_gender);

        var td_cls_id = document.createElement("td");
        title = $("#sele").find('option[value="'+postData["cls_id"]+'"]').text();
        td_cls_id.innerHTML = title;
        $(tr_ele).append(td_cls_id);

        // 那兩個a標(biāo)簽辣苏,也就是刪除按鈕和編輯按鈕用字符串的話就相對來說方便一些
        var a_td = '<td><a class="aa glyphicon glyphicon-remove" aria-hidden="true"></a><a class="fa fa-spoon fa-2x" aria-hidden="true"></a> </td>';
        $(tr_ele).append(a_td);

        $("#tb").append(tr_ele);
    }
    
    function delEvent() { // 為刪除按鈕綁定事件
        $("#tb").on('click','.aa',function () {
            $("#delModal").modal("show");
            var nid = $(this).parent().parent().attr("nid"); // 刪除一個記錄就必須要用到id了肝箱,
            $("#nid").val(nid); // 把獲取的的id賦值到刪除提示框的一個隱藏input中,待到按下確認(rèn)刪除按鈕時發(fā)送
        })
    }


    function editEvent() {  // 綁定編輯按鈕的點擊事件
        $("#tb").on("click",".edit-row",function () { // 動態(tài)綁定事件稀蟋,我們必須考慮到動態(tài)添加的標(biāo)簽一般綁定下
            $("#editModal").modal("show");            // 是不會有事件的煌张,就要用到動態(tài)綁定,也就是在按下按鈕時綁定事件并觸發(fā)
            $(this).parent().siblings().each(function () { // 編輯的話就要獲取table上某一行的數(shù)據(jù)了
                var v = $(this).text();
                var n = $(this).attr("na"); // 把相對應(yīng)的鍵值賦給na(隨意的名稱)退客,直接取出來對應(yīng)就行了
                if(n=="cs_id"){             // 這樣的話之后添加和刪除某個選項就不必痛苦了骏融。。。
                    var cid = $(this).attr("cls_id");
                    $("#editModal select[name='cls_id']").val(cid)
                }else if(n=='gender'){
                    if(v=="男"){
                        $("#editModal :radio[value='1']").prop('checked',true);  // 選中 radio 的某一個
                    }else{
                        $("#editModal :radio[value='0']").prop('checked',true);
                    }
                }
                else{
                    $("#editModal input[name='"+n+"']").val(v);
                }
            });
        })
    }
    
    function editConfirm() { // 編輯跟添加類似绎谦,
        var postData = {};
        $(".editConfirm").click(function () {
            $("#editModal").find("input,select").each(function () {
                var n = $(this).attr("name");
                var v = $(this).val();
                if(n=="gender"){
                    if($(this).prop("checked")){
                        postData[n] = v;
                    }
                }else{
                postData[n] = v;
                }
            });
            console.log(postData);

            $.ajax({
                url: "/edit_student/",
                type: "POST",
                data: postData,
                success:function (arg) {
                    ret = JSON.parse(arg);
                    if(ret["code"]==1000){ // ret['code'] 等于 1000 就是為true了
                        window.location.reload();
                        $("#editModal").modal("hide"); // 這里就不用js刪除了管闷,直接刷新頁面
                    }else{
                        alert(ret['message'])
                    }
                }
            })
        })
    }
</script>
</body>
</html>



添加按鈕提示框,當(dāng)用戶輸入有問題時就會提示 ’ 用戶輸入錯誤 ‘ 窃肠,




下面這個是編輯框包个,點擊打開某個學(xué)生時會默認(rèn)選中,



整個總體來說寫的還是存在一個bug冤留,例如在添加學(xué)生信息時碧囊,頁面上是用 js 創(chuàng)建tr表格的,各種屬性沒有添加上去纤怒,
頁面信息有時候用js添加比較好糯而,不用刷新整個頁面,而有時候是頁面整個刷新為好泊窘,看各種情況了熄驼。
下面是總結(jié)呵,

1. 
    Python序列化
        字符串 = json.dumps(對象)    對象->字符串
        對象 = json.loads(字符串)    字符串->對象
        
    JavaScript:
        字符串 = JSON.stringify(對象) 對象->字符串
        對象 = JSON.parse(字符串)     字符串->對象
        
    應(yīng)用場景:
        數(shù)據(jù)傳輸時烘豹,
            發(fā)送:字符串
            接收:字符串 -> 對象
2. ajax

    $.ajax({
        url: 'http//www.baidu.com',
        type: 'GET',
        data: {'k1':'v1'},
        success:function(arg){
            // arg是字符串類型
            // var obj = JSON.parse(arg)
        }
    })
    
    
    $.ajax({
        url: 'http//www.baidu.com',
        type: 'GET',
        data: {'k1':'v1'},
        dataType: 'JSON',
        success:function(arg){
            // arg是對象
        }
    })
    
    
    $.ajax({
        url: 'http//www.baidu.com',
        type: 'GET',
        data: {'k1':[1,2,3,4]},
        dataType: 'JSON',
        success:function(arg){
            // arg是對象
        }
    })
    
    發(fā)送數(shù)據(jù)時:
        data中的v
        
        a. 只是字符串或數(shù)字
            $.ajax({
                url: 'http//www.baidu.com',
                type: 'GET',
                data: {'k1':'v1'},
                dataType: 'JSON',
                success:function(arg){
                    // arg是對象
                }
            })
        b. 包含屬組
            $.ajax({
                url: 'http//www.baidu.com',
                type: 'GET',
                data: {'k1':[1,2,3,4]},
                dataType: 'JSON',
                traditional: true, //// 要加這一句
                success:function(arg){
                    // arg是對象
                }
            })
            
        c. 傳字典瓜贾,或者將其轉(zhuǎn)換成字符串
        
            b. 包含屬組
            $.ajax({
                url: 'http//www.baidu.com',
                type: 'GET',
                data: {'k1': JSON.stringify({}) },
                dataType: 'JSON',
                success:function(arg){
                    // arg是對象
                }
            })
            
    
    
3. 事件委托

    $('要綁定標(biāo)簽的上級標(biāo)簽').on('click','要綁定的標(biāo)簽',function(){})

    $('要綁定標(biāo)簽的上級標(biāo)簽').delegate('要綁定的標(biāo)簽','click',function(){})

4. 編輯
    

5. 總結(jié)

        新URL方式: //也就是跳轉(zhuǎn)到新頁面的方式
            - 獨立的頁面
            - 數(shù)據(jù)量大或條目多
            
        對話框方式:
            - 數(shù)據(jù)量小或條目少
                -增加,編輯
                    - Ajax: 考慮携悯,當(dāng)前頁祭芦;td中自定義屬性
                    - 頁面(***)
                
        刪除:
            對話框

這個就到這里了。路漫漫其修遠兮

django 分頁

補充:
寫一個對頁面分頁的類憔鬼,django的內(nèi)置分頁太丑了

# tests.py 文件龟劲,建立自定制的類
class couPaginator(object):
    def __init__(self,totalCount,CurrentPage,perPageItemNum=30,maxPageNum=8):
        # 數(shù)據(jù)總個數(shù)
        self.total_count = totalCount
        # 當(dāng)前頁
        self.current_page = CurrentPage
        # 每頁最多顯示的條數(shù)
        self.per_page_item_num = perPageItemNum
        # 最多顯示頁面
        self.max_page_num = maxPageNum

        self.check()

    def check(self): # 檢查數(shù)據(jù),
        try:
            self.total_count = int(self.total_count)
            self.current_page = int(self.current_page)
            if self.current_page > self.num_pages: # 如果當(dāng)前頁大于最大頁數(shù)
                self.current_page=self.num_pages
            if self.current_page <= 1: # 如果當(dāng)前頁小于等于1
                self.current_page=1
        except Exception as e:
            pass
    @property # 裝飾器轴或,可以使得函數(shù)不加 () 直接調(diào)用
    def num_pages(self):
        a,b=divmod(self.total_count,self.per_page_item_num) # 總數(shù)目/每頁顯示數(shù)據(jù)昌跌,返回整除和余數(shù)
        if b==0:
            return a
        else:
            return a+1 
    def start(self): # 返回 開始
        return (self.current_page-1)*self.per_page_item_num
    def end(self): # 返回結(jié)束
        return self.current_page*self.per_page_item_num

    @property
    def pager_num_range(self): # 這個是分頁函數(shù),也就是頁面下面的一排跳轉(zhuǎn)頁面
        if self.num_pages <= self.max_page_num:
            return range(1,self.num_pages+1)
        if self.current_page <= self.max_page_num/2:
            return range(1,self.max_page_num+1)
        part = int(self.max_page_num/2)
        if self.current_page+part>=self.num_pages+1:
            return range(self.num_pages-self.max_page_num+1,self.num_pages+1)
        return range(self.current_page-part,self.current_page+part)
    
    def page_str(self): # 對上面的分頁函數(shù)轉(zhuǎn)成html侮叮,可以直接在模版渲染出來避矢,不用再做另外的轉(zhuǎn)換
        test_list=[]
        if self.current_page==1:
            prev = "<li><a href='#'>上一頁</a></li>"
        else:
            prev = "<li><a href='/index2?p=%s'>上一頁</a></li>" %(self.current_page-1)
        if self.current_page==self.max_page_num:
            next = "<li><a href='#'>下一頁</a></li>"
        else:
            next = "<li><a href='/index2?p=%s'>下一頁</a></li>" %(self.current_page+1)
        test_list.append(prev)
        test_list.append(next)
        for i in self.pager_num_range:
            if i == self.current_page:
                temp = "<li class='active'><a href='/index2?p=%s'>%s</a></li>" %(i,i)
            else:
                temp = "<li><a href='/index2?p=%s'>%s</a></li>" %(i,i)
            test_list.append(temp)
        first = "<li><a href='/index2?p=1'>首頁</a></li>"
        last = "<li><a href='/index2?p=%s'>尾頁</a></li>" %(self.num_pages)
        test_list.append(first)
        test_list.append(last)
        return ' '.join(test_list)

模版文件

# index2.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap.css">
</head>
<body>
    {% for foo in data %}
        <p>{{ foo.name }} - {{ foo.age }}</p>
    {% endfor %}


    <ul class="pagination">
        {{ test.page_str|safe }}
      </ul>
</body>
</html>

視圖函數(shù)

# 視圖函數(shù)悼瘾,views.py 文件
test_list = []  # 創(chuàng)建數(shù)據(jù)
for i in range(999):
    temp = {'name':'root'+str(i),'age':i}
    test_list.append(temp)

def index2(request):
    p = request.GET.get("p")
    from app01.tests import couPaginator
    test = couPaginator(999,p,perPageItemNum=10)
    return render(request,"index2.html",{
        "data":test_list[test.start():test.end()],
        "test":test,
    })

不要忘記在 urls.py 文件中添加路由導(dǎo)航囊榜,還有要在靜態(tài)文件下添加bootstrap 文件,靜態(tài)文件目錄也需要配置

2.分頁組件
    - Django內(nèi)置分頁
        - Paginator亥宿、 Page   
        - 頁面:include
    
    - 擴展Django的內(nèi)置分頁
        - CustomPaginator(Paginator)
    傳入:
        - 所有數(shù)據(jù) 
        - 當(dāng)前頁
        - 每頁顯示30條
        - 最多頁面7個
    
    - 自定義分頁
    傳入:
        - 所有數(shù)據(jù)的個數(shù)
        - 當(dāng)前頁
        - 每頁顯示30條
        - 最多頁面7個


form 表單驗證卸勺,基本

調(diào)用 django 內(nèi)置的 Form 組件,對前端的輸入進行驗證和返回錯誤提示信息烫扼,

# views.py 文件下的
from django import forms
from django.forms import fields
class F1form(forms.Form):
    user = fields.CharField(
        max_length=18, # 最長
        min_length=6, # 最短
        required=True, # 限制不能為空
        error_messages={  # 自定制返回到前端的錯誤提示信息
            "required": "用戶名不能為空",
            "max_length": "用戶名太長",
            "min_length": "用戶名太短",
        }
    )
    pwd = fields.CharField(
        min_length=32,
        required=True,
        error_messages={
            "min_length": "最短32個字符",
            "required": "密碼不能為空",
        }
    )
    age = fields.IntegerField(
        required=True,
        error_messages={
            "required": "年齡不能為空",
            "invalid": "必須為數(shù)字",
        }
    )
    email = fields.EmailField(
        required=True,
        error_messages={
            "required": "郵箱不能為空",
            "invalid": "郵箱格式錯誤",
        }
    )


def fm(request):
    if request.method == "GET":
        return render(request,"fm.html")
    if request.method == "POST":
        # user = request.POST.get("user")
        # age = request.POST.get("age")
        # pwd = request.POST.get("pwd")
        # email = request.POST.get("email")
        # print(user,age,pwd,email)
        obj = F1form(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data) # 驗證通過獲取到用戶輸入的數(shù)據(jù)
        else:
            print(obj.errors) # 驗證失敗返回錯誤信息
        return render(request,"fm.html",{"obj":obj})

前端的html文件

# fm.html 文件曙求,用obj.errors.user.0 來取到user錯誤信息的第一個,因為一個輸入框會不止一個錯誤提示
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap.css">
</head>
<body>
<form action="/fm.html/" method="post" id="fm">
    <p><input type="text" name="user" placeholder="user">{{ obj.errors.user.0 }}</p>
    <p><input type="text" name="pwd" placeholder="pwd">{{ obj.errors.pwd.0 }}</p>
    <p><input type="text" name="age" placeholder="age">{{ obj.errors.age.0 }}</p>
    <p><input type="text" name="email" placeholder="email">{{ obj.errors.email.0 }}</p>
    <p><input type="submit" value="提交" class="btn btn-primary"></p>

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

在URL路由文件urls.py 文件下要添加路徑導(dǎo)航,
path('fm.html/', views.fm),
要注釋掉 form 的鎖 csrf

django內(nèi)置的 forms 還能自己生成html代碼悟狱,也就是輸入框静浴,所以, views.py 和 fm.html 文件也可以改成下面的挤渐,

# views.py 文件
def fm(request):
    if request.method == "GET":
        obj = F1form()  # 改動的地方
        return render(request,"fm.html",{"obj":obj}) # 還有這里
    if request.method == "POST":
        # user = request.POST.get("user")
        # age = request.POST.get("age")
        # pwd = request.POST.get("pwd")
        # email = request.POST.get("email")
        # print(user,age,pwd,email)
        obj = F1form(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
        else:
            print(obj.errors)
        return render(request,"fm.html",{"obj":obj})

# html 文件中的 input 輸入框就可以用 django 中的來代替了
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap.css">
</head>
<body>
<form action="/fm.html/" method="post" id="fm">
    <p>{{ obj.user }}{{ obj.errors.user.0 }}</p>
    <p>{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
    <p>{{ obj.age }}{{ obj.errors.age.0 }}</p>
    <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
    <p><input type="submit" value="提交" class="btn btn-primary"></p>

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

form 也可以驗證ajax提交的數(shù)據(jù)苹享,因為ajax提交的數(shù)據(jù)到服務(wù)器也是用post提取的,(具體看你ajax中type的設(shè)置了)


Form組件

    - 對用戶請求的驗證
        - AJax
        - Form
    - 生成HTML代碼

    a. 創(chuàng)建一個類
    b. 類中創(chuàng)建字段(包含正則表達式)
    c. GET
        obj = Fr()
        obj.user = > 自動生成HTML
        
    d. POST
        obj = Fr(request.POST)
        if obj.is_valid():
            obj.cleaned_data
        else:
            obj.errors
            return .... obj
    

form 提交數(shù)據(jù)浴麻,驗證數(shù)據(jù)的有效性得问,

我們可以自定制正則,也可以用django內(nèi)置的規(guī)則软免,

# models.py 創(chuàng)建一個表格
from django.db import models

# Create your models here.

class userInfo(models.Model):
    username = models.CharField(max_length=32)
    email = models.EmailField(max_length=32)

# urls.py 
from django.contrib import admin
from django.urls import path
from app01 import views
from django.conf.urls import url

urlpatterns = [
    path('admin/', admin.site.urls),
    path('users/', views.users),
    path('add_user/', views.add_user),
    url("^edit_user-(\d)$", views.edit_user), #這個是之前版本的路由導(dǎo)航
]

# fm.py 自創(chuàng)建的文件宫纬,放置 form 類
from django import forms
from django.forms import fields

class UserForm(forms.Form):
    username = fields.CharField(
        max_length=32,
        required=True,
        error_messages={  # 自定制錯誤提示信息
            "required":"請輸入用戶名",
            "max_length": "必須輸入32個字符",
        }
    )
    email = fields.EmailField(
        required=True,
        error_messages={
            "required": "必須輸入郵箱",
            "invalid": "不是正確的郵箱格式",
        }
    )
# views.py 
from django.shortcuts import render
from django.shortcuts import redirect
from app01 import models

from app01 import fm

def users(request): # 返回所有的數(shù)據(jù),也就是所有表格的信息
    data_list = models.userInfo.objects.all()
    return render(request,"users.html",{"data_list":data_list})

def add_user(request): # 添加數(shù)據(jù)膏萧,跳轉(zhuǎn)到add_user.html, 
    if request.method == "GET":
        obj = fm.UserForm()
        return render(request,"add_user.html",{"obj":obj})
    if request.method == "POST": # post 接收數(shù)據(jù)漓骚,用form檢測格式
        obj = fm.UserForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
            models.userInfo.objects.create(**obj.cleaned_data) # 檢測通過創(chuàng)建數(shù)據(jù)
            return redirect("/users.html")
        else:
            return render(request,"add_user.html",{"obj":obj}) # 錯誤提示,返回錯誤信息

def edit_user(request,nid): # 編輯信息榛泛,使用form為我們寫好的生成html认境,在edit_user.html中
    if request.method == "GET":
        data = models.userInfo.objects.filter(id=nid)[0] # nid 在ulrs.py 文件正則取得
        obj = fm.UserForm({"username":data.username,"email":data.email})
        return render(request,"edit_user.html",{"obj": obj,"nid":nid})
    if request.method == "POST":
        obj = fm.UserForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
            models.userInfo.objects.filter(id=nid).update(**obj.cleaned_data)
            return redirect("/users")
        else:
            print(obj.errors) # 記得,返回錯誤信息時還要返回一次nid
            return render(request,"edit_user.html",{"obj":obj,"nid":nid})

# users.html  ----》user 函數(shù)(對應(yīng))
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href="/add_user/">添加</a>
{% for foo in data_list %}
    <p>
        <span> {{ foo.id }} </span>
        <span> {{ foo.username }} </span>
        <span> {{ foo.email }} </span>
    <a href="/edit_user-{{ foo.id }}">編輯</a>
    </p>
{% endfor %}

</body>
</html>

# add_user.html ----》add_user 函數(shù)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/add_user/" method="post" novalidate>
    <p>{{ obj.username }}{{ obj.errors.username.0 }}</p>
    <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
    <input type="submit">
</form>
</body>
</html>

# edit_user.html ----》edit_user
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/edit_user-{{ nid }}" method="post" novalidate>
    <p>{{ obj.username }}{{ obj.errors.username.0 }}</p>
    <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
    <input type="submit" value="提交">
</form>
</body>
</html>



Form組件
    - form表單(驗證挟鸠;保留上次內(nèi)容)
        - 
    - Ajax(驗證叉信;無需上次內(nèi)容)
        - 返回HttpResponse
        - 前端:跳轉(zhuǎn)或錯誤信息
        

所謂的擴展
        
1. Form組件擴展:

    1.簡單擴展
        利用Form組件自帶的正則擴展:
            a. 方式一
                from django.forms import Form
                from django.forms import widgets
                from django.forms import fields
                from django.core.validators import RegexValidator
                 
                class MyForm(Form):
                    user = fields.CharField(
                        error_messages={'invalid': '...'},
                        validators=[RegexValidator(r'^[0-9]+$', '請輸入數(shù)字'), RegexValidator(r'^159[0-9]+$', '數(shù)字必須以159開頭')],
                    )
            b. 方式二
                from django.forms import Form
                from django.forms import widgets
                from django.forms import fields
                from django.core.validators import RegexValidator
                 
                class MyForm(Form):
                    user = fields.RegexField(r'^[0-9]+$',error_messages={'invalid': '...'})
                    
    2.基于源碼流程
        a. 單字段
            from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
            class AjaxForm(forms.Form):
                username = fields.CharField()
                user_id = fields.IntegerField(
                    widget=widgets.Select(choices=[(0,'alex'),(1,'劉皓宸'),(2,'楊建'),])
                )
            # 自定義方法 clean_字段名
            # 必須返回值self.cleaned_data['username']
            # 如果出錯:raise ValidationError('用戶名已存在')
            def clean_username(self):
                v = self.cleaned_data['username']
                if models.UserInfo.objects.filter(username=v).count():
                    # 整體錯了
                    # 自己詳細錯誤信息
                    raise ValidationError('用戶名已存在')
                return v
            def clean_user_id(self):
                return self.cleaned_data['user_id']
                    
                 
        b. 整體錯誤驗證
            class AjaxForm(forms.Form):
                username = fields.CharField()
                user_id = fields.IntegerField(
                    widget=widgets.Select(choices=[(0,'alex'),(1,'劉皓宸'),(2,'楊建'),])
                )
                # 自定義方法 clean_字段名
                # 必須返回值self.cleaned_data['username']
                # 如果出錯:raise ValidationError('用戶名已存在')
                def clean_username(self):
                    v = self.cleaned_data['username']
                    if models.UserInfo.objects.filter(username=v).count():
                        # 整體錯了
                        # 自己詳細錯誤信息
                        raise ValidationError('用戶名已存在')
                    return v
                def clean_user_id(self):
                    return self.cleaned_data['user_id']

                def clean(self):
                    value_dict = self.cleaned_data
                    v1 = value_dict.get('username')
                    v2 = value_dict.get('user_id')
                    if v1 == 'root' and v2==1:
                        raise ValidationError('整體錯誤信息')
                    return self.cleaned_data
                    
                    
        PS: _post_clean
form結(jié)束了,就這些東西艘希,擴展也并不是很多內(nèi)容
                
         
2. Django序列化
    a.對象
    b.字典
    c.元祖

===================================


首先能完成任務(wù)台丛,

亮點惩嘉,分為兩種,一參加過某種大型的架構(gòu),二某種東西研究得特別深未桥,那就研究,

1.筆試:

2.面試

方向:
    - 基礎(chǔ)
    - 亮點

基礎(chǔ):
    1.設(shè)計程序
    2.開發(fā)

亮點:
    某框架的源碼:
    Tornado - 異步非堵塞(IO多路復(fù)用)

關(guān)于序列化問題扯再,也就是 Queryset 類型轉(zhuǎn)成 json 類型传黄,可以參考
博客:http://www.cnblogs.com/wupeiqi/articles/5246483.html
http://www.cnblogs.com/wupeiqi/articles/6144178.html

今天在簡書編輯后丟了很多東西,好氣啊

關(guān)于 NON_FIELD_ERRORS凤壁,也就是 all 了吩屹,下面是一個補充:

from django.shortcuts import render
from django.shortcuts import HttpResponse
from app01 import models

from django import forms
from django.forms import fields
from django.forms import widgets
from django.core.exceptions import ValidationError


class LoginForm(forms.Form):
    username = fields.CharField(
        max_length=32,
        required=True,
        error_messages={
            'required':'請輸入用戶名',
            'max_length':'最長輸入32個字符',
        },
        widget=widgets.TextInput()
    )
    # def clean_username(self):
    #     v1 = self.cleaned_data['username']
    #     v2 = models.User.objects.filter(username=v1).first()
    #     if not v2:
    #         raise ValidationError("用戶名錯誤") # 這個引發(fā)的錯誤會在errors.username顯示
    #     return v1

    password = fields.CharField(
        max_length=32,
        required=True,
        error_messages={
            'required':'請輸入密碼',
            'max_length':'最長輸入32個字符'
        },
        widget=widgets.PasswordInput()
    )

    def clean(self):
        v1 = self.cleaned_data.get('username')
        v2 = self.cleaned_data.get('password')
        obj = models.User.objects.filter(username=v1).first()
        if not obj:
            raise ValidationError("用戶名錯誤")
        elif obj.password != v2:
            raise ValidationError("密碼錯誤")
        return self.cleaned_data

from django.core.exceptions import NON_FIELD_ERRORS
def login(request):
    if request.method == "GET":
        obj = LoginForm()
        return render(request,"login.html",{"obj":obj})
    else:
        obj = LoginForm(request.POST)
        all_code = None
        if obj.is_valid():
            print(obj.cleaned_data)
            return HttpResponse("登陸成功")
        else:
            print(obj.errors)
            all_code = obj.errors[NON_FIELD_ERRORS] 
             # 在 template中沒有 NON_FIELD_ERRORS,我只想到這個辦法來傳過去
        return render(request,"login.html",{"obj":obj,"all_code":all_code})
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拧抖,一起剝皮案震驚了整個濱河市煤搜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌唧席,老刑警劉巖擦盾,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嘲驾,死亡現(xiàn)場離奇詭異,居然都是意外死亡迹卢,警方通過查閱死者的電腦和手機辽故,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腐碱,“玉大人榕暇,你說我怎么就攤上這事∮麒荆” “怎么了彤枢?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長筒饰。 經(jīng)常有香客問我缴啡,道長,這世上最難降的妖魔是什么瓷们? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任业栅,我火速辦了婚禮,結(jié)果婚禮上谬晕,老公的妹妹穿的比我還像新娘碘裕。我一直安慰自己,他們只是感情好攒钳,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布帮孔。 她就那樣靜靜地躺著,像睡著了一般不撑。 火紅的嫁衣襯著肌膚如雪文兢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天焕檬,我揣著相機與錄音姆坚,去河邊找鬼。 笑死实愚,一個胖子當(dāng)著我的面吹牛兼呵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播腊敲,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼击喂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了兔仰?” 一聲冷哼從身側(cè)響起茫负,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乎赴,沒想到半個月后忍法,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡榕吼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年饿序,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羹蚣。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡原探,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出顽素,到底是詐尸還是另有隱情咽弦,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布胁出,位于F島的核電站型型,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏全蝶。R本人自食惡果不足惜闹蒜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抑淫。 院中可真熱鬧绷落,春花似錦、人聲如沸始苇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽催式。三九已至往弓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蓄氧,已是汗流浹背函似。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留喉童,地道東北人撇寞。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像堂氯,于是被迫代替她去往敵國和親蔑担。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容