day63 django-模板语言
我们的功能是需要解耦的,从开始就一直在强调这一点,所以我们的函数需要另外放到一个单独的文件里面,一般都是放到views文件里面,views叫做视图,一般术语叫做视图函数,用来进行各种逻辑判断的,需要一个功能的时候就去写一段逻辑代码块,都是存放到这里的,所谓的视图就是既视感,我们写到这里的都是可以执行然后看到功能的效果的,而功能和需求是随时会变动的,所以这里的函数都是根据需求随时满足的,
而我们的tool文件夹则不一样,首先声明一下我们的tool文件夹[tool这个名字是自定义的,没有规律按照个人洗好即可,你要能够分辨出来它是干什么的就行]是python-package格式的,它创建好之后会有一个自带的init文件,里面是空的,我们自己在里面新建py文件就好,我们的封装好的函数都是放在那里面的,所谓的封装好的就是类似于模块一样的,那些功能是会被反复的调用的,所以我们为了节省代码,所以就把他们都单独拎出来了,写成函数,用的时候引用就好了.
我们来整理一下我们的django的一些语法,专用术语叫做模板语言:
我们都学了这几个模板语言:
在django的模板语言里面设置变量,用with标签:{%with%} {%endwith%},如下所示,我下面设置的变量是字符串。
{% with morning_opt="01" %} {% endwith %}
{# 这是注释 #}
{{这是放变量名}}
还有循环,我们的这个循环就类似于我们的for循环,不过他是有开始和结束的
{% for i in p%}
{{forloop.counter}} # 这里我们是要对循环的元素进行排序,
{{forloop.last}}
{{forloop.first}}
默认是从1开始的这样写就是从0开始了{{forloop.counter0}}
{{ i }} # 这里的i如果是字典的话,我们的语法是支持使用{{i.name}}
{% endfor %}
还有if判断:
{%if student.cid == class.id%}
<option selected value="{{ class.id }}">{{ class.cname }}</option>
{%else%}
<option value="{{ class.id }}">{{ class.cname }}</option>
{%endif%}
我们使用django的时候需要连接数据库,在连接库的时候,我们需要传一些参数,然后这些参数,我们每次写函数的时候都会重复的去写它,这样的话反复去连接数据库的过程本身就是有极大的优化空间的,鉴于此,我们使用了面向对象编程,
下面是代码:
import pymysql DB_CONFIG = { "host": "localhost", "user": "root", "password": "123", "database": "book_list", "charset": "utf8" } # 指定单条语句 def update(sql, arg=None): # 取数据库里面学生表插入一条数据 conn = pymysql.connect( host=DB_CONFIG["host"], user=DB_CONFIG['user'], password=DB_CONFIG['password'], database=DB_CONFIG['database'], charset=DB_CONFIG['charset'], ) # 指定输出的结果类型是字典 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute(sql, arg) conn.commit() cursor.close() conn.close() # 查询单个数据记录 def get_one(sql, arg=None): conn = pymysql.connect( host=DB_CONFIG["host"], user=DB_CONFIG["user"], password=DB_CONFIG["password"], database=DB_CONFIG["database"], charset=DB_CONFIG["charset"] ) # 指定输出的结果是类型是字典 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute(sql, arg) ret = cursor.fetchone() cursor.close() conn.close() return ret # 查询多条数据 def get_list(sql, arg=None): conn = pymysql.connect( host=DB_CONFIG["host"], user=DB_CONFIG["user"], password=DB_CONFIG["password"], database=DB_CONFIG["database"], charset=DB_CONFIG["charset"] ) cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute(sql) ret = cursor.fetchall() cursor.close() conn.close() return ret def magic(data_o): tmp = {} for i in data_o: if i["id"] not in tmp: tmp[i["id"]] = {"id": i["id"], "tname": i["tname"], "cname": [i["cname"]],} else: # 我们的这个else是要跟上面的if平级的,不能够写到for那一级,否则得到的结果会出问题, # 它就显示的都是单个的字母,而不是完整的单词 tmp[i["id"]]["cname"].append(i["cname"]) data = list(tmp.values()) return data def create(sql, arg=None): conn = pymysql.connect( host=DB_CONFIG["host"], user=DB_CONFIG["user"], password=DB_CONFIG["password"], database=DB_CONFIG["database"], charset=DB_CONFIG["charset"] ) cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute(sql, arg) the_id = cursor.lastrowid # 这里的lastrowid是得到最后一个数据, 提交之后,获取刚插入的数据的ID conn.commit() cursor.close() conn.close() return the_id # 批量执行单挑语句 def pl_modify(sql, arg=None): conn = pymysql.connect( host=DB_CONFIG["host"], user=DB_CONFIG["user"], password=DB_CONFIG["password"], database=DB_CONFIG["database"], charset=DB_CONFIG["charset"] ) cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.executemany(sql, arg) # 这里我们需要执行多条操作,使用executemany来完成 conn.commit() cursor.close() conn.close() # 接下来我们使用比较高级一点的用法,面向对象去把相同的代码封装到一个类里面, # 然后把不同的方法作为类里面的函数去使用,可以节省代码 class DBHelper(): def __init__(self): self.conn = None self.cursor = None self.connect() def connect(self): self.conn = pymysql.connect( host=DB_CONFIG["host"], user=DB_CONFIG["user"], password=DB_CONFIG["password"], database=DB_CONFIG["database"], charset=DB_CONFIG["charset"] ) self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor) # 指定单条语句 def update(self, sql, arg=None): # 取到数据库里面的学生表插入一条新数据 # 指定输出的结果类型是字典 self.cursor.execute(sql, arg) self.conn.commit() # 批量执行单条语句 def pl_modify(self, sql, arg=None): self.cursor.executemany(sql, arg) self.conn.commit() # 执行单条语句,同时获取最后插入的那条数据 def create(self, sql, arg=None): self.cursor.execute(sql, arg) the_id = self.cursor.lastrowid self.conn.commit() return the_id # 查询单个数据 def get_one(self, sql, arg=None): self.cursor.execute(sql, arg) ret = self.cursor.fetchone() return ret # 查询多个数据 def get_list(self, sql, arg=None): self.cursor.execute(sql, arg) ret = self.cursor.fetchall() return ret def close(self): self.cursor.close() self.conn.close() # 进入with语句自动执行,自动进入自动退出,我们使用with语法打开一个文件的时候是不需要另外关闭文件的,它本身自带关闭功能 # with 就是一个类,它底层就是一个类,我们使用with的时候用它本身就可以实例化出来一个对象,我们使用with语法的时候, # as后面的就是我们的实例化的对象,这个对象是可以自定义的,我们首先是需要在这里定义enter和exit使用方法,才能使用with方法, # 否则就需要使用传统方法,在下面使用类来实例化一个对象 def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.close() # db = DBHelper()
如下是我们的例子:我们把上面的类和类里面封装的函数方法都使用到了,
# 展示所有的班级列表 def class_form(request): # 这个函数是展示所有的班级列表 # 1.去数据库里面取出数据 # conn = pymysql.connect( # host="localhost", # user="root", # password="123", # database="book_list", # charset="utf8") # 指定输出的结果类型是字典这里的DictCursor是django里面自带的封装好的功能, # 我们把它记下来然后用的时候想到它就可以完成我们需要的工作 # cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # cursor=conn.cursor() # 这样写就是得到元祖的结果, # 我们需要把它转换成字典,然后我们才能通过字典的特性键对值的方式去取值 sql = "select id,cname from class order by id;" # cursor.execute(sql) # ret = cursor.fetchall() with db_master.DBHelper() as qw: ret = qw.get_list(sql) # cursor.close() # conn.close() print(ret) # 2 用数据去填充HTML页面 这里需要去看视频理解一下---->已经理解过了 # 这里是key和value的方式,{key:value},class_form是变量名, # 我们这里写的变量名class_form需要和HTML里面的for i in class_form对应上, # 这两个是必须要保持一致的,后面的ret是我们上面mysql语句运行之后的得到的结果赋值给这个变量了 return render(request, 'class-form.html', {"class_form": ret}) # , {"class-form": ret}这里的变量命名不够规范所以会报错 # 添加班级 def add_class(request): if request.method == "POST": class_name = request.POST.get("cname") # 因为我们的id是自增的所以我们在这里只需要增加cname就好了,只需要定义这一个变量就够了 # 1.去数据库里面取出数据 # 指定输出的结果类型是字典这里的DictCursor是django里面自带的封装好的功能, # 我们把它记下来然后用的时候想到它就可以完成我们需要的工作 sql = "insert into class (cname) VALUES (%s);" with db_master.DBHelper() as ff: ff.update(sql, [class_name]) return redirect("/class_form/") return render(request, 'add-class.html') # 删除课程 def delete_class(request): # 根据班级id删除 # 班级id从数据库里面取出来 print(request.GET) class_id = request.GET.get("class_id") print(class_id) # 去到数据库里面删除 sql = "delete from class where id=%s;" # 对数据库进行改变需要提交操作 with db_master.DBHelper() as obj: obj.update(sql,[class_id]) # return HttpResponse(class_id) return redirect('/class_form/') # 修改课程 def edit_class(request): if request.method == "POST": class_id = request.POST.get("id") class_name = request.POST.get("cname") # 去数据库里面更新 sql = "update class set cname=%s where id=%s;" with db_master.DBHelper() as fh: fh.update(sql, [class_name, class_id]) return redirect('/class_form/') # 取到被编辑的班级id class_id = request.GET.get("class_id") # 去数据库里面查询当前班级的信息 sql = "select id,cname from class where id=%s;" ret = db_master.get_one(sql, [class_id]) print(ret) return render(request, "edit-class.html", {"class_info": ret})
我们在这里加入几个例子,看不懂没有关系的,能有个印象就行:
pymql语句模糊查询的时候的拼接注意事项,
def search_teacher(request): print(request.body) print("="*120) # 拿到搜索词 search_str = request.POST.get("search_str") # 去到数据库里面模糊查找 sql = "SELECT teacher.id, tname, cname from teacher " \ "LEFT JOIN class_2_teacher on teacher.id = " \ "class_2_teacher.tid LEFT JOIN class ON " \ "class_2_teacher.cid = class.id WHERE tname LIKE %s;" with db_master.DBHelper() as eq: # 这一段的重点是我们的字符串拼接的时候是在pymysql里面,sql语句查询的时候模糊查找使用的like,我们在拼接的时候不是在sql语句查询的时候完成的,而是在我们执行sql语句的时候,传参里面把它作为参数传进去,然后进行拼接,我们在拼接的时候使用的是format方法去拼接的,如下所示: teacher_list_o = eq.get_list(sql, ["{}%".format(search_str), ]) teacher_lt = db_master.magic(teacher_list_o) print(teacher_lt) return render(request, "teacher-form.html", {"teacher_form": teacher_lt})
django框架搭建,连接数据库和前端把数据库页面显示出来,
教师表格:(由于django框架的搭建需要太多的文件了,我们不能够把那么多的文件都拿出来贴过来,贴过来也不能够直接执行,所以就只是有一些简单的views里面的函数体,函数体里面涉及到的模块都没有贴过来,就是体会一些吧,然后函数体里面都是有注释的,)
def teacher_form(request): # 写sql语句 sql = "select teacher.id, tname, cname from teacher left join class_2_teacher on" \ " teacher.id = class_2_teacher.tid LEFT JOIN class on class_2_teacher.cid = class.id;" ret = db_master.get_list(sql) print(ret) print("="*120) teacher_list = db_master.magic(ret) print(teacher_list) print("="*100) return render(request, "teacher-form.html", {"teacher_form": teacher_list}) def add_teacher(request): if request.method == "POST": teacher_name = request.POST.get("tname") # 我们需要在这里把老师所授课程的内容信息填充到跟tname一样的选择框里面, # 这样我们在添加老师信息的时候可以把老师的名字和所授课程一同添加上去,这样才完成了完整的功能实现 cid_list = request.POST.getlist("cid") # 这里的getlist是得到一个列表, # 我们的老师所授课程是可以支持多选的,所以并不是一个单独的值,所以需要用到getlist print(teacher_name, cid_list) print("="*120) # 取到teacher表格里面插入数据 sql = "insert into teacher (tname) VALUES (%s);" # 这里我们得到了最新添加的那一条数据的id,把它赋值给一个新的变量 new_teacher_id = db_master.create(sql, teacher_name) # 更新class_2_teacher表格 sql1 = "insert into class_2_teacher(cid, tid) VALUES (%s, %s);" # for cid in cid_list: # 我们这里是使用for循环去遍历每一个数据,然后把他们依次添加到页面上去, # db_master.update(sql1, [cid, new_teacher_id]) # 这里我们写的是一个列表推倒式,循环遍历每一条数据,我们循环遍历的是cid_list,这个cid_list是我们 # 添加老师数据的时候需要添加的老师所授课程的选项,而老师所授的课程是可以多选的,所以是一个列表的数据类型 data = [(i, new_teacher_id) for i in cid_list] # 我们的new_teacher_id是我们最新添加的老师的信息, # 老师的信息是只有名字的,我们的老师id是设计的自增加,所以我们需要到数据库里面获取到老师的id,然后放到这里来填充上面的sql语句 # 我们通过函数create已经获取到了tid,并把它赋值给一个变量,new_teacher_id,它就是tid,它写到我们的列表推倒式的后一个数据里面, # 我们传参是需要按照位置对应着来的,而cid就是列表里面循环的那个数据, # 我们把上面的那个sql语句占位符所需要的参数单独拿出来写到一个列表推倒式里面去, # 然后赋值给一个变量,这样我们就可以把它传入到我们下面需要执行的函数里面去了, # db_master.update(sql, [teacher_name]) # db_master.pl_modify(sql1, data) # 这是执行我们的列表推倒式的结果,这里的data是我们的批量执行语句的参数, # 就是上面的列表推倒式所赋值给的那个变量 with db_master.DBHelper() as db: # 我们在这里实例化出来了一个对象,它的作用就是我们可以使用到类里面的那些用法 db.pl_modify(sql1, data) return redirect("/teacher_form/") sql2 = "select id,cname from class;" class_list = db_master.get_list(sql2) return render(request, "add-teacher.html", {"class_form": class_list})
展示讲师表格信息:
# 展示所有的讲师列表 def teacher_form(request): # 写sql语句 sql = "select teacher.id, tname, cname from teacher left join class_2_teacher on" \ " teacher.id = class_2_teacher.tid LEFT JOIN class on class_2_teacher.cid = class.id;" ret = db_master.get_list(sql) print(ret) print("="*120) teacher_list = db_master.magic(ret) print(teacher_list) print("="*100) return render(request, "teacher-form.html", {"teacher_form": teacher_list})
增加讲师表格信息:
def add_teacher(request): if request.method == "POST": teacher_name = request.POST.get("tname") # 我们需要在这里把老师所授课程的内容信息填充到跟tname一样的选择框里面, # 这样我们在添加老师信息的时候可以把老师的名字和所授课程一同添加上去,这样才完成了完整的功能实现 cid_list = request.POST.getlist("cid") # 这里的getlist是得到一个列表, # 我们的老师所授课程是可以支持多选的,所以并不是一个单独的值,所以需要用到getlist print(teacher_name, cid_list) print("="*120) # 取到teacher表格里面插入数据 sql = "insert into teacher (tname) VALUES (%s);" # 这里我们得到了最新添加的那一条数据的id,把它赋值给一个新的变量 new_teacher_id = db_master.create(sql, teacher_name) # 更新class_2_teacher表格 sql1 = "insert into class_2_teacher(cid, tid) VALUES (%s, %s);" # for cid in cid_list: # 我们这里是使用for循环去遍历每一个数据,然后把他们依次添加到页面上去, # db_master.update(sql1, [cid, new_teacher_id]) # 这里我们写的是一个列表推倒式,循环遍历每一条数据,我们循环遍历的是cid_list,这个cid_list是我们 # 添加老师数据的时候需要添加的老师所授课程的选项,而老师所授的课程是可以多选的,所以是一个列表的数据类型 data = [(i, new_teacher_id) for i in cid_list] # 我们的new_teacher_id是我们最新添加的老师的信息, # 老师的信息是只有名字的,我们的老师id是设计的自增加,所以我们需要到数据库里面获取到老师的id,然后放到这里来填充上面的sql语句 # 我们通过函数create已经获取到了tid,并把它赋值给一个变量,new_teacher_id,它就是tid,它写到我们的列表推倒式的后一个数据里面, # 我们传参是需要按照位置对应着来的,而cid就是列表里面循环的那个数据, # 我们把上面的那个sql语句占位符所需要的参数单独拿出来写到一个列表推倒式里面去, # 然后赋值给一个变量,这样我们就可以把它传入到我们下面需要执行的函数里面去了, # db_master.update(sql, [teacher_name]) # db_master.pl_modify(sql1, data) # 这是执行我们的列表推倒式的结果,这里的data是我们的批量执行语句的参数, # 就是上面的列表推倒式所赋值给的那个变量 with db_master.DBHelper() as db: # 我们在这里实例化出来了一个对象,它的作用就是我们可以使用到类里面的那些用法 db.pl_modify(sql1, data) return redirect("/teacher_form/") sql2 = "select id,cname from class;" class_list = db_master.get_list(sql2) return render(request, "add-teacher.html", {"class_form": class_list})
删除讲师表格信息:
def delete_teacher(request): # 根据老师id删除 # 讲师id从数据库里面取出来 print(request.GET) teacher_id = request.GET.get("teacher_id") print(teacher_id) # 去到数据库里面删除 sql = "delete from teacher where id=%s;" # 我们这里的%s是占位符,这里的占位符是为了动态传参, # 我们的程序不能够写死了,需要灵活,需要足够的包容性,所以需要在这里写上一个占位符,但是我们的sql语句这样一来就不够完整了, # 所以在执行的时候需要把占位符里面的缺失的那一块补齐,这样才能够拼凑出完整的sql语句, # 然而我们补齐的那部分就是我们上面定义的变量,那个变量的作用是存放我们取出想要的数据用的, db_master.update(sql, [teacher_id]) # return HttpResponse(class_id) return redirect("/teacher_form/")
修改讲师表格信息:{这一段是最复杂的,我们的注释是比代码本身还要多的,我们的讲师表格是有一个外键,就是我们的课程表格里面的class,所以我们修改的时候一方面需要把我本身里面的字段拿出来还需要把我们的外键的字段拿出来,然后我们修改的时候不仅仅是修改了我们本身的信息还有我们的外键的字段信息都会需要跟着有相应的调整,这里面牵扯到的sql语句还有逻辑判断还有前端的页面显示等等都需要做出相应的调整,而且修改的时候是有很多种情况的,我们这里就采用简单粗暴的方式把原有信息统统删除掉然后我们再一一更新,这样就好了,}
def edit_teacher(request): if request.method == "POST": teacher_id = request.POST.get("tid") teacher_name = request.POST.get("tname") class_li = request.POST.getlist("cid") # print(teacher_id, teacher_name, class_li) # 这里可以拿到数据,但是仅仅在后端拿到了,并没有渲染到前端啊, # print("="*150) sq = "update teacher set tname=%s where id=%s;" with db_master.DBHelper() as ve: ve.update(sq, [teacher_name, teacher_id]) # print(the_id) sql_del = "delete from class_2_teacher where tid=%s;" sql_add = "insert into class_2_teacher (cid, tid) VALUES (%s, %s);" # sq1 = "update class_2_teacher set cid=%s where tid=%s;" # 我们不能够直接在这里更新,需要考虑到多种情况,要先把数据都删掉然后再增加,才可以达到效果 data1 = [(i, teacher_id) for i in class_li] with db_master.DBHelper()as fg: fg.update(sql_del, [teacher_id]) # 先删除 rel = fg.pl_modify(sql_add, data1) # 再增加 return redirect("/teacher_form/") # 这里我们把数据更新之后就回到了我们的展示表格的页面, # 但是返回之后需要得到把数据替换掉之后的结果,这里的代码是没有办法去是现这一步的 # 所以我们需要接着去写代码实现接下来的功能, # 去拿到被编辑的teacher的id teacher_id = request.GET.get("teacher_id") # 去数据库里面查询当前讲师的信息 sql = "select id, cname from class;" # 查询老师的信息,老师的id,tname还有授课班级的cid, sql2 = "select teacher.id, tname,cid from teacher left join" \ " class_2_teacher on teacher.id=class_2_teacher.tid where tid=%s;" with db_master.DBHelper() as fl: class_l = fl.get_list(sql) teacher_info_o = fl.get_list(sql2, [teacher_id]) # 这里我们虽然是把fetchone改成了fetchall,看起来反正我的sql语句是得到一个结果根据我的语法是这样的,如果是在sql里面的话结果是一样的 # 但是我们的程序是无法识别的,它只能知道你的fetchall就是得到多个结果,它只能看到你的fetchall,并不能根据fetchall倒推出你的sql语句是得到的一个结果而不是多个,所以我们不能够改成fetchall去写 # 我们的fetchall系统识别到它是得到多个结果的,所以它无法确定把哪个结果给你放到输入框里面显示出来,所以就直接选择的简单粗暴的方式不去显示了,这就是它的解决方案,所以你看,我们的计算机甚至都不会拐弯,它一点都不够智能, # 所以我们必须要了解每一个环节是什么意思,甚至我们的每一个变量都需要我们去理解为什么这里需要使用它而不是它,不然自己随便乱改就不会得到预期的效果,这是无可厚非的, # 如果执意要改的话,我们只能够花掉更多的时间去一点点找到错处然后去调试,直至你彻底理解了那些细节, # print(res) print(teacher_info_o) print("="*120) teacher_info = db_master.magic2(teacher_info_o) print(teacher_info) # sql2 = "select id, cname from class;" # with db_master.DBHelper() as li: # 这里我们挪到上面去了,两个sql语句一同执行 # rels = li.get_list(sql2) return render(request, "edit-teacher.html", {"class_form": class_l, "class_2_teacher": teacher_info}) # 这里的变量名我们采坑都不止一次了,需要长点记性了,哪个变量是需要对应哪里的都需要对上号字典里面的key是HTML页面里面的变量,value是我们views函数里面得到的值