Django框架
pip3 install django 命令:
# 创建Django程序
django-admin startproject mysite
# 进入程序目录
cd mysite
# 启动socket服务端,等待用户发送请求
python manage.py runserver 127.0.0.1:8080
# 创建app
python manage.py starapp app01 pycharm
1. 创建project
2. 配置:
- 模板路径
template目录
TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'template')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],},},]
- 静态文件路径
static目录
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
) 3. 额外配置
MIDDLEWARE = [#'django.middleware.csrf.CsrfViewMiddleware',]
Web框架本质
浏览器(socket客户端)
2. 发送IP和端口 http://www.baidu.com:80/index/
GET:
请求头 http1.1 /index?p=123
请求体(无内容)
POST:
请求头 http1.1 /index?p=123
请求体 ...
4. 接收响应
普通响应:页面直接显示
重定向响应:再一起一次Http请求 服务器(socket服务端)
1. 启动并监听ip和端口,等待用户连接
3. 接收请求进行处理,并返回
普通返回:
响应头:
Access-Control-Allow-Origin:* 响应体:
<html>...</html>
重定向返回:
响应头:
LOCATION: 'http://www.baidu.com'
Access-Control-Allow-Origin:*
路由系统:
urls.py
from django.urls import path,re_path
from app01 import views urlpatterns = [
# path('admin/', admin.site.urls),
path('index/', views.index),
re_path('^edit/(\w+)/$',views.edit1), # 加上 $
re_path('^edit/(\w+).html$',views.edit2),
re_path('^edit/(?P<a2>\w+)/(?P<a1>\w+).html$',views.edit3),
# 按参数名传参 # def edit3(request,*args,**kwargs):
# 不要将(\w+)与(?P<a2>\w+)混用
# 如果前面不加结尾符,则不能匹配此url path('index2/', views.index2,name='n2'),
# 给url命名;在函数中通过别名反找到url
re_path('index3/(\w+)', views.index3,name='n3'),
# 可随意生成(\w+)位置的值
re_path('^index4/(?P<a2>\w+)/(?P<a1>\w+).html$', views.index4,name='n4'),
# 可随意生成(?P<a2>\w+)位置的值 re_path('^', default),
# 此规则放最后
# 什么都不输或者输错了,将会被匹配 # def default(request):return HttpResponse('url 错误')
] views.py
def edit(request,a1):
# a1 为re_path('^edit/(\w+)/$')括号中的字符,按位置传参,
# 若url中有2个括号,函数就有request参数和另2个参数
return HttpResponse('...') # 通过别名反找到url,反生成url
from django.urls import reverse
def index2(request):
v = reverse('n2')
return HttpResponse(v) def index3(request,*args):
v = reverse('n3',args=(123,))
# 请求url:index3/3 生成url:index3/123
# 有多少(\w+),args=(,)就写多少个参数
return HttpResponse(v) def index4(request,**kwargs):
v = reverse('n4',kwargs={'a2':666,'a1':777)) # /index4/666/777.html
# 请求url:index3/3 生成url:index3/123
# 有多少(?P<a2>\w+),kwargs={,}就写多少个键值对
return HttpResponse(v) # 若是给url命名,在templates模板中可以直接使用名字{% url 'm1' %}
# path('index10/', views.index10,name='m1'),
# <form method="post" action="{% url 'm1' %}"> # -><form method="post" action="/index10/">
# re_path('index10/(\w+)/', views.index10,name='m2'),
# <form method="post" action="{% url 'm3' 'abc' %}"> # "补位"
url 的常用使用
路由分发:
urls.py分配url到app
from django.urls import path,re_path,include
urlpatterns = [
path('app02/', include('app02.urls')),
path('app01/', include('app01.urls')),
# 只匹配开头,然后交与app01中的urls继续匹配
# 请求url为 http://127.0.0.1:8000/app01/index/
# -> 先匹配到app01 -> app01下的urls中匹配index
] 在app01.urls.py文件下匹配url
from django.urls import path,re_path
from app01 import views urlpatterns = [
path('index/', views.index),
]
路由分发
ORM操作
ORM操作 (Django2.1.8)
Http请求:
url -> 视图(模板+数据)
步骤:
1. 创建数据库
2.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'s4day70db',
'USER': 'root',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': 3306,
}
}
3. __init__文件中
import pymysql
pymysql.install_as_MySQLdb() 4.注册app
INSTALLED_APPS = [app01,] 5. from django.db import models
class UserGroup(models.Model):
title = models.CharField(max_length=32) class UserInfo(models.Model):
nid = models.BigAutoField(primary_key=True)
user = models.CharField(max_length=32)
password = models.CharField(max_length=64)
age = models.IntegerField(default=1)
ug = models.ForeignKey('UserGroup',on_delete=models.CASCADE,null=True)
# 联合唯一
class Meta:
unique_together = [
('b','g'),] 6.创建数据表,命令:
python manage.py makemigrations
python manage.py migrate
# 报错django.db.utils.InternalError: (1366, "Incorrect string value: '\\xE8\\x8B\\xB1\\xE8\\xAF\\xAD...' for column 'name' at row 1")
# 解决方法,数据库设置默认编码 default charset=utf8 # orm中,若不手动创建models.AutoField(primary_key=True),则自动创建id列。
# 已经创建好的数据库表,修改后重新在终端执行命令即可修改。
# 在已有列的表中增加列,设置值为空null=True,或者default=''设置默认值。
外键:
UserInfo表中生成外键,列名为 ug_id
ug(对象) 代表UserGroup中的一行数据 增
models.UserGroup.objects.create(title='销售部')
obj = models.UserGroup.objects.create(title='销售部')
print(obj.id) # 返回创建好的数据 obj = models.UserGroup(title='xxx')
obj.save() # 批量插入数据
objs = [
models.UserGroup(name='name-1'),
models.UserGroup(name='name-2'),
]
models.UserGroup.objects.bulk_create(objs,10)
查
# 类->数据库表,对象->数据表行
group_list = models.UserGroup.objects.all() # 获取所有数据
# for row in group_list:
# print(row.id,row.title)
group_list = models.UserGroup.objects.filter(id__gt=1) # filter(筛选条件) QuerySet[obj,obj]
group_list = models.UserGroup.objects.filter(id__gt=1).first() # 取第一个值,obj对象 obj = models.UserInfo.objects.filter(id__gt=1).first()
obj.ug.title
# 含外键表查寻,对象.外键表列名 即可获取主表的值。 models.UserGroup.objects.all().values('id','title') # 字典类型,两列。
models.UserGroup.objects.all().values_list('id','title') # 元组类型,两列。 obj = models.UserGroup.objects.filter(id__gt=1).first()
obj.userinfo_set.all() # obj.userinfo_set.filter(nid=2)对另一张表的列做筛选
# 反向操作,获取已被关联外键项的所有与之关联的数据!? # obj.表名小写_set.all()
for row in obj.userinfo_set.all():
# 获取到的是userinfo 中的数据
print(row.age,row.user) models.UserGroup.objects.all().values('id','title','userinfo__age') # 反向查找,跨表
models.UserInfo.objects.all().values('nid','ug__title',) # 正向查时跨表
models.UserInfo.objects.all().values_list('nid','ug__title',) # 正向查时跨表
# xxx.filter() 也可以跨表,跟value一样。 # 查询主动做连表
models.UserInfo.objects.all().select_related('ug')
# 不做连表,做多次查询
models.UserInfo.objects.all().prefetch_related('ug') user_list = models.UserInfo.objects.all()[page_info.start():page_info.end()] # 分页,获取某段数据 # 排序
models.UserInfo.objects.order_by('nid') # 从大到小
models.UserInfo.objects.order_by('-nid','name') # 从小到大,id重复按name排序 # 分组
from django.db.models import Count,Sum,Min
user_list = models.UserInfo.objects.values('ug_id').annotate(xxx = Count('nif'))
# print(user_list,user_list.query)
# <QuerySet [{'xxx': 10, 'ug_id': 1}]> SELECT `app01_userinfo`.`ug_id`, COUNT
# (`app01_userinfo`.`nid`) AS `xxx` FROM `app01_userinfo` GROUP BY
# `app01_userinfo`.`ug_id` ORDER BY NULL
# user_list = models.UserInfo.objects.values('ug_id').annotate(xxx = Count('nid')).filter(xxx__gt=3)
# 分组后筛选
# <QuerySet [{'xxx': 10, 'ug_id': 1}]> SELECT `app01_userinfo`.`ug_id`, COUNT
# (`app01_userinfo`.`nid`) AS `xxx` FROM `app01_userinfo` GROUP BY
# `app01_userinfo`.`ug_id` HAVING COUNT(`app01_userinfo`.`nid`) > 3 ORDER BY NULL # 其它
models.UserInfo.objects.filter(id__lt=1) # <
models.UserInfo.objects.filter(id__gte=1) # >=
models.UserInfo.objects.filter(id__in=[1,2,3]) # in[1,2,3,]
models.UserInfo.objects.filter(id__range=[1,3])
models.UserInfo.objects.filter(id=1)
models.UserInfo.objects.exclude(id=1) # id !=1 # Q
# 方式一
models.UserInfo.objects.filter(Q(nid=8) | Q(nid__gt=10) & Q(caption='root'))
# 方式二 组合查询
q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 9)) q2 = Q()
q2.connector = 'OR'
q2.children.append(('c1', 1))
q2.children.append(('c1', 10)) con = Q()
con.add(q1, 'AND')
con.add(q2, 'AND')
models.Tb1.objects.filter(con) # extra
# extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
result = models.UserInfo.objects.filter(id__gt=1).extra(
where=['app01_userinfo.id < %s'],
params=[100,],
tables=['app01_usertype'],
order_by=['-app01_userinfo.id'],
select={'uid':1,'sw':"select count(1) from app01_userinfo"}
)
print(result.query)
# SELECT (1) AS "uid", (select count(1) from app01_userinfo) AS "sw", "app01_userinfo"."id", "app01_userinfo"."name", "app01_userinfo"."age", "app01_userinfo"."ut_id" FROM "app01_userinfo" , "app01_usertype" WHERE ("app01_userinfo"."id" > 1 AND (app01_userinfo.id < 100)) ORDER BY ("app01_userinfo".id) DESC # 执行原生SQL
from django.db import connection, connections
cursor = connection.cursor()
# cursor = connections['指定数据库'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
row = cursor.fetchone()
- 原生SQL语句
- raw
result = models.UserInfo.objects.raw('select * from userinfo') 删
models.UserGroup.objects.filter(id=2).delete() # 注意有外键的情况
更新
models.UserGroup.objects.filter(id=2).update(title='公关部')
from django.db.models import F
# F 用来获取原来的值
models.UserInfo.objects.all().update(age = F('age') +1) 反向:别名,不用小写表名做反向操作,而是用别名.all()取数据。
related_name = 'xxx'
user_set ==> xxx
related_query_name = 'xxx'
user_set ==> xxx_set
# CBV
path('login.html',views.Login.as_view()), from django.views import View
class Login(View):
def get(self,request):
return HttpResponse('Login.get')
xss攻击 CSRF
xss攻击
- 慎用 safe和mark_safe
前端:{{ item|safe }}
后端:from django.utils.safestring import mark_safe
tag = mark_safe(tag)
- 非要用,一定要过滤关键字 CSRF
a. 基本应用
form表单中添加
{% csrf_token %} b. 全站禁用
# 'django.middleware.csrf.CsrfViewMiddleware', c. 局部禁用
'django.middleware.csrf.CsrfViewMiddleware', from django.views.decorators.csrf import csrf_exempt @csrf_exempt
def csrf1(request): if request.method == 'GET':
return render(request,'csrf1.html')
else:
return HttpResponse('ok')
d. 局部使用
# 'django.middleware.csrf.CsrfViewMiddleware', from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_protect
def csrf1(request): if request.method == 'GET':
return render(request,'csrf1.html')
else:
return HttpResponse('ok') c. 特殊CBV
from django.views import View
from django.utils.decorators import method_decorator @method_decorator(csrf_protect,name='dispatch')
class Foo(View): def get(self,request):
pass def post(self,request):
pass
PS:CBV中添加装饰器
def wrapper(func):
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner
# 1. 指定方法上添加装饰器 # class Foo(View):
#
# @method_decorator(wrapper)
# def get(self,request):
# pass
#
# def post(self,request):
# pass
# 2. 在类上添加
# @method_decorator(wrapper,name='dispatch')
# class Foo(View):
#
# def get(self,request):
# pass
#
# def post(self,request):
# pass
Ajax提交数据时候,携带CSRF
a. 放置在data中携带 <form method="POST" action="/csrf1.html">
{% csrf_token %}
<input id="user" type="text" name="user" />
<input type="submit" value="提交"/>
<a onclick="submitForm();">Ajax提交</a>
</form>
<script src="/static/jquery-1.12.4.js"></script>
<script>
function submitForm(){
var csrf = $('input[name="csrfmiddlewaretoken"]').val();
var user = $('#user').val();
$.ajax({
url: '/csrf1.html',
type: 'POST',
data: { "user":user,'csrfmiddlewaretoken': csrf},
success:function(arg){
console.log(arg);
}
})
} </script> b. 放在请求头中 <form method="POST" action="/csrf1.html">
{% csrf_token %}
<input id="user" type="text" name="user" />
<input type="submit" value="提交"/>
<a onclick="submitForm();">Ajax提交</a>
</form>
<script src="/static/jquery-1.12.4.js"></script>
<script src="/static/jquery.cookie.js"></script> <script>
function submitForm(){
var token = $.cookie('csrftoken');
var user = $('#user').val();
$.ajax({
url: '/csrf1.html',
type: 'POST',
headers:{'X-CSRFToken': token},
data: { "user":user},
success:function(arg){
console.log(arg);
}
})
}
</script>
模板
# 如果传入函数名,将会自动执行函数并取到值。
{% for a in page_info.pager %}
{{ a|safe }} #xss攻击
{% endfor %} index.html <select name="class_id">
<!-- 循环所有的班级 -->
{% for row in class_list %}
<!-- 如果是当前学生所在班级,则默认选中 -->
{% if row.id == current_student_info.class_id %}
<option selected value="{{ row.id }}">{{ row.title }}</option>
{% else %}
<option value="{{ row.id }}">{{ row.title }}</option>
{% endif %}
{% endfor %}
</select> {% for item in item_list %} <a>{{ item }}</a> {% endfor %}
{{forloop.counter}}
{{forloop.first}}
{{forloop.last}}
{% if ordered_warranty %} {% else %} {% endif %} result = {}
for row in teacher_list:
tid =row['tid']
if tid in result:
result[tid]['titles'].append(row['title'])
else:
result[tid] = {'tid': row['tid'],'name':row['name'],'titles': [row['title'],]}
return render(request,'teacher.html',{'teacher_list':result.values()}) 母版:
<html>
...
{% block s1 %} {%endblock%}
...
{% block s2 %} {%endblock%} </html> 子板:
{% extends "layout.html "%} {% block s1 %} <h1>fff</h1> {%endblock%}
{% block s2 %} <h1>ffffff</h1> {%endblock%} layout.html
{% block x1 %}{%endblock%}
<h1>ff</h1>
{% block x2 %}{%endblock%}
<h1>2</h1>...
{% block x3 %}{%endblock%}
index.html
{%extends 'layout'%} {% block x1 %}dfssssssdfsd{%endblock%} {% block x2 %}dfsdfsd{%endblock%} {% block x3 %}fff{%endblock%} 自定义模板语言函数
创建templatetags目录,在其下创建xxx.py文件
使用特殊方法要先导入:{% load xx %}
xxx.py
from django import template
register = template.Library() @register.filter # 只能有2个参数
def my_func(value,arg):
return value+arg
{{ name|my_func:""}} # 冒号后不能有空格
{%if name |my_func%}
〈h3〉真〈/h3〉
{%else%}
〈h3〉假</h3〉
{%endif%} #register.simple_tag # 可传多个参数
def my_func(value,a1,a2,a3):
return value+a1+a2+a3
{% my_func "a11" "a222" "a333" %} 小组件,可在页面多次加载,可不用{% load xx %}导入
{% include 'pub.html' %}
pub.html
<div>
<h3>特别漂亮的组件</h3>
<div class="title">标题:{{ name}}</div>
<div class="content">内容:{{ name}}</div>
</div>
index.html
<body>{% include 'pub.html' %}
cookie session
Cookie
a. 保存在客户端浏览器上的“键值对”
b. 服务端可以向用户浏览器端写cookie
c. 客户端每次方请求时,会携带cookie去 set_cookie
key,
value='',
max_age=None,
expires=None,
path='/',
domain=None,
secure=False, Https
httponly=False 只能自Http请求中传入,js代码无法获取到 cookie签名:
obj = HttpResponse('...')
obj.set_cookie('k1','v1')
request.COOKIES.get('k1') obj.set_signed_cookie(k1,v1,max_age,salt='ff')
request.get_signed_cookie('k1',salt='ff') session保持会话
Cookie是什么?
保存在客户端浏览器上的键值对
Session是什么?
保存在服务端的数据(本质是键值对)
应用:依赖cookie
作用:保持会话(Web网站) # 登陆成功返回时,在request中设置session键值对后,将通过cookie发送随机字符串
# session值保存在数据库表中的
# 在浏览器请求时,获取浏览器带来的session随机字符串,随后检测是否有这个用户登录 if 登陆成功:
request.session['username']='name1'
request.session['password']='pwd1'
return render()
判断是否登陆
v = request.session.get('username')
if v:return HttpResponse('%s,登陆成功'%v)