前戏
一.http协议
1.url:协议://域名(IP)+端口(80)/路径?参数(a=1&b=2)
2.基于请求响应
3.基于TCP协议
4.请求协议格式
请求首行 请求方式 url(路径?get请求参数) 协议/版本号
请求头 key:value
请求体 数据(只有post请求才会有请求体)
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36
二.Django的下载安装
1.django:pip3 install django == 2.1.1
2.创建Django项目:django-admin.py startproject 项目名称
3.创建应用:python manage.py startapp app名称
4.启动项目:python manage.py runserver IP:PORT
项目名称
--manage.py #启动文件 与项目交互命令
--项目名称
----settings.py:配置信息
----urls:路径与视图函数的映射
----wsgi:封装socket
app01
----models:存放与该app相关的表结构
----view:存放与该app相关的视图函数
正戏
一.url控制器
urls.py:请求路径与视图函数的映射关系
(1)简单使用:通过正则分组获取url中的动态参数
(2)有名分组:给分组起一个名字,实现关键字传参
(3)分 发:把每一个app自己的url分发各自的路由文件
(4)反向解析:不要硬编码url,通过别名解析url
二.视图函数
request(请求对象)
request.method 请求方式
request.path 请求路径
request.POST POST的请求数据,字典格式
request.GET GET的请求数据,字典格式
request.META 请求头
request.get_full_path()
request.is_ajax()
request(响应对象)
三种形式:
1.HttpResponse("字符串")
2.render("页面")
---读取文件字符串
---渲染变量
3.redirect() #重定向
三.模板语法
服务器发送请求:
1.地址栏输入url 默认get方式
2.form表单发请求 可以设置get或post
3.a标签发请求
四.ORM(object relation mapping)
类----------表
类属性-----表字段
类对象-----表记录
数据库的迁移:django会把setting中的INSTALLED_APPS中每一个应用中models对应类创建成数据库中的表
python manage.py makemigrations 同步
python manage.py migrate
新的数据类型:QuerySet [obj1,obj2....]
1.添加记录
#方式1:
book=Book(title="python",price=123,pub_date="2012-12-12",publish="人民出版社") book.save()
#方式2:
book=Book.objects.create(title="python",price=123,pub_date="2012-12-12",publish="人民出版社")
2.查询记录
(1)all(): 调用者:objects管理器 返回queryset
(2)filter(): 调用者:objects管理器 返回queryset
(3)get(): 调用者:objects管理器 返回查询到model对象(注意,查询结果有且只有一个才会执行,否则报错)
(4)first(),last()方法: 调用者:queryset 返回model对象
(5)exclude(): 调用者:objects管理器 返回queryset
(6)order_by(): 由queryset对象调用,返回值是queryset
(7)count: 数数: 由queryset对象调用返回int
(8)reverse(): 由queryset对象调用,返回值是queryset
(9)exists(): 由queryset对象调用,返回布尔值
(10)values()方法: 由queryset对象调用,返回值是queryset
(11)values_list(): 由queryset对象调用,返回值是queryset
(12)distinct(): 由queryset对象调用,返回值是queryset
模糊查询(双下划线)
Book.objects.filter(price__in=[100,200,300]) Book.objects.filter(price__gt=100) Book.objects.filter(price__lt=100) Book.objects.filter(price__range=[100,200]) Book.objects.filter(title__contains="python") Book.objects.filter(title__icontains="python") Book.objects.filter(title__startswith="py") Book.objects.filter(pub_date__year=2012)
3.删除记录
Book.objects.filter(price=100).delete()
4.修改记录
Book.objects.filter(id=edit_book_id).update(price=111)
Book.objects.filter(price=111).update(publish="南京出版社")
五.ORM的多表操作
1.操作记录
一对多:
方式1
publish_obj=Publish.objects.get(nid=1) book_obj=Book.objects.create(title="追风筝的人",publishDate="2012-12-21",price=100,publish=publish_obj)
方式2:
book_obj=Book.objects.create(title="追风筝的人",publishDate="2012-12-21",price=100,publish_id=1)
book_obj.publish:与这本书关联出版社对象
多对多操作:
核心:第三张关系表添加记录
app01_book_author id book_id author_id 1 1 1 2 1 2 3 2 2 autor id name 1 liu 2 wu
book_obj.author.add(1,2)
book_obj.author.remove(1)
book_obj.author.clear()
book_obj.author.set(3) 清空后设置id
book_obj.author.all() 查询与这本书关联的所有queryset的集合
2.基于对象的跨表查询(基于子查询)
正向查询
一对多:
正向查询按字段:book.publish Book----------------------------------->Publish <------------------------------------- 反向查询表名小写_set.all():pub_obj,book_set.all()
多对多:
正向查询字段book.author.all() Book------------------------------------->Author <---------------------------------------- 反向查询按表名小写_set.all():liu.book_set.all()
一对一:
正向查询字段 liu.info Author------------------------------>AuthorInfo <--------------------------------- 反向查询按表名小写 info.author
总结:正向查询按字段;反向查询得到一个对象,按表名小写,可能得到多个对象,按表名小写_set().all()
3.基于双下划线的跨表查询(基于join实现的)
创建表结构
from django.db import models class Book(models.Model): title=models.CharField(max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2) # 出版社可以发布多部书(一对多) publish=models.ForeignKey('Publish') # 一个人可以写多本书,一本书也可以由多个人撰写(多对多) authorList=models.ManyToManyField('Author') class Author(models.Model): name=models.CharField(max_length=32) age=models.IntegerField() addr=models.CharField(max_length=32) tel=models.CharField(max_length=13) class Publish(models.Model): name=models.CharField(max_length=32) addr=models.CharField(max_length=32)
编写views代码,查询实现
def index(request): bookobj = models.Book.objects.all() # 练习1: 查询人民出版社出版过的所有书籍的名字与价格(一对多) # ret = models.Book.objects.filter(publish__name='山西出版社').values_list('title') # ret = models.Publish.objects.filter(name='山西出版社').values_list('book__title','book__authorList__name') # ret = models.Author.objects.filter(book__publish__name='山西出版社').values_list('book__title') # 练习2: 查询egon出过的所有书籍的名字(多对多) # ret = models.Book.objects.filter(authorList__name='alex').values_list('title') # ret =models.Author.objects.filter(name='alex').values_list('book__title') # 练习3: 查询人民出版社出版过的所有书籍的名字以及作者的姓名 # ret = models.Publish.objects.filter(name='机械先驱出版社').values_list('book__title','book__authorList__name') # ret = models.Book.objects.filter(publish__name='机械先驱出版社').values_list('title','authorList__name') # ret = models.Author.objects.filter(book__publish__name='机械先驱出版社').values_list('book__title','name') # 练习4: 手机号以151开头的作者出版过的所有书籍名称以及出版社名称 # ret = models.Author.objects.filter(tel__startswith='158').values_list('book__title','book__publish__name') # ret =models.Publish.objects.filter(book__authorList__tel__startswith='158').values_list('book__title','name') # ret = models.Book.objects.filter(authorList__tel__startswith='158').values_list('publish__name','title') # print(ret) return HttpResponse('OK')
六.Ajax
浏览器向服务端发送请求的形式:
1.地址栏输入url 默认get方式
2.form表单的提交按钮 默认get方式
3.a标签 默认get
4.Ajax特点:
1.异步
2.局部刷新
$.ajax({ url:"/cal/", type:"post", data:{ num1:num1, num2:num2, csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val() }, success:function(response){ console.log(reponse); $("#ret").val(reponse) } })
json数据
------------------------------------- | Python |Json | ===================== | dict |object | ===================== | list,tuple |array | ===================== | str |string | ===================== | int,float |number | ===================== | True |true | ===================== | False |false | ===================== | None |null | --------------------------------------
ContentType
request.POST
request.GET
request.body
http协议请求格式 post url http user_agent:..... accept:........... ContentType:json user=liu&pwd=123 #封装数据格式:application/x-www-form-urlencoded {"user":"liu","pwd":123} #json格式 浏览器------------------------------------>服务器 <------------------------------------ http协议响应格式 发送接送数据给服务器: 发送者Ajax: $.ajax({ url:"/cal/", type:"post", contentType:"json", data:JSON.stringfy({ num1:num1, num2:num2, csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val() }), success:function(response){ console.log(response); $("#ret").val(response) } })
Django服务器:
视图函数:json_dict=json.lodas(request.body.decode("utf8"))
注意:
Django解析:
if contentType:"urlencoded": request.POST=data elif contentType=="formdata": request.FILES=data else: request.POST={}
七.分页器
假如我们有100本数的数据,想要将其分页,一页展示8条数据
创建数据: book_list[] for i in range(100): book=Book(title="book_%s"%i,price=i*i) book_list.append(book) Book.objects.bulk_create(list) 分页器的使用: paginator=Paginator(book_list,8) print(paginator.count) #100 print(paginator.num_pages) #分页数:13 print(paginator.page_range) #range(1,14) page=paginator.page(5) for i in page: print(i) print(page.has_next()) print(page.has_previous()) print(page.next_page_number()) print(page.previous_page_number())
自定义分页
保存搜索条件 保存copy出的数据 QueryDict #request.GET["xxx"]=123 print(type(request.GET)) from django.http.request import QueryDict print(request.GET)
================================================= import copy params=copy.deepcopy(request.GET) params["xxx"]=123 print("params",params) print(params.urlencode()) #"a=1&b=2&xxx=123"
八.cookie与session
cookie:针对每一个服务器都会保存一个key-value结构,类似于{ }
obj=HttpResponse("OK") obj=render("") obj=redirect("") #设置cokkie obj.set_cookie("key","value","max_age=") #获取cookie request.COOKIES.get() #删除 obj.delete_cookie("cookie_key",path="/",domain=name)
session
#设置session request.session["username"]="user" #取出session request.session.get("username") #删除session del request.session["username"] request.session.flush()
用户认证组件
使用django自带的用户表 auth_user 插入记录的命令:python manage.py createsuperuser 1.auth.authenticate(username=user,password=pwd) 2.auth.login(request,user_obj) request.session["user_id"]=user.pk request.user:全局变量,模板,视图直接可以使用 3.auth.logout(request) 4.User.objects.create_user(username=user,password=pwd) 5.#重置密码 user=User.objects.get(username=request.user.username) user.set_password("666") user.save()
九.ModleForm
1.model:
class UserInfo(AbstractUser): tel=models.CharField(max_lenght=32) gender=models.IntegerField(choices((1,"男"),(2,"女")),default=1) liu=UserInfo.objects.get(pk=1) liu.get_gender_display()
2.modelform使用
model.pclass Book(models.Model):
nid=models.AutoField(primary_key=True) title=models.CharField(max_length=32) price=models.DecimalField(maax_digits=8,decimal_places=2) pub_date=models.DateTimeField() publish=models.ForeignKey(to="Publish",on_delete=models.CASCADE) authors=models.ManyToManyField(to="Author") def __str__(self): return self.title
form.py:
#构建modelform class BookModelForm(forms.ModelForm): class Meta: model=Book fields="__all__"
BookModelForm等同于:
class BookForm(forms.Form): title=forms.CharField(max_length=32) price=forms.IntegerField() pub_date=forms.DateField(widget=widgets.TextInput(attrs={"type":"date"})) #publish=forms.ChoiceField(choices=[(1,"AAA"),(2,"BBB")]) publish=forms.ModelChoiceField(queryset=Publish.objects.all()) authors=forms.ModelMultipleChoiceField(queryset=Author.objects.all())
添加书籍逻辑:
def add(request): if method=="GET": form=BookModelForm() return render(request,"add.html",{"form":form}) else: form=BookModelForm(request.POST) if form.is_valid(): form.save() #Book.objects.create(**clean_data) return redirect("/") else: return render(request,,"add.html",{"form":form})
编辑书籍逻辑:
def edit(request,id): edit_obj=Book.objects.get(pk=id) if method=="GET": form=BookModelForm(instance=edit_obj) return render(request,{"form":form}) else: form=BookModelForm(request.POST,instance=edit_obj) if form.is_valid(): form.save() #edit_obj.update(clean_data) return redirect("/") else: return render(request,{"form":form})
十.视图函数
FBV---------function based view
CBV---------class based view
path('index/',Views.index), path('login/',Views.LoginView.as_view()), path('login/',View.as_view.view) #用户访问get请求/login/-------view(request)
十一.自定义过滤器和标签
1.在setting中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
2.在app中创建templatetages模块(模块名只能是templatetags)
3.创建任意 .py文件,如:my_tags.py
from django import template from django.utils.safestring import mark_safe register = template.Library() #register的名字是固定的,不可变的 @register.filter def filter_multi(v1,v2): return v1*v2
4.在使用自定义simple_tag和filter的html文件导入之前创建的 my_tags.py
{% load my_tags %}
5.使用模板中:
#num = 12 {% load my_tags%} {{ num|filter_multi:2 }} #24
总结:
1.修改表结构:在权限表中加入is_menu和icon两个字段用来表示该权限是否是菜单权限
2.登录成功后:注入该用户的权限列表和菜单权限列表注入session中
permission_menu_list = [{},{}]
3.在菜单区域中(side_bar):渲染出菜单链接标签:
{% for item in request.session.permission_menu_list %} <p><a href="{{ item.url }}">{{ item.title }}</a></p> {% enfor %}
4.点击标签加入active样式:
解决思路1:每一个返回模板的视图函数中:
permission_menu_list = request.session.get("permission_menu_list") for item in permission_menu_list: if re.search("^{}$".format(item["url"]),request.path): item["class"] = "active"
解决思路2:引入inclusion_tag方法:
@register.inclusion_tag("rbac/menu.html") def get_menu_styles(request): permission_menu_list = request.session.get("permission_menu_list") for item in permission_menu_list: if re.search("^{}$".format(item["url"]),request.path) item["class"] = "active" return {"permission_menu_list":permission_menu_list}
在layout.html中:
<div calss="menu-body"> {% load web %} {% get_menu_styles request %} </div>
十二.rbac(Role-Based Access Control)的应用
(1)先将 rbac 组件移植到新的项目中
(2)将settings中install_app 中加入"rbac"
(3)将新项目的用户表与rbac的User表一对一关联
(4)数据迁移
(5)在登录成功后引入rbac下的initial_session方法,在登录用户的权限信息存储(注意user对象)
(6)在settings中引入rbac下的权限校验中间件
(7)在项目中的base模板中引入菜单样式,渲染显示