Django
- Django框架之序列化
- FBV&CBV
- FBV:Function Basic View
- /index/ func(request)
- if reqeust.methond = 'GET'
- /index/ func(request)
- CBV: Class Basic View
- /index/ class(object)
- 判断:get请求
- get方法
- post方法
- /index/ class(object)
- FBV对应: 函数。CBV对应: 类
- FBV:Function Basic View
- 自定义分页
-
def hosts(request):
"""
:param request: 请求相关数据。
:return:
"""
current_page = int(request.GET.get('page'))
all_count = models.hosts.objects.all().count()
page_obj = Page(current_page,all_count,'/hosts')
hostList = models.hosts.objects.all()[page_obj.start:page_obj.end]
page_str = page_obj.page_html()
return render(request,'hosts.html',{'hostList':hostList,'page_str':page_str}) -
class Page(object):
def __init__(self,current_page,all_count,base_url,per_page=10, pager_page_count=11):
"""
#分页的初始化
:param current_page: 当前页码
:param per_page: 每页显示数据条数
:param all_count: 数据库中总条数
:param pager_page_count: 页面上最多显示多少个页码
"""
self.base_url = base_url
self.current_page = current_page
self.all_count = all_count
self.per_page = per_page
self.pager_page_count = pager_page_count
pager_count,b = divmod(all_count,per_page)
if b!= 0:
pager_count += 1
self.pager_count = pager_count
half_pager_page_count = int(pager_page_count/2)
self.half_pager_page_count = half_pager_page_count
@property
def start(self):
"""
数据库获取值起始索引
:return:
"""
return (self.current_page -1) * self.per_page
@property
def end(self):
"""
数据库获取值结束索引
:return:
"""
return self.current_page * self.per_page
def page_html(self):
"""
生成HTML总页码
:return:
"""
#如果数据总页码pager_count<11 pager_page_count
if self.pager_count < self.pager_page_count:
pager_start = 1
pager__end = self.pager_count
else:
#数据页码已经超过11
#判断,如果当前页 <= 5 half_page_page_count
if self.current_page <= self.half_pager_page_count:
pager_start = 1
pager_end = self.pager_page_count
else:
# 如果当前页 +5 > 总页码
if (self.current_page + 5) > self.pager_count:
pager_end = self.pager_count
pager_start = self.pager_count - self.pager_page_count + 1
else:
pager_start = self.current_page - self.half_pager_page_count
pager_end = self.current_page + self.half_pager_page_count
page_list = []
if self.current_page <= 1:
prev = '<a href="#">上一页</a>'
else:
prev = '<a href="%s?page=%s">上一页</a>' % (self.base_url,self.current_page - 1,)
page_list.append(prev)
for i in range(pager_start,pager_end + 1):
if self.current_page == i:
tpl = '<a class="active" href="%s?page=%s">%s</a>' % (self.base_url,i, i,)
else:
tpl = '<a href="%s?page=%s">%s</a>' % (self.base_url,i, i,)
page_list.append(tpl)
if self.current_page >= self.pager_count:
nex = '<a href="#">下一页</a>'
else:
nex = '<a href="%s?page=%s">下一页</a>' % (self.base_url,self.current_page + 1)
page_list.append(nex)
page_str = ''.join(page_list)
return page_str
-
- CSRF,跨站请求伪造
- 正常:
- 先GET请求:
- 页面
- 隐藏:input 随机字符串
- POST:
- 数据
- input 随机字符串
- 先GET请求:
- 非法:
- POST
- 数据
- 全局:
- settings.py 文件中的中间件:django.middleware.csrf.CsrfViewMiddleware
- 局部:
- @csrf_protect,装饰器,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
- 使用:
- Form 提交
<form action="/icbc.html" method="POST">
{% csrf_token %}
<input type='text' name='from' />
<input type='text' name='to' />
<input type='text' name='money' />
<input type='submit' value='转账' />
</form> -
Ajax提交
基于请求体
function ajaxSubmit() {
$.ajax({
url: "/icbc.html",
type: 'POST',
data: $('#f1').serialize(),
success:function (arg) {
console.log(arg)
}
})
}
基于请求头:
a. 在cookie中获取csrftoken对应的值 l2kEqQLhR1gH0hh3ioZ1dfxT3iSwjXoKTf7GNFggJZ7E6DROB6k33L7vdqe5lV1v
b. 发送请求时,放在请求头中也可以
function ajaxSubmit() {
$.ajax({
url: "/icbc.html",
type: 'POST',
data: {'k1':'v1','k2':'v2'},
headers: {"X-CSRFToken": $.cookie('csrftoken')},
success:function (arg) {
console.log(arg)
}
})
}
- Form 提交
- 正常:
- Ajax
-
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR,"app01/static") #setting.py 中设置{% load staticfiles %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'dist/css/bootstrap.css' %}">
<script src="{% static 'dist/js/jquery-3.3.1.js' %}"></script>
<script src="{% static 'dist/js/bootstrap.js' %}"></script> - 在线JSON校验格式化工具(BeJSON)
- Ajax 优点:1. 异步交互,2 局部刷新
- Ajax实现:
- jquery(兼容了大多数浏览器)
- 形式1: $.ajax(settings)
- 形式2: $.ajax(url,[settings])
- JS
- jquery(兼容了大多数浏览器)
-
- ORM 表模型
- 注意事项:
- 在 models.py 文件中创建表结构的时候,表的各个字段之间不能用逗号,否则执行:makemigrations和 migrate之后,数据库的表只有一个字段。
class Book(models.Model):
title = models.CharField(max_length=100)
publication_data = models.DateField()
price = models.DecimalField(max_digits=5, decimal_places=2,default=10)
publisher = models.ForeignKey(Publisher,on_delete=models.CASCADE)
- 在 models.py 文件中创建表结构的时候,表的各个字段之间不能用逗号,否则执行:makemigrations和 migrate之后,数据库的表只有一个字段。
- 让ORM接口实现的过程中,在terminal中打印SQL语句
- 在setting.py 文件中添加如下信息
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
- 在setting.py 文件中添加如下信息
- 单表查询
- 单表查询
- 表.objects.all() ---QuerySet 的集合对象 [obj1,obj2] obj: 就是当前操作表的一条记录
- 表.objects.filter() ---QuerySet 的集合对象 [obj1,obj2]
- 表.objects.get() ---- model对象, obj 当前操作表的一条记录
- QuerySet.first() ---model对象 eg:表.objects.all().first() 集合的第一个对象
- QuerySet.last( ) ----model对象 eg:表.objects.all().last()
- 表.objects.values('title','price') ------返回一个特殊的Queryset,运行后得到的并不是一系列的model的实例化对象,而是一个可迭代的字典序列
<QuerySet [{'title': 'python', 'price': Decimal('99.99')}, {'title': 'C#', 'price': Decimal('88.88')}, {'title': '天龙八部', 'price': Decimal('77.88')}, {'title': 'ce': Decimal('66.66')}]>
- 表.objects.exclude() ----包含了与所筛选条件不匹配的对象
- 表.objects.exist() ----包含所筛选的条件就返回True,否则返回False
- 万能的__:
- 格式: 表.objects.filter(字段__keyword)
- 表.objects.filter(id__lt=10,id__gt=1) # 获取id大于1 且 小于10的值
- 表.objects.filter(id__in=[11, 22, 33]) # 获取id 等于11、22、33的数据
- 表.objects.filter(id__range=[11, 33]) #范围 between and
- 关联查询(多表查询) inner join; left join ; right join
- sql:
- 子查询
- select name from dep where id = (select dep_id from emp where name='zhangsan')
- 联表查询
- select dep.name from emp inner join dep on emp_dep_id=dep.id where emp.name='zhangsan'
- 子查询
- 关联查询的两个手段:1.通过对象 2. 通过双下划线 __
- 通过对象
#查询python这本书出版社的联系方式(一对多)
book_obj = Book.objects.get(title='python')
ret = book_obj.publisher.email
#查询Linux这本书所有作者的名字(多对多)
book_obj2 = Book.objects.get(title='jinpingmei')
author_list = book_obj2.auhtors.all()
for author in author_list:
print(author.name) - 通过双下划线__(重点)
# python这本书的价格是多少
# 单表查询
ret = Book.objects.filter(title='python').values('price')
print(ret) #<QuerySet [{'price': Decimal('99.99')}]>
# 多表查询
# 查询python这本书出版社的联系方式
connect = Book.objects.filter(title='python').values('publisher__email') #此处直接用双下划线即可查到publisher下的email
print(connect) #<QuerySet [{'publisher__email': 'sss@aa.com'}]>#查询作者为alex的出过哪些书
#方式一:正向查询:
books = Book.objects.filter(auhtors__name='alex').values('title')
print(books) #<QuerySet [{'book__title': 'C#'}, {'book__title': '天龙八部'}]>
#方式二:反向查询:
books2 = Author.objects.filter(name='alex').values('book__title')
print(books2) #<QuerySet [{'book__title': 'C#'}, {'book__title': '天龙八部'}]>#查询出版了python这本书的出版社名字
#方式一:正向查询:
publish = Book.objects.filter(title='python').values('publisher__name')
print(publish)
#方式二:反向查询:
publish = Publish.objects.filter(book__title='python').values('name')
print(publish)
- 通过对象
- 聚合与分组查询
- SQL:
- 聚合函数 max min count avg sum 对应的ORM函数:aggregate(*args, **kwargs):
-
from django.db.models import Avg,Min,Sum,Max
# 查询Book表中所有书籍j价格的平均值
# sql语句 select AVG(price) from book
ret = Book.objects.all().aggregate(PriceAvg=Avg('price')) # "PriceAvg"是起的别名
print(ret)
return HttpResponse('ok')
-
- 分组函数 group by 字段 对应的ORM函数:annotate(*args, **kwargs)
#分组函数查询
#每一个作者出过书的总价格
ret3 = Book.objects.values('auhtors__name').annotate(Sum('price'))
print(ret3) #<QuerySet [{'auhtors__name': 'alex', 'price__sum': Decimal('166.760000000000')},
# {'auhtors__name': 'egon', 'price__sum': Decimal('188.870000000000')},
# {'auhtors__name': 'oldboy', 'price__sum': Decimal('67')},
# {'auhtors__name': 'yuan', 'price__sum': Decimal('67')}]>
- 聚合函数 max min count avg sum 对应的ORM函数:aggregate(*args, **kwargs):
- SQL:
- F查询和Q查询
- F 使用查询条件的值,专门取对象中某列值的操作
def query3(request):
from django.db.models import F,Q
# 将所有书的价格统一上调¥100
Book.objects.update(price=F('price')+100) - Q 构建搜索条件
- Q对象可以对关键字参数进行封装,从而更好的应用多个查询
- 可以组合使用 &,| 操作符,当一个操作符是用于两个Q对象,它产生一个新的Q对象
- Q对象可以用~操作符放在前面表示否定,也可运行否定与不否定形式的组合
ret = Book.objects.filter(Q(title__startswith='p')|Q(title__startswith='C'))
# 此时 ret 返回的是两个QuerySet的Book对象,如果想输出Book的title,需要在Class Book 下使用str方法
def __str__(self):
return self.title
- F 使用查询条件的值,专门取对象中某列值的操作
- sql:
- 单表查询
- 多对多的添加方法:
-
authors = models.ManyToManyField(Author) #数据库中会自动生成一个多对多的表
#获取作者对象
book_obj1 = Book.objects.filter(title = 'python')[0]
author_obj1 = Author.objects.get(id=1)
author_obj2 = Author.objects.get(id=2)
book_obj1.authors.add(author_obj1,author_obj2) #remove()方法 :删除 #clear() 方法:清空,所有的关联都清空
-
- 一对多添加方法:
-
def addArticle2(request):
# 一对多的添加方法
#方法一: from app01.models import *
# Book.objects.create(id=2,title='Java', publication_data='2019-05-01', price=99.9,
# publisher_id=2)
#方法二:通过 数据表.objects.get()方法:
p1 = Publisher.objects.get(name='中文出版社')
Book.objects.create(id=3,title='C#', publication_data='2020-1-1',price=22.22,
publisher=p1) - objects.get()方法与objects.filter()方法的区别:
- 表.objects.filter():得到的是一个集合对象,比如:[obj1, obj2]
- 表.objects.get(): 得到的是一个确切的对象。
-
- 数据的添加方法:
- Create()方法,Save()方法
# create 方法
Book.objects.create(title='C#',price=88.88)
#save方法
book = Book(title='JAVA',price=77.77)
book.save()
- Create()方法,Save()方法
- 注意事项:
- 数据库与ORM
- django默认支持sqlite,mysql,oracle,postgresql数据库。
- django 默认使用sqlite数据库,默认自带sqlite的数据库驱动,引擎名称:django.db.backends.sqlite3
- mysql 的引擎名称:django.db.backends.mysql
- mysql驱动程序
- MySQLdb(mysql python)
- mysql client
- MySQL
- PymySQL(纯python的mysql驱动程序)
- django settings.py 里面默认使用sqlite数据库,在setting里面有如下设置:
-
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
} - 如果我们要更改数据库,需要更改:
-
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'python_test', #你的数据库名称
'USER': '', #你数据库的用户名
'PASSWORD': '', #你数据库的密码
'HOST': '', # 你的数据库主机,默认是localhost
'PORT': '' , #数据库的端口
}
}
-
- 表与表之间的关系:
- 一对一
- 在外建字段的基础上增加唯一约束
- 一对多
- 外键字段一定在子表(一对多的多的表)中。
- 多对多
- 在第三张表实现。通过两个FOREIGN KEY
- 一对一
-
- django默认支持sqlite,mysql,oracle,postgresql数据库。
- ORM
- python manage.py # 可以查看 manage.py 下的所有命令
- 同步更改数据库或字段
-
python manage.py makemigrations
- python manage.py migrate
-
两个命令的区别:makemigrations这个命令是记录我们对models.py的所有改动,并且将这个改动迁移到migrations这个文件下生成一个文件例如:0001文件,如果你接下来还要进行改动的话可能生成就是另外一个文件不一定都是0001文件,但是这个命令并没有作用到数据库,这个刚刚我们在上面的操作过程之后已经看到了,而当我们执行python manage.py migrate 命令时 这条命令的主要作用就是把这些改动作用到数据库也就是执行migrations里面新改动的迁移文件更新数据库,比如创建数据表,或者增加字段属性
- 另外一个需要注意的是这两个命令默认情况下是作用于全局,也就是对所有最新更改的models或者migrations下面的迁移文件进行对应的操作,如果要想仅仅对部分app进行作用的话 则执行如下命令:
- python manage.py makemigrations appname
- python manage.py migrate appname
-
- 清空数据库:
- python manage.py flush
- 创建超级管理员
- python manage.py createsuperuser #按照提示输入用户名和对应的密码就好了,邮箱可以留空,用户名和密码必填
- python manage.py changepassword username #修改用户密码
-
def addBook(request):
if request.method == 'POST':
title = request.POST.get('title') # 通过文本框的name字段获取的,而不是id字段。
price = request.POST.get('price')
author = request.POST.get('author')
publish = request.POST.get('publish') - ORM之 插入数据
#添加数据
Book.objects.create(title=title,price=price,author=author,publish=publish) - ORM之 获取表中数据
def index(request):
all_book_list = Book.objects.all(); # Book.object.all 表示获取表中所有的对象,格式为:[<obj1>,<obj2>,<obj3>]
return render(request,'index.html',{'all_book_list':all_book_list}) # all_book_list 作为一个字典参数传回去 - ORM之 展示数据
<div class="outer">
<a href="/addBook/"><button type="button" class="btn btn-primary">添加</button></a>
<table class="table table-striped">
<tr>
<th>编号</th>
<th>书名</th>
<th>价格</th>
<th>作者</th>
<th>出版社</th>
</tr>
{% for book in all_book_list %}
<tr>
<td>{{ book.id }}</td>
<td>{{ book.title }}</td>
<td>{{ book.price }}</td>
<td>{{ book.author }}</td>
<td>{{ book.publish }}</td>
</tr>
{% endfor %}
</table>
</div> - ORM之删除数据
<a href="/delete/?id={{ book.id }}"><button type="button" class="btn btn-danger" >删除</button></a>
def delete(request):
id = request.GET.get('id') # 获取 index.html 里面 删除按钮传过来的 id。
Book.objects.filter(id=id).delete() # 先通过 filter 过滤一下id,然后再执行删除。
return redirect('/index/') # 删除之后,重新返回到首页。 - ORM之编辑数据
- http://www.cnblogs.com/yuanchenqi/articles/6811632.html
Django模板语言 TEPLATE - 定义:将具体数据嵌入到前段模板的语法 HTML代码+逻辑控制代码
- 语法。
- 逻辑控制语法:{{ }} HTML里面嵌入两个大括号,渲染变量
- filter: {{var | 方法:参数}}
- {% %} 渲染标签
- 自定义filter和simpletag:
- 在app中昂创建templatetags模块( 必须的 )
- 创建任意 .py 文件,如:my_tags.py
from django import template
register = template.Library()
@register.filter
def filter_multi(v1, v2):
return v1*v2 - 创建任意 .py 文件,如:my_tags.py 在使用自定义的simple_tag 和 filter 的html文件中导入之前创建的 my_tags.py: {% load my_tags %}
- 使用simple_tag 和 filter:
{% load xxx%} #首行
num = 12
{{ num|filter_multi:2 }} #24 - 总结:
- filter: 只能接受一个参数,但是可以用if等语句
- simpletag:能接受多个参数,但是不可以用if等语句
- extend 模板继承
- 到目前为止,我们的模板范例都只是些零星的HTML片段,但在实际应用中,你将用Django模版系统来创建整个HTML页面,这就带来一个最常见的 Web 开发问题:在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?Django解决此类问题的首选方法是使用一种优雅的策略-模板继承。
- 创建一个共用的html,然后其他页面对它进行继承
<div class="body">
<div class="left">
<a href="/addArticle/">添加文章</a>
</div>
<div class="right">
{% block content %}
{% endblock %}
</div>
</div> -
{% extends 'base.html' %}
{% block content %}
<form action="" method="post">
<p>姓名<input type="text" name="user"></p>
<p>密码<input type="password" name="pwd"></p>
</form>
{% endblock %}
- 控制器(urls.py) -------------: url 与 视图函数的映射关系
-
urlpatterns = [
url( 正则表达式,views视图函数,参数,别名)
]
-
- 安装Django
- pip3 install django
- Mac下安装pip的方法:sudo easy_install pip
- Django的基本命令
- 创建一个django project: django-admin.py startproject mysite
- manage.py (操作项目命令)
- settings(配置文件)
- url(控制器)
- wsgi(封装的socket对象,这个以后我们不用关注)
- 在mysite目录下创建应用,比如blog:python manage.py startapp blog
- Django 流程
- 创建Django项目: django-admin startproject projectname
- 创建应用:python manage.py startapp appname
- 在控制器(urls.py)创建 url 与 视图函数的映射关系(一一对应)
- 创建视图函数,完成逻辑代码
- 从数据库中取出集合对象
- 把数据库变量嵌入到模版进行渲染(render方法)
- 将渲染的html页面返回给客户端。
- 创建一个django project: django-admin.py startproject mysite
- 通过Pycharm 直接新建Django项目,方便快捷
- 启动,在当前目录下的终端中执行:
- python manage.py runserver 8080
- pip3 install django
- Boostrap
- Web前端开发框架
- https://v3.bootcss.com/
- MVC和MTV模式
- Django和MTV模式本质是各组件之间为了保持松耦合关系,Django的MTV分别代表:
- Model(模型):负责业务对象与数据库对象(ORM 与数据库相关的操作)
- Template(模板):负责如何把页面展示给用户(所有HTML界面)
- View(视图):负责业务逻辑,并在适当的时候调用Model和Template(逻辑处理)
- 此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template
- Django和MTV模式本质是各组件之间为了保持松耦合关系,Django的MTV分别代表:
- Cookie
- Cookie是什么
- 保存在客户端浏览器上的键值对 {key:value}
- cookie依附在请求头或响应头中出现
- 发送请求时,会自动携带自己网站的cookie
- 应用:
- 实现登录。
- 投票
- 使用:
- 设置
-
response = redirect('/index')
response.set_cookie('uuuuu',user)
return response - 更多参数
-
set_cookie(self, key, value='', max_age=None(超时时间:秒数), expires=None(超时时间:截止日期,是时间对象), path='/'(生效路径:
访问指定URL时才能读到;默认/,表示全页面都可以得到cookie),domain=None(默认当前域名), secure=False(https的时候,改为:True), httponly=False, samesite=None):
-
- 获取
-
ck = request.COOKIES.get('uuuuu')
-
- 设置
- 登录的时候,密码要加密,后台处理密码的时候,要加密之后存入。登录的时候,也要将密码输入文本进行加密,再与数据库中的数据进行匹配。
-
import hashlib
def encrypt(pwd):
obj = hashlib.md5()
obj.update(pwd.encode('utf-8'))
data = obj.hexdigest()
return data -
def login(request):
if request.method == 'GET':
return render(request,'login.html')
else:
user = request.POST.get('username')
pwd = request.POST.get('password')
pwd = md5.encrypt(pwd)
print(pwd)
obj = models.userInfo.objects.filter(username=user, password=pwd).first()
if obj:
return redirect('/index')
else:
return render(request,'login.html',{'msg':'用户名或密码错误'})
- Cookie是什么
- Session
- session 是什么?
- 保存在服务器端的键值对
- 依赖cookie
- session 是什么?