实例项目

项目需求分析

通过form表单的方式,来实现以下几个功能
1、html标签的自动生成
2、上次输入数据的保留
3、输入数据的验证

代码实施

数据库代码

from django.db import models

class Classes(models.Model):
    title = models.CharField(max_length=32)

class Student(models.Model):
    sname = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    age = models.IntegerField()
    cls = models.ForeignKey('Classes',on_delete=models.CASCADE)

class Teacher(models.Model):
    tname = models.CharField(max_length=32)
    c2t = models.ManyToManyField('Classes')

数据库报错'on_delete'

Djiango的时候发现执行mange.py makemigrations 和 migrate是会报错,少位置参数on_delete,查了一下是因为指定外键的方式不对,改一下就OK了。
一对多设计 多方持有一方的外键
所以解决方法是:

cls = models.ForeignKey('Classes')
添加字段变成
cls = models.ForeignKey('Classes',on_delete=models.CASCADE)

班级管理

由于不小心把django升级到了2.0版本,在做路由的时候发现出现了问题,下面有记录。2.0是咱们为python3.x出的,先用用看
班级管理功能:
1、班级的列表
2、班级的增加
3、班级的编辑

班级的路由url

from django.contrib import admin
from django.urls import path,re_path
from clsmanagent import views
from django.conf.urls import url

urlpatterns = [
    path('class_list/', views.class_list),
    path('add_class/', views.add_class),
    path('edit_class/<int:nid>/', views.edit_class),

班级管理列表

视图文件py

from django.shortcuts import render,redirect,HttpResponse
from django.forms import Form, fields,widgets
from clsmanagent import models

# 班级form验证
class ClassForm(Form):
    title = fields.RegexField('全栈\d+',label='班级名称')

# 班级信息
def class_list(request):
    # if request.method == "GET":
    obj = models.Classes.objects.all()
    return render(request, 'classlist.html', {'obj': obj})

班级的列表的html文件

<h2>班级列表</h2>
<hr>
<span><a href="/add_class/">添加班级</a></span>
{#<form action="/class_list/" method="post">#}
{#    {% csrf_token %}#}
    <ul>
        {% for cls_list in obj %}
            <li>{{ cls_list.title }}<a href="/edit_class/{{ cls_list.id }}/">编辑</a></li>
        {% endfor %}
    </ul>
{#</form>#}

班级增加功能

增加功能视图文件

#添加班级
def add_class(request):
    if request.method == "GET":
        obj = ClassForm()
        return render(request,'addclass.html',{'obj':obj})
    else:
        obj = ClassForm(request.POST)
        if obj.is_valid():
            models.Classes.objects.create(**obj.cleaned_data)
            return redirect('/class_list/')
        return render(request, 'addclass.html', {'obj': obj})

增加班级的html代码

<form action="/add_class/" method="post">
    {% csrf_token %}
    <p>
{#        {{ obj.as_p }}#}
        {{ obj.title }} {{ obj.errors.title.0 }}
    </p>
    <p>
        <input type="submit" value="提交">
    </p>
</form>

编辑班级

编辑班级视图文件

def edit_class(request,nid):
    if request.method == "GET":
        cls_info = models.Classes.objects.filter(id=nid).first()
        print(cls_info)
        obj = ClassForm(initial={'title':cls_info.title})
        return render(request,'editclass.html',{'obj':obj,'nid':nid})
    else:
        obj = ClassForm(request.POST)
        if obj.is_valid():
            models.Classes.objects.filter(id=nid).update(**obj.cleaned_data)
            return redirect('/class_list/')
        return render(request,'editclass.html',{'obj':obj,'nid':nid})

编辑班级的html代码

<body>
    <h2>编辑班级</h2>
    <hr>
    <form action="/edit_class/{{ nid }}/" method="post">
        {% csrf_token %}
        <p>
        {{ obj.title }}{{ obj.errors.title.0 }}
        </p>
        <input type="submit" value="提交">
    </form>

学生表功能

功能和班级功能一样,这里就把视图函数全部放到一起

#学生列表
def student_list(request):
    stu_list = models.Student.objects.all()
    return render(request,'studentlist.html',{'stu_list':stu_list})

#添加学生
##创建学生的Form条件验证
class StuForm(Form):
    sname = fields.CharField(min_length=2,max_length=6,label='学生姓名')
    email = fields.EmailField()
    age = fields.IntegerField()
    cls_id = fields.IntegerField(
        widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'))#把班级变成下拉框,这里django会自动给我们记录select的value,不需要我们自己来操心
    )
def add_stu(request):
    if request.method == "GET":
        obj = StuForm()
        return render(request,'addstudent.html',{'obj':obj})
    else:
        obj = StuForm(request.POST)
        if obj.is_valid():
            models.Student.objects.create(**obj.cleaned_data)
            return redirect('/student_list/')
        return render(request,'addstudent.html',{'obj':obj})

#编辑学生
def edit_stu(request,nid):
    if request.method == "GET":
        row = models.Student.objects.filter(id=nid).values('sname','email','age','cls_id').first()#让他变成字典的类型可以传参到下面的form里面,因为我们知道表达里面的data和initial后面都是一个字典类型
        obj = StuForm(row)
        return render(request,'editstudent.html',{'obj':obj,'nid':nid})
    else:
        obj = StuForm(request.POST)
        if obj.is_valid():
            models.Student.objects.filter(id=nid).update(**obj.cleaned_data)#参数我一个字典
            return redirect('/student_list/')
        return render(request,'editstudent.html',{'obj':obj,'nid':nid})

学生列表html代码

    <h2>学生列表</h2>
    <hr>
    <a href="/add_stu/">添加学生</a>
    <ul>
        {% for stu in stu_list %}
            <li>{{ stu.sname }}-{{ stu.age }}-{{ stu.email }}-{{ stu.cls_id }}<a href="/edit_stu/{{ stu.id }}/">编辑</a></li>
        {% endfor %}

    </ul>

增加学生html代码

<form action="/add_stu/" method="post" novalidate>
    {% csrf_token %}
    <h2>添加学生</h2>
    <hr>
    <p>{{ obj.sname }}{{ obj.errors.sname.0 }}</p>
    <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
    <p>{{ obj.age }}{{ obj.errors.age.0 }}</p>
    <p>{{ obj.cls_id }}{{ obj.errors.cls_id.0 }}</p>
    <input type="submit" value="提交">
</form>

编辑学生html代码

<h2>编辑学生信息</h2>
<hr>
<form action="/edit_stu/{{ nid }}" method="post">
    {% csrf_token %}
    <p>{{ obj.sname }}</p>
    <p>{{ obj.email }}</p>
    <p>{{ obj.age }}</p>
    <p>{{ obj.cls_id }}</p>
    <input type="submit" value="提交">
</form>

下面是多对多的操作

添加老师

老师列表html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>老师列表</title>
</head>
<body>
<hr>
<a href="/add_teacher/">添加老师</a>
<hr>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>老师姓名</th>
                <th>任教班级</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                {% for foo in teach_list %}
                    <td>{{ foo.id }}</td>
                    <td>{{ foo.tname }}</td>
                    <td>{{ foo.c2t.all }}</td>
                {% endfor %}

            </tr>
        </tbody>
    </table>
</body>
</html>

添加老师html代码

<form action="/add_teacher/" method="post">
    {% csrf_token %}
    <p>姓名:{{ obj.tname }}</p>
    <p>任教班级:{{ obj.xx }}</p>
    <input type="submit" value="提交">
</form>

添加老师和老师列表逻辑代码

def teacher_list(request):
    if request.method == "GET":
        teach_list = models.Teacher.objects.all()
        return render(request,'teacher.html',{'teach_list':teach_list})

class TeachForm(Form):
    tname = fields.CharField(min_length=2)
    xx = fields.CharField(
        widget=widgets.SelectMultiple(choices=models.Classes.objects.values_list('id','title'))
    )
    #上面这个显示的结果是可以多选,但是clean_data的数据都是字符串格式,对于取值是很麻烦的
        要想使用正确的多选框要使用下面的方式
            xx = fields.MultipleChoiceField(
        choices=models.Classes.objects.values_list('id', 'title'),
        widget=widgets.SelectMultiple()
    )

    # xx = fields.CharField(
    #     widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'))
    # )#这样显示出来的是一个单选的下拉框格式

def add_teacher(request):
    if request.method == "GET":
        obj = TeachForm()
        return render(request,'addteacher.html',{'obj':obj})
     else:
        obj = TeachForm(request.POST)
        if obj.is_valid():
            # models.Teacher.objects.create(tname=obj.cleaned_data['tname'])第一种方法,但是对于字段多来说不好用
            niubi = obj.cleaned_data.pop('xx')
            row = models.Teacher.objects.create(**obj.cleaned_data)
            row.c2t.add(*niubi)
            return redirect('/teacher/')
        return render(request,'addteacher.html',{'obj':obj})

djagon实战form数据库等操作

urls故障

https://docs.djangoproject.com/en/2.0/intro/tutorial02/

django2.0版本主要更新了urls,url变成了path,在使用r'^edit_class/(\d+)/', views.edit_class), 路由的时候,发现报错404不能找到路径。经过查看文档发现2.0v版本以后url变成了path,而path的规则变成了如下:

    <ul>
        {% for cls_list in obj %}
            <li>{{ cls_list.title }}<a href="/edit_class/{{ cls_list.id }}/">编辑</a></li>
        {% endfor %}
    </ul>
from django.urls import path
from . import views
urlpatterns = [
     path('edit_class/<int:nid>/', views.edit_class),
]

这里把传入的参数会变成指定的,不需要(\d+/)了,

转换格式类型

说明

Str
匹配除分隔符(/)外的非空字符,默认类型<year>等价于<str:year>

Int

匹配0和正整数

Slug

匹配字母、数字、横杠、下划线组成的字符串,str的子集

Uuid

匹配格式化的UUID,如075194d3-6885-417e-a8a8-6c931e272f00

path

匹配任何非空字符串,包括路径分隔符,是全集

单选框的方法

djagon实战form数据库等操作