MVC
M:models数据库相关
V:views 视图逻辑相关
C:controller控制器 url分发 不同的路径找到不同的视图函数
MTV
M:models数据库相关
T:templates模板 ,HTML文件
V:views 视图逻辑相关
+ url控制器 不同的路径找到不同的视图函数
MVVM 后面介绍
项目文件夹下的urls.py文件中的url写法:
from django.conf.urls import url,include
from django.contrib import admin
from app01 import views
urlpatterns = [
# url(r'^admin/', admin.site.urls),
#首页
url(r'^$', views.base),
url(r'^app01/', include('app01.urls')),
url(r'^app02/', include('app02.urls')),
]
app01下urls.py内容写法
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^$', views.app01base),
url(r'^index/', views.index),
]
app02下urls.py内容写法
from django.conf.urls import url
from django.contrib import admin
from app02 import views
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^$', views.app02base),
url(r'^home/', views.home),
]
request.body
:获取post请求提交过来的原始数据request.GET
:获取GET请求提交的数据request.META
:请求头相关信息,就是一个大字典request.path
:/index/ 路径request.path_info
/request.get_full_path()
:/index/?username=dazhuang&password=123 def index(request): #http相关请求信息---封装--HttpRequest对象
if request.method == 'GET':
print(request.body) #获取post请求提交过来的原始数据
print(request.GET) #获取GET请求提交的数据
# print(request.META) # 请求头相关信息,就是一个大字典
print(request.path) #/index/ 路径
print(request.path_info) #/index/ 路径
print(request.get_full_path()) #/index/?username=dazhuang&password=123
return render(request,'index.html')
else:
print(request.body) # b'username=dazhuang'
print(request.POST) #获取POST请求提交的数据
return HttpResponse('男宾三位,拿好手牌!')
响应相关的方法
FBV和CBV
from django.views import View
# FBV:
def home(request):
print('home!!!')
return render(request,'home.html')
# CBV
class LoginView(View):
# 通过请求方法找到自己写的视图类里面对应的方法
def get(self,request):
return render(request,'login2.html')
def post(self,request):
username = request.POST.get('uname')
password = request.POST.get('pwd')
print(username,password)
return HttpResponse('登录成功!')
urls.py
url(r'^login2/', views.LoginView.as_view()),
CBV通过不同的请求方法找到对应的试图类中的方法
def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),self.http_method_not_allowed) #反射
from django.views import View
class LoginView(View):
# GET
def dispatch(self, request, *args, **kwargs):
print('请求来啦')
ret = super().dispatch(request, *args, **kwargs)
print('到点了,走人了')
return ret
def get(self,request):
print('get方法执行了')
return render(request,'login2.html')
def post(self,request):
username = request.POST.get('uname')
password = request.POST.get('pwd')
print(username,password)
return HttpResponse('登录成功!')
FBV加装饰器
def n1(f):
def n2(*args,**kwargs):
print('请求之前')
ret = f(*args,**kwargs)
print('请求之后')
return ret
return n2
@n1
def home(request):
print('home!!!')
return render(request,'home.html')
CBV加装饰器
from django.views import View
from django.utils.decorators import method_decorator
def n1(f):
def n2(*args,**kwargs):
print('请求之前')
ret = f(*args,**kwargs)
print('请求之后')
return ret
return n2
# @method_decorator(n1,name='get') #方式三
class LoginView(View):
# GET
# @method_decorator(n1) #方式2 给所有方法加装饰器
def dispatch(self, request, *args, **kwargs):
# print('请求来啦')
ret = super().dispatch(request, *args, **kwargs)
# print('到点了,走人了')
return ret
# @method_decorator(n1) #方式1
def get(self,request):
print('get方法执行了')
return render(request,'login2.html')
def post(self,request):
username = request.POST.get('uname')
password = request.POST.get('pwd')
print(username,password)
return HttpResponse('登录成功!')
}
{% 逻辑 %}`示例
html代码:
<p>{{ num }}</p>
<p>{{ name }}</p>
<p>{{ namelist.2 }}</p>
<p>{{ d1.age }}</p>
<p>{{ a.kind }}</p>
<p>{{ a.eat }}</p>
views.py代码
def index(request):
num = 100
name = 'shige'
name_list = ['大壮','小壮','壮壮']
d1 = {'name':'大壮','age':73,'hobby':'xuefei+xiangxi'}
class Animal:
def __init__(self):
self.kind = 'dog'
def eat(self):
return 'shi'
a = Animal()
return render(request,'index.html',{'num':num,'name':name,'namelist':name_list,'d1':d1,'a':a})
return render(request,'index.html',locals())
locals() 获取函数内部所有变量的值,并加工成{'变量名':'变量值'....}这样一个字典
在Django的模板语言中,通过使用 过滤器 来改变变量的显示。
{{ value|filter_name:参数 }}
使用管道符"|"来应用过滤器。注意事项:
<p>{{ name_list|length }}p>
<p>{{ xx|default:'啥也没有' }}p>
<p>{{ movesize|filesizeformat }}p>
<p>{{ name|slice:':3' }}p>
<p>{{ now|date:'Y-m-d' }}p>
<p>{{ words|truncatechars:'9' }}p>
<p>{{ words|truncatewords:'3' }}p>
<p>{{ words|cut:'i' }}p>
<p>{{ name_list|join:'+' }}p>
<p>{{ tag|safe }}p>
标签: {% tag %}
:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 (例如{% tag %}
标签 内容{% endtag %}
)。
循环一个字典
{% for key,value in d1.items %}
{{ forloop.counter }}
<li>{{ key }} -- {{ value }}</li>
{% endfor %}
forloop.counter
当前循环的索引值(从1开始),forloop是循环器,通过点来使用功能forloop.counter0
当前循环的索引值(从0开始)forloop.revcounter
当前循环的倒序索引值(从1开始)forloop.revcounter0
当前循环的倒序索引值(从0开始)forloop.first
当前循环是不是第一次循环(布尔值)forloop.last
当前循环是不是最后一次循环(布尔值)forloop.parentloop
本层循环的外层循环的对象,再通过上面的几个属性来显示外层循环的计数等forloop.parentloop.counter
示例
{# {% for key,value in d1.items %}#}
{# {{ forloop.counter }}#}
{# <li>{{ key }} -- {{ value }}li>#}
{# {% endfor %}#}
{# {% for key,value in d1.items %}#}
{# {{ forloop.counter0 }}#}
{# <li>{{ key }} -- {{ value }}li>#}
{# {% endfor %}#}
{# {% for key,value in d1.items %}#}
{# {{ forloop.revcounter }}#}
{# <li>{{ key }} -- {{ value }}li>#}
{# {% endfor %}#}
{# {% for key,value in d1.items %}#}
{# {{ forloop.revcounter0 }}#}
{# <li>{{ key }} -- {{ value }}li>#}
{# {% endfor %}#}
{# {% for key,value in d1.items %}#}
{# {{ forloop.first }}#}
{# <li>{{ key }} -- {{ value }}li>#}
{# {% endfor %}#}
{#<ul>#}
{# {% for dd2 in d2 %}#}
{# <li>#}
{# {% for ddd2 in dd2 %}#}
{# {{ forloop.parentloop.counter }}#}
{# {{ forloop.counter }}#}
{# <a href="">{{ ddd2 }}a>#}
{# {% endfor %}#}
{##}
{# li>#}
{# {% endfor %}#}
{#ul>#}
{#<ul>#}
{# {% for foo in d3 %}#}
{# <li>{{ foo }}li>#}
{# {% empty %}#}
{# <li>查询的内容啥也没有li>#}
{# {% endfor %}#}
{##}
{#ul>#}
{% if num > 100 or num < 0 %}
无效
{% elif num > 80 and num < 100 %}
优秀
{% else %}
凑活吧
{% endif %}
if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断,注意条件两边都有空格。
Django的模板语言不支持连续判断,即不支持以下写法:
{% if a > b > c %} ... {% endif %}
Django的模板语言中属性的优先级大于方法(了解)
def xx(request):
d = {"a": 1, "b": 2, "c": 3, "items": "100"}
return render(request, "xx.html", {"data": d})
with标签
{% with total=business.employees.count %}
{{ total }}
{% endwith %}
{% with business.employees.count as total %}
{{ total }}
{% endwith %}
{% block title %}My amazing site{%/span> endblock %}
{% block content %}{% endblock %}
base.html
, 它定义了一个可以用于两列排版页面的简单HTML骨架。“子模版”的工作是用它们的内容填充空的blocks。
block
标签定义了三个可以被子模版内容填充的block。 block
告诉模版引擎: 子模版可能会覆盖掉模版中的这些位置。
子模版可能看起来是这样的:
{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
{% for entry in blog_entries %}
{{ entry.title }}
{{ entry.body }}
{% endfor %}
{% endblock %}
extends
标签是这里的关键。它告诉模版引擎,这个模版“继承”了另一个模版。当模版系统处理这个模版时,首先,它将定位父模版——在此例中,就是“base.html”。那时,模版引擎将注意到 base.html
中的三个 block
标签,并用子模版中的内容来替换这些block。这里是使用继承的一些提示:
{% extends %}
标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作,模板渲染的时候django都不知道你在干啥。{% block %}
标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。{% block %}
中。{% endblock %}
标签一个 名字 。例如:{% block content %}
...
{% endblock content %}
在大型模版中,这个方法帮你清楚的看到哪一个 {% block %}
标签被关闭了。
block
标签。这些我们后面用到的时候再讲:
1. 在***settings***中的***INSTALLED_APPS***配置当前app,不然django无法找到自定义的***simple_tag***.
2. 在app中创建templatetags模块
注:模块名只能是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
@register.simple_tag #和自定义filter类似,只不过接收更灵活的参数,没有个数限制。
def simple_tag_multi(v1,v2):
return v1 * v2
@register.simple_tag
def my_input(id,arg):
result = "" %(id,arg,)
return mark_safe(result)
{% load my_tags %}
-------------------------------.html
{% load xxx %}
# num=12
{{ num|filter_multi:2 }} #24
{{ num|filter_multi:"[22,333,4444]" }}
{% simple_tag_multi 2 5 %} 参数不限,但不能放在if for语句中
{% simple_tag_multi num 5 %}
注意:filter可以用在if、for等语句后,simple_tag不可以
{% if num|filter_multi:30 > 100 %}
{{ num|filter_multi:30 }}
{% endif %}
inclusion_tag
app应用文件夹中创建一个templatetags文件件,必须是这个名字
templatetags文件夹中创建一个 xx.py文件,文件名字随便起
创建自定义inclusion_tag
@register.inclusion_tag('inclusiontag.html')
def func(v1):
return {'oo':v1}
func的return数据,传给了inclusiontag.html,作为模板渲染的数据,将inclusiontag.html渲染好之后,作为一个组件,生成到调用这个func的地方
使用
{% load xx %}
{% func l1 %}
from django import template
register = template.Library()
@register.inclusion_tag('result.html') #将result.html里面的内容用下面函数的返回值渲染,然后作为一个组件一样,加载到使用这个函数的html文件里面
def show_results(n): #参数可以传多个进来
n = 1 if n < 1 else int(n)
data = ["第{}项".format(i) for i in range(1, n+1)]
return {"data": data}#这里可以穿多个值,和render的感觉是一样的{'data1':data1,'data2':data2....}
# STATIC_URL = '/xxx/' #别名,随便写名字,但是如果你改名字,别忘了前面页面里面如果你是通过/xxx/bootstrap.css的时候,如果这里的别名你改成了/static/的话,你前端页面的路径要改成/static/bootstrap.css。所以我们都是用下面的load static的方式来使用静态文件路径
STATIC_URL = '/static/' #别名
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'jingtaiwenjian'), #注意别忘了写逗号,第二个参数就是项目中你存放静态文件的文件夹名称
]
{% static %}
{% load static %}
{% load static %}
{% load static %}
{% static "images/hi.jpg" as myphoto %}
{% get_static_prefix %}
{% load static %}
或者
{% load static %}
{% get_static_prefix as STATIC_PREFIX %}
/
这个斜杠***必须写上,不然这个请求会拼接当前网页的路径来发送请求,就不能匹配我们的后端路径了orm – Object Relational Mapping
app01 应用下 的models.py文件中写
class UserInfo(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=16,null=True,blank=True,db_index=True)
age = models.IntegerField(default=1,unique=True,choices=((1,'男'),(2,'女'),(3,'二椅子')))
current_date = models.DateField(auto_now=True,auto_now_add=True)
不连接mysql的话,默认连接的是sqlite数据库
# DATABASES = {
'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
# }
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST':'127.0.0.1',
'PORT':3306,
'NAME':'orm01',
'USER':'root',
'PASSWORD':'123',
}
}
import pymysql
pymysql.install_as_MySQLdb()
python manage.py makemigrations
python manage.py migrate
student_obj = models.Student(
name='dazhaung',
age=23,
)
student_obj.save()
new_obj = models.Student.objects.create(name='xiaozhuang2',age=6) #写成 **{'name':'xx'}
print(new_obj) #Student object -- model对象
print(new_obj.name) #点属性,可以获取对应字段的数据
print(new_obj.age)
objs_list = []
for i in range(100,3000000):
obj = models.Student(
name='xiangxixxx',
age = 10,
)
objs_list.append(obj)
models.Student.objects.bulk_create(objs_list)
models.Student.objects.update_or_create(
name='红旭妹妹2',
defaults={
'age':38,
}
)
添加日期数据
import datetime
current_date = datetime.datetime.now()
# print(current_date) #2019-07-19 12:19:26.385654
# 两种方式
# models.Brithday.objects.create(name='B哥',date=current_date)
# models.Brithday.objects.create(name='得港10',date='2000-12-08')
models.Student.objects.get(id=3).delete() #model对象来调用的delete方法
models.Student.objects.filter(name='红旭妹妹').delete() #
models.Student.objects.all().delete() #删除所有
更新 update方法
***model***对象不能调用更新方法 报错信息’Student’ object has no attribute 'update"
只能***queryset***调用,如果
models.Student.objects.get(name='红旭妹妹').update(age=38)
models.Student.objects.filter(name='红旭妹妹').update(age=38)
all_objs = models.Student.objects.all()
#, , ]> -- 类似于列表 -- queryset集合
# for i in all_objs:
# print(i.name)
print(all_objs)
,空的querysetobjs = models.Student.objects.filter(id=2) #找id为2的那条记录
print(objs) #]>
objs = models.Student.objects.filter(name='dazhaung')
print(objs) #]>
obj = models.Student.objects.get(id=3) #找id为3的那条记录
print(obj) #xiaozhuang2
all()
: 查询所有结果,结果是queryset类型filter(**kwargs)
: 它包含了与所给筛选条件相匹配的对象,结果也是queryset类型Book.objects.filter(title='linux',price=100) #里面的多个条件用逗号分开,并且这几个条件必须都成立,是and的关系,or关系的我们后面再学,直接在这里写是搞不定or的
models.Student.objects.filter(id=7,name='大壮哥哥',age=78).update(
name='大壮禅师',
age=78
)
#打伞形式传参
models.Student.objects.filter(**{'id':7,'name':'大壮禅师'}).update(age=100)
models.Student.objects.all().filter(id=7) queryset类型可以调用fitler在过滤
get(**kwargs)
: 返回与所给筛选条件相匹配的对象,不是***queryset类型***,是***行记录对象***,返回结果***有且只有一个***,如果符合筛选条件的对象超过一个或者没有都会抛出错误。捕获异常。 Book.objects.get(id=1)
exclude(**kwargs)
: ***排除***的意思,它包含了与所给筛选条件不匹配的对象。exclude
返回值是queryset类型 Book.objects.exclude(id=6)
,返回id不等于6的所有的对象
order_by(*field)
: queryset类型的数据来调用,对查询结果排序,默认是按照id来升序排列的,返回值还是queryset类型。
models.Book.objects.all().order_by('price','id') #直接写price,默认是按照price升序排列,按照字段降序排列,就写个负号就行了
order_by('-price'),order_by('price','id')# 是多条件排序,按照price进行升序,price相同的数据,按照id进行升序
reverse()
: queryset类型的数据来调用,对查询结果反向排序,返回值还是queryset类型
# 排序之后反转
# query = models.Student.objects.all().order_by('id').reverse()
# print(query)
count()
: queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量。
first()
: queryset类型的数据来调用,返回第一条记录 Book.objects.all()[0] = Book.objects.all().first(),
得到的都是model对象,不是queryset
last()
: queryset类型的数据来调用,返回最后一条记录,结果为model对象类型
exists()
: queryset类型的数据来调用,如果QuerySet包含数据,就返回True,否则返回False。空的queryset类型数据也有布尔值True和False,但是一般不用它来判断数据库里面是不是有数据,如果有大量的数据,你用它来判断,那么就需要查询出所有的数据,效率太差了,用count或者exits。例:
all_books = models.Book.objects.all().exists() #翻译成的sql是SELECT (1) AS `a` FROM `app01_book` LIMIT 1,就是通过limit 1,取一条来看看是不是有数据
values(field)
: queryset类型的数据来调用,返回一个ValueQuerySet(一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列,只要是返回的queryset类型,就可以继续链式调用queryset类型的其他的查找方法,其他方法也是一样的。)
(field)
: 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
distinct()
: values和values_list得到的queryset类型的数据来调用,从返回结果中剔除重复纪录,结果还是queryset
query = models.Student.objects.all().values('age').distinct()
print(query)
Book.objects.filter(price__in=[100,200,300]) #price值等于这三个里面的任意一个的对象
Book.objects.filter(price__gt=100) #大于,大于等于是price__gte=100,别写price>100,这种参数不支持
Book.objects.filter(price__lt=100)
Book.objects.filter(price__range=[100,200]) #sql的between and,大于等于100,小于等于200
Book.objects.filter(title__contains="python") #title值中包含python的
Book.objects.filter(title__icontains="python") #不区分大小写
Book.objects.filter(title__startswith="py") #以什么开头,istartswith 不区分大小写
Book.objects.filter(pub_date__year=2012)
# all_books = models.Book.objects.filter(pub_date__year=2012) #找2012年的所有书籍
# all_books = models.Book.objects.filter(pub_date__year__gt=2012)#找大于2012年的所有书籍
all_books = models.Book.objects.filter(pub_date__year=2019,pub_date__month=2)#找2019年月份的所有书籍,如果明明有结果,你却查不出结果,是因为mysql数据库的时区和咱们django的时区不同导致的,了解一下就行了,你需要做的就是将django中的settings配置文件里面的USE_TZ = True改为False,就可以查到结果了,以后这个值就改为False,而且就是因为咱们用的mysql数据库才会有这个问题,其他数据库没有这个问题。
#添加书籍
url(r'^add_book/', views.add_book,name='abook'), #name='abook' 别名
# 删除书籍
url(r'^delete_book/(\d+)/', views.delele_book,name='delete_book'),
视图:
from django.urls import reverse
reverse('别名') reverse('abook') -- /add_book/ #不带参数的
print(reverse('delete_book',args=(71,))) #/delete_book/71/ 带参数的
模板
{% url 'abook' %} 无参数的
{% url 'delete_book' book.id %} 无参数的
表的三种关系:
示例
from django.db import models
# Create your models here.
from django.db import models
# Create your models here.
#作者表
class Author(models.Model): #比较常用的信息放到这个表里面
name=models.CharField( max_length=32)
age=models.IntegerField()
# authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)
authorDetail=models.OneToOneField(to='AuthorDetail') #一对一到AuthorDetail表 生成为表字段之后,会自动变为authorDetail_id这样有一个名称
# 外键字段 -- 外键字段名_id
# foreign+unique
def __str__(self):
return self.name
#作者详细信息表
class AuthorDetail(models.Model):
birthday=models.DateField()
# telephone=models.BigIntegerField()
telephone=models.CharField(max_length=32)
addr=models.CharField( max_length=64)
def __str__(self):
return self.addr
#出版社表 和 书籍表 是 一对多的关系
class Publish(models.Model):
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
email=models.EmailField() #charfield -- asdfasdf
def __str__(self):
return self.name
#书籍表
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2) #decimal(16,2)
publishs=models.ForeignKey(to="Publish")
authors=models.ManyToManyField(to='Author',)
def __str__(self):
return self.title
#手动创建第三张表,暂时忽略
# class BookToAuthor(models.Model):
# book_id = models.ForeignKey(to='Book')
# author_id = models.ForeignKey(to='Author')
# # xx = models.CharField(max_length=12)
一对一
xx = models.OneToOneField(to='表名',to_field='字段名',on_delete=models.CASCADE)
删除时的一些级联效果,to_field
可以不写,默认是关联到另一张表的主键,on_delete
在1.x版本的django中不用写,默认是级联删除的,2.x版本的django要写。
一对多
xx = models.ForeignKey(to='表名',to_field='字段名',on_delete=models.CASCADE)
多对多
xx = models.ManyToManyField(to='另外一个表名')
增
1.1 一对一增加
new_author_detail = models.AuthorDetail.objects.create(
birthday='1979-08-08',
telephone='138383838',
addr='黑龙江哈尔滨'
)
obj = models.AuthorDetail.objects.filter(addr='山西临汾').first()
方式1
models.Author.objects.create(
name='王涛',
age='40',
authorDetail=new_author_detail,
)
方式2 常用
models.Author.objects.create(
name='王涛',
age='40',
authorDetail_id=obj.id,
)
1.2 一对多
obj = models.Publish.objects.get(id=2)
models.Book.objects.create(
title = '李帅的床头故事',
publishDate='2019-07-22',
price=3,
# publishs=models.Publish.objects.get(id=1),
publishs=obj,
)
方式2 常用
models.Book.objects.create(
title='李帅的床头故事2',
publishDate='2019-07-21',
price=3.5,
# publishs=models.Publish.objects.get(id=1),
publishs_id=obj.id
)
1.3 多对多
方式1 常用
book_obj = models.Book.objects.get(nid=1)
book_obj.authors.add(*[1,2])
方式2
author1 = models.Author.objects.get(id=1)
author2 = models.Author.objects.get(id=3)
book_obj = models.Book.objects.get(nid=5)
book_obj.authors.add(*[author1,author2])
删
一对一和一对多的删除和单表删除是一样的
一对一 表一外键关联到表二,表一删除,不影响表2,表2删除会影响表1
models.AuthorDetail.objects.get(id=2).delete()
models.Author.objects.get(id=3).delete()
一对多
models.Publish.objects.get(id=1).delete()
models.Book.objects.get(nid=1).delete()
多对多关系删除
book_obj = models.Book.objects.get(nid=6)
book_obj.authors.remove(6)
book_obj.authors.remove(*[5,6])
book_obj.authors.clear()
book_obj.authors.add(*[1,])
book_obj.authors.set('1')
book_obj.authors.set(['5','6']) #删除然后更新
更新
一对一
models.Author.objects.filter(id=5).update(
name='崔老师',
age=16,
# authorDetail=models.AuthorDetail.objects.get(id=5),
authorDetail_id=4,
)
一对多
models.Book.objects.filter(pk=4).update(
title='B哥的往事2',
# publishs=models.Publish.objects.get(id=3),
publishs_id=3,
)
多对多
models.Publish.objects.filter(pk=2).update(
id=4, # 没有级联更新,报错!!
)
查 基于对象的跨表查询 – 类似于子查询
正向查询
反向查询
关系属性(字段)写在哪个类(表)里面,从当前类(表)的数据去查询它关联类(表)的数据叫做正向查询,反之叫做反向查询
一对一
正向查询
1 查询崔老师的电话号
author_obj = models.Author.objects.filter(name='崔老师').first()
print(author_obj.authorDetail) #辽宁峨眉山
print(author_obj.authorDetail.telephone) #444
* 反向查询
```python
#2 查询一下这个444电话号是谁的.
author_detail_obj = models.AuthorDetail.objects.get(telephone='444')
print(author_detail_obj.author) #崔老师
print(author_detail_obj.author.name) #崔老师
> 正向查询` book_obj.publishs ` 对象.属性
> Book ---------------------------------------------> Publish
> <----------------------------------------------
反向查询 `publish_obj.book_set.all()` 对象.表名小写_set
一对多
正向查询
# 查询一下李帅的床头故事这本书的出版社是哪个
book_obj = models.Book.objects.get(title='李帅的床头故事')
print(book_obj.publishs) #B哥出版社
print(book_obj.publishs.name) #B哥出版社
反向查询
# B哥出版社出版社出版了哪些书
# 反向查询
pub_obj = models.Publish.objects.get(name='B哥出版社')
print(pub_obj.book_set.all()) #, ]>
正向查询 `book_obj.publishs ` 对象.属性 Book ---------------------------------------------> Publish <---------------------------------------------- 反向查询 `publish_obj.book_set.all() ` 对象.表名小写_set
多对多
正向查询
# 李帅的床头故事这本书是谁写的
book_obj = models.Book.objects.get(title='李帅的床头故事')
print(book_obj.authors.all())
反向查询
# 高杰写了哪些书
author_obj = models.Author.objects.get(name='高杰')
print(author_obj.book_set.all())
基于双下划綫的跨表查询 – 连表 join
一对一
#1 查询崔老师的电话号
obj = models.Author.objects.filter(name='崔老师').values('authorDetail__telephone')
print(obj) #
# 2. 哪个老师的电话是444
obj = models.Author.objects.filter(authorDetail__telephone='444').values('name')
print(obj)
反向查询
#2 查询崔老师的电话号.
obj = models.AuthorDetail.objects.filter(author__name='崔老师').values('telephone','author__age')
print(obj) #
obj =models.AuthorDetail.objects.filter(telephone='444').values('author__name')
print(obj)
一对多
正向查询
# 查询一下李帅的床头故事这本书的出版社是哪个
obj = models.Book.objects.filter(title='李帅的床头故事').values('publishs__name')
print(obj) #
# B哥出版社出版社出版了哪些书
obj = models.Publish.objects.filter(name='B哥出版社').values('book__title')
print(obj) #
反向查询
# 查询一下李帅的床头故事这本书的出版社是哪个
obj = models.Publish.objects.filter(book__title='李帅的床头故事').values('name')
obj = models.Publish.objects.filter(xx__title='李帅的床头故事').values('name')
print(obj)
# B哥出版社出版社出版了哪些书
pub_obj = models.Publish.objects.get(name=‘B哥出版社’)
print(pub_obj.book_set.all()) #
多对多
正向查询
#李帅的床头故事这本书是谁写的
obj = models.Book.objects.filter(title='李帅的床头故事').values('authors__name')
print(obj)
#高杰写了哪些书
obj = models.Author.objects.filter(name='高杰').values('book__title')
print(obj)
反向查询
#李帅的床头故事这本书是谁写的
obj = models.Author.objects.filter(book__title='李帅的床头故事').values('name')
print(obj) #
#高杰写了哪些书
obj = models.Book.objects.filter(authors__name='高杰').values('title')
print(obj)
进阶的
# B哥出版社 出版的书的名称以及作者的名字
obj = models.Book.objects.filter(publishs__name='B哥出版社').values('title','authors__name')
print(obj)
<QuerySet [{'title': '李帅的床头故事', 'authors__name': '高杰'}, {'title': '李帅的床头故事', 'authors__name': '崔老师'}, {'title': '李帅的床头故事2', 'authors__name': '崔老师'}, {'title': '李帅的床头故事2', 'authors__name': '王涛'}]>
obj = models.Publish.objects.filter(name='B哥出版社').values('book__title','book__authors__name')
print(obj)
obj = models.Author.objects.filter(book__publishs__name='B哥出版社').values('name','book__title')
print(obj)
authorDetail author book publish
#手机号以4开头的作者出版过的所有书籍名称以及出版社名称
ret =models.AuthorDetail.objects.filter(telephone__startswith='4').values('author__book__title','author__book__publishs__name')
print(ret)
QuerySet [{'author__book__title': '李帅的床头故事', 'author__book__publishs__name': 'B哥出版社'}, {'author__book__title': '李帅的床头故事2', 'author__book__publishs__name': 'B哥出版社'}]>
#查询一下B哥出版社出版了哪些书
obj = models.Publish.objects.filter(name='B哥出版社').first()
print(obj.xx.all())
from django.db.models import Avg,Max,Min,Sum,Count
# 计算所有图书的平均价格
# obj = models.Book.objects.all().aggregate(a=Avg('price'),m=Max('price')) #aggregate()是QuerySet 的一个终止子句,得到的是个字典.
# print(obj['m'] - 2) #{'price__avg': 2.833333}
# models.Publish.objects.annotate(a=Avg('book__price')).values('a')
# models.Book.objects.values('publish_id','id').annotate(a=Avg('price')) {'pulish_id':1,'a':11.11}
from django.db.models import F,Q
F 针对自己单表中字段的比较和处理
models.Book.objects.filter(good__gt=F('comment')*2)
models.Book.objects.all().update(price=F('price')+1)
Q & | 非~
filter(Q(xx=11)|Q(ss=22)&Q(oo=33))
filter(Q(Q(xx=11)|Q(ss=22))&Q(oo=33)) &优先级高
filter(Q(Q(xx=11)|Q(ss=22))&Q(oo=33),name='dd')
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
rep = HttpResponse(...)
rep = render(request, ...)
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...)
def logout(request):
rep = redirect("/login/")
rep.delete_cookie("user") # 删除用户浏览器上之前设置的usercookie值
return rep
实例:
def check_login(func):
@wraps(func)
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.get_signed_cookie("login", salt="SSS", default=None) == "yes":
# 已经登录的用户...
return func(request, *args, **kwargs)
else:
# 没有登录的用户,跳转刚到登录页面
return redirect("/login/?next={}".format(next_url))
return inner
def login(request):
if request.method == "POST":
username = request.POST.get("username")
passwd = request.POST.get("password")
if username == "xxx" and passwd == "dashabi":
next_url = request.GET.get("next")
if next_url and next_url != "/logout/":
response = redirect(next_url)
else:
response = redirect("/class_list/")
response.set_signed_cookie("login", "yes", salt="SSS")
return response
return render(request, "login.html")
# 方式1
def login(request):
ret = HttpResponse('ok')
ret.set_cookie('k1','你好'.encode('utf-8').decode('iso-8859-1'))
#取值:request.COOKIES['k1'].encode('utf-8').decode('iso-8859-1').encode('iso-8859-1').decode('utf-8')
return ret
方式2 json
def login(request):
ret = HttpResponse('ok')
import json
ret.set_cookie('k1',json.dumps('你好'))
#取值 json.loads(request.COOKIES['k1'])
return ret
request.session['k1']
request.session.get('k1',None) #request.session这句是帮你从cookie里面将sessionid的值取出来,将django-session表里面的对应sessionid的值的那条记录中的session-data字段的数据给你拿出来(并解密),get方法就取出k1这个键对应的值#设置值
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在则不设置
del request.session['k1'] #django-session表里面同步删除
request.session.keys()
request.session.values()
request.session.items()
设置会话Session和Cookie的超时时间request.session.set_expiry(value)
删除当前的会话数据并删除会话的Cookie。request.session.flush()
django.contrib.auth.logout()
函数中就会调用它检查会话session的key在数据库中是否存在request.session.exists("session_key")
session_key就是那个sessionid的值
会话session的keysession_key = request.session.session_key
获取sessionid的值
将所有Session失效日期小于当前日期的数据删除,将过期的删除request.session.clear_expired()
from functools import wraps
def check_login(func):
@wraps(func)
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.session.get("user"):
return func(request, *args, **kwargs)
else:
return redirect("/login/?next={}".format(next_url))
return inner
def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
if user == "alex" and pwd == "alex1234":
# 设置session
request.session["user"] = user
# 获取跳到登陆页面之前的URL
next_url = request.GET.get("next")
# 如果有,就跳转回登陆之前的URL
if next_url:
return redirect(next_url)
# 否则默认跳转到index页面
else:
return redirect("/index/")
return render(request, "login.html")
@check_login
def logout(request):
# 删除所有当前请求相关的session
request.session.delete()
return redirect("/login/")
@check_login
def index(request):
current_user = request.session.get("user", None)
return render(request, "index.html", {"user": current_user})
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5DTRmMUu-1614860803386)(C:\Users\Administrator\Desktop\interview_python-master\img\django处理流程.png)]
生成页面HTML标签
校验用户提交的数据合法性
保留用户输入的数据
from django import forms
def mobile_validate(value): value是要被校验的数据
mobile_re = re.compile(r'^13[0-9]{9}')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误') #别忘了raise错误
class MyForm(forms.Form):
name = forms.CharField(
required=True, #默认等于True,内容不能为空
min_length=6, #最小长度为6
label='用户名', #标识
initial='高杰DSB', #初始值,默认值
# validators=[RegexValidator(r'^金瓶梅','没看过金瓶梅,不能通过'),RegexValidator(r'红旭妹妹$','没看过红旭妹妹,不能通过'),], #写自定义校验规则,RegexValidator(正则,错误信息)
# validators=[mobile_validate,], #写自定义校验规则,RegexValidator(函数名称,)
help_text='这是输入用户名的地方,不能太短!',
error_messages={'required':'不能为空!','min_length':'太短了!'},
# widget=forms.widgets.TextInput(attrs={'class':'form-control'}),
widget=forms.widgets.TextInput,
)
password = forms.CharField(
min_length=8,
max_length=10, #最大长度不能超过10位
label='密码',
widget=forms.widgets.PasswordInput(), #密文输入
)
radio单选框:
sex = forms.ChoiceField(
label='性别',
initial=3, #初始值
choices=((1, "男"), (2, "女"), (3, "保密")),
widget=forms.widgets.RadioSelect(),
)
select下拉单选框
city = forms.ChoiceField(
label='性别',
initial=3,
choices=((1, "北京"), (2, "上海"), (3, "东莞")),
widget=forms.widgets.Select(),
)
checkbox多选框
hobby = forms.MultipleChoiceField(
label='爱好',
choices=((1, "抽烟"), (2, "喝酒"), (3, "烫头")),
widget=forms.widgets.CheckboxSelectMultiple,
)
select下拉多选框
girls = forms.MultipleChoiceField(
label='爱好',
choices=((1, "红旭妹妹"), (2, "相玺哥哥"), (3, "程根姐姐")),
widget=forms.widgets.SelectMultiple,
)
单选checkbox
status = forms.ChoiceField(
label='remeber me!!',
choices=(('True', "红旭妹妹"), ('False', "相玺哥哥")),
widget=forms.widgets.CheckboxInput,
)
#给标签加属性
widget=forms.widgets.TextInput(attrs={'class':'c1','type':'date'}),
{% load static %}
Bootstrap 101 Template
你好,世界!
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
},
widget=forms.widgets.TextInput(attrs={"class": "form-control"})
)
...
# 定义局部钩子,用来校验username字段,之前的校验股则还在,给你提供了一个添加一些校验功能的钩子
def clean_username(self):
value = self.cleaned_data.get("username")
if "666" in value:
raise ValidationError("光喊666是不行的")
else:
return value
class LoginForm(forms.Form):
...
password = forms.CharField(
min_length=6,
label="密码",
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}, render_value=True)
)
re_password = forms.CharField(
min_length=6,
label="确认密码",
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}, render_value=True)
)
...
# 定义全局的钩子,用来校验密码和确认密码字段是否相同,执行全局钩子的时候,cleaned_data里面肯定是有了通过前面验证的所有数据
def clean(self):
password_value = self.cleaned_data.get('password')
re_password_value = self.cleaned_data.get('re_password')
if password_value == re_password_value:
return self.cleaned_data #全局钩子要返回所有的数据
else:
self.add_error('re_password', '两次密码不一致') #在re_password这个字段的错误列表中加上一个错误,并且clean_data里面会自动清除这个re_password的值,所以打印clean_data的时候会看不到它
raise ValidationError('两次密码不一致')
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
...
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
for field in iter(self.fields):
self.fields[field].widget.attrs.update({
'class': 'form-control'
})
基于这个原因,Django 提供一个辅助类来让我们可以从Django 的模型创建Form,这就是ModelForm。
modelForm: form与model的终极结合,会根据你model中的字段转换成对应的form字段,并且并你生成标签等操作。
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
publish=models.ForeignKey(to="Publish",to_field="nid")
authors=models.ManyToManyField(to='Author',)
def __str__(self):
return self.title
class BookForm(forms.ModelForm):
class Meta:
model = models.Book
fields = "__all__"
labels = {
"title": "书名",
"price": "价格"
}
widgets = {
"password": forms.widgets.PasswordInput(attrs={"class": "c1"}),
"publishDate": forms.widgets.DateInput(attrs={"type": "date"}),
}
model = models.Book # 对应的Model中的类
fields = "__all__" # 字段,如果是__all__,就是表示列出所有的字段
exclude = None # 排除的字段
labels = None # 提示信息
help_texts = None # 帮助提示信息
widgets = None # 自定义插件
error_messages = None # 自定义错误信息
error_messages = {
'title':{'required':'不能为空',...} #每个字段的所有的错误都可以写,...是省略的意思,复制黏贴我代码的时候别忘了删了...
}
>>> from myapp.models import Book
>>> from myapp.forms import BookForm
# 根据POST数据创建一个新的form对象
>>> form_obj = BookForm(request.POST)
# 创建书籍对象
>>> new_ book = form_obj.save()
# 基于一个书籍对象创建form对象
>>> edit_obj = Book.objects.get(id=1)
# 使用POST提交的数据更新书籍对象
>>> form_obj = BookForm(request.POST, instance=edit_obj)
>>> form_obj.save()
之前我们通过form组件来保存书籍表数据的时候的写法:
def edit_book(request,n):
book_obj = models.Book.objects.filter(pk=n).first()
if request.method == 'GET':
# all_authors = models.Author.objects.all() #
# all_publish = models.Publish.objects.all()
form = BookForm(instance=book_obj)
return render(request,'edit_book.html',{'form':form,'n':n}) #传递的这个n参数是给form表单提交数据的是的action的url用的,因为它需要一个参数来识别是更新的哪条记录
else:
form = BookForm(request.POST,instance=book_obj) #必须指定instance,不然我们调用save方法的是又变成了添加操作
if form.is_valid():
form.save()
return redirect('show')
else:
return render(request,'edit_book.html',{'form':form,'n':n})
WSGI:
web服务器网关接口,是一套协议。用于接收用户请求并将请求进行初次封装,然后将请求交给web框架。
实现wsgi协议的模块:wsgiref,本质上就是编写一socket服务端,用于接收用户请求(django)
werkzeug,本质上就是编写一个socket服务端,用于接收用户请求(flask)
uwsgi:
与WSGI一样是一种通信协议,它是uWSGI服务器的独占协议,用于定义传输信息的类型。
uWSGI:
是一个web服务器,实现了WSGI的协议,uWSGI协议,http协议
1、 Django走的大而全的方向,开发效率高。它的MTV框架,自带的ORM,admin后台管理,自带的sqlite数据库和开发测试用的服务器,给开发者提高了超高的开发效率。
重量级web框架,功能齐全,提供一站式解决的思路,能让开发者不用在选择上花费大量时间。
自带ORM和模板引擎,支持jinja等非官方模板引擎。
自带ORM使Django和关系型数据库耦合度高,如果要使用非关系型数据库,需要使用第三方库
自带数据库管理app
成熟,稳定,开发效率高,相对于Flask,Django的整体封闭性比较好,适合做企业级网站的开发。python web框架的先驱,第三方库丰富
2、 Flask 是轻量级的框架,自由,灵活,可扩展性强,核心基于Werkzeug WSGI工具 和jinja2 模板引擎
适用于做小网站以及web服务的API,开发大型网站无压力,但架构需要自己设计
与关系型数据库的结合不弱于Django,而与非关系型数据库的结合远远优于Django
3、 Tornado走的是少而精的方向,性能优越,它最出名的异步非阻塞的设计方式
Tornado的两大核心模块:
iostraem:对非阻塞的socket进行简单的封装
ioloop: 对I/O 多路复用的封装,它实现一个单例
什么是CORS?
CORS是一个W3C标准,全称是“跨域资源共享"(Cross-origin resoure sharing).
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而客服了AJAX只能同源使用的限制。
什么是CSRF?
CSRF主流防御方式是在后端生成表单的时候生成一串随机token,内置到表单里成为一个字段,同时,将此串token置入session中。每次表单提交到后端时都会检查这两个值是否一致,以此来判断此次表单提交是否是可信的,提交过一次之后,如果这个页面没有生成CSRF token,那么token将会被清空,如果有新的需求,那么token会被更新。
攻击者可以伪造POST表单提交,但是他没有后端生成的内置于表单的token,session中没有token都无济于事。
为什么要使用会话管理
众所周知,HTTP协议是一个无状态的协议,也就是说每个请求都是一个独立的请求,请求与请求之间并无关系。但在实际的应用场景,这种方式并不能满足我们的需求。举个大家都喜欢用的例子,把商品加入购物车,单独考虑这个请求,服务端并不知道这个商品是谁的,应该加入谁的购物车?因此这个请求的上下文环境实际上应该包含用户的相关信息,在每次用户发出请求时把这一小部分额外信息,也做为请求的一部分,这样服务端就可以根据上下文中的信息,针对具体的用户进行操作。所以这几种技术的出现都是对HTTP协议的一个补充,使得我们可以用HTTP协议+状态管理构建一个的面向用户的WEB应用。
Session 和Cookie的区别
这里我想先谈谈session与cookies,因为这两个技术是做为开发最为常见的。那么session与cookies的区别是什么?个人认为session与cookies最核心区别在于额外信息由谁来维护。利用cookies来实现会话管理时,用户的相关信息或者其他我们想要保持在每个请求中的信息,都是放在cookies中,而cookies是由客户端来保存,每当客户端发出新请求时,就会稍带上cookies,服务端会根据其中的信息进行操作。
当利用session来进行会话管理时,客户端实际上只存了一个由服务端发送的session_id,而由这个session_id,可以在服务端还原出所需要的所有状态信息,从这里可以看出这部分信息是由服务端来维护的。
除此以外,session与cookies都有一些自己的缺点:
cookies的安全性不好,攻击者可以通过获取本地cookies进行欺骗或者利用cookies进行CSRF攻击。使用cookies时,在多个域名下,会存在跨域问题。
session 在一定的时间里,需要存放在服务端,因此当拥有大量用户时,也会大幅度降低服务端的性能,当有多台机器时,如何共享session也会是一个问题.(redis集群)也就是说,用户第一个访问的时候是服务器A,而第二个请求被转发给了服务器B,那服务器B如何得知其状态。实际上,session与cookies是有联系的,比如我们可以把session_id存放在cookies中的。
JWT是如何工作的
首先用户发出登录请求,服务端根据用户的登录请求进行匹配,如果匹配成功,将相关的信息放入payload中,利用算法,加上服务端的密钥生成token,这里需要注意的是secret_key很重要,如果这个泄露的话,客户端就可以随机篡改发送的额外信息,它是信息完整性的保证。生成token后服务端将其返回给客户端,客户端可以在下次请求时,将token一起交给服务端,一般是说我们可以将其放在Authorization首部中,这样也就可以避免跨域问题。
一般是用户通过浏览器向我们的服务器发起一个请求(request),这个请求会去访问视图函数,如果不涉及到数据调用,那么这个时候视图函数返回一个模板也就是一个网页给用户)
视图函数调用模型毛模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。
1.wsgi ,请求封装后交给web框架(Flask,Django)
2.中间件,对请求进行校验或在请求对象中添加其他相关数据,例如:csrf,request.session
3.路由匹配 根据浏览器发送的不同url去匹配不同的视图函数
4.视图函数,在视图函数中进行业务逻辑的处理,可能涉及到:orm,templates
5.中间件,对响应的数据进行处理
6.wsgi,将响应的内容发送给浏览器
当前的问题是用django的rest framework模块做一个get请求的发送时间以及时区信息的api
class getCurrenttime(APIView):
def get(self,request):
local_time = time.localtime()
time_zone =settings.TIME_ZONE
temp = {'localtime':local_time,'timezone':time_zone}
return Response(temp)
Nginx(engine x)是一个高性能的HTTP和反向代理服务器,也是 一个IMAP/POP3/SMTP服务器,工作在OSI七层,负载的实现方式:轮询,IP_HASH,fair,session_sticky.
Apache HTTP Server是一个模块化的服务器,源于NCSAhttpd服务器
Tomcat 服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,是开发和调试JSP程序的首选。
在进行数据库的设计时,所遵循的一些规范,只要按照设计规范进行设计,就能设计出没有数据冗余和数据维护异常的数据库结构。
数据库的设计的规范有很多,通常来说我们在设是数据库时只要达到其中一些规范就可以了,这些规范又称之为数据库的三范式,一共有三条,也存在着其他范式,我们只要做到满足前三个范式的要求,就能设陈出符合我们的数据库了,我们也不能全部来按照范式的要求来做,还要考虑实际的业务使用情况,所以有时候也需要做一些违反范式的要求。
1.数据库设计的第一范式(最基本),基本上所有数据库的范式都是符合第一范式的,符合第一范式的表具有以下几个特点:
数据库表中的所有字段都只具有单一属性,单一属性的列是由基本的数据类型(整型,浮点型,字符型等)所构成的设计出来的表都是简单的二比表
2.数据库设计的第二范式(是在第一范式的基础上设计的),要求一个表中只具有一个业务主键,也就是说符合第二范式的表中不能存在非主键列对只对部分主键的依赖关系
3.数据库设计的第三范式,指每一个非主属性既不部分依赖与也不传递依赖于业务主键,也就是第二范式的基础上消除了非主属性对主键的传递依赖
qq登录,在我们的项目中分为了三个接口,
第一个接口是请求qq服务器返回一个qq登录的界面;
第二个接口是通过扫码或账号登陆进行验证,qq服务器返回给浏览器一个code和state,利用这个code通过本地服务器去向qq服务器获取access_token覆返回给本地服务器,凭借access_token再向qq服务器获取用户的openid(openid用户的唯一标识)
第三个接口是判断用户是否是第一次qq登录,如果不是的话直接登录返回的jwt-token给用户,对没有绑定过本网站的用户,对openid进行加密生成token进行绑定
1.GET是从服务器上获取数据,POST是向服务器传送数据
2.在客户端,GET方式在通过URL提交数据,数据在URL中可以看到,POST方式,数据放置在HTML——HEADER内提交
3.对于GET方式,服务器端用Request.QueryString获取变量的值,对于POST方式,服务器端用Request.Form获取提交的数据
一、日志相关概念
1.日志是一种可以追踪某些软件运行时所发生事件的方法
2.软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情
3.一个事件可以用一个包含可选变量数据的消息来描述
4.此外,事件也有重要性的概念,这个重要性也可以被成为严重性级别(level)
二、日志的作用
1.通过log的分析,可以方便用户了解系统或软件、应用的运行情况;
2.如果你的应用log足够丰富,可以分析以往用户的操作行为、类型喜好,地域分布或其他更多信息;
3.如果一个应用的log同时也分了多个级别,那么可以很轻易地分析得到该应用的健康状况,及时发现问题并快速定位、解决问题,补救损失。
4.简单来讲就是我们通过记录和分析日志可以了解一个系统或软件程序运行情况是否正常,也可以在应用程序出现故障时快速定位问题。不仅在开发中,在运维中日志也很重要,日志的作用也可以简单。总结为以下几点:
1.程序调试
2.了解软件程序运行情况,是否正常
3,软件程序运行故障分析与问题定位
4,如果应用的日志信息足够详细和丰富,还可以用来做用户行为分析
Django在中间件中预置了六个方法,这六个方法的区别在于不同的阶段执行,对输入或输出进行干预,方法如下:
1.初始化:无需任何参数,服务器响应第一个请求的时候调用一次,用于确定是否启用当前中间件
def __init__():
pass
2.处理请求前:在每个请求上调用,返回None或HttpResponse对象。
def process_request(request):
pass
3.处理视图前:在每个请求上调用,返回None或HttpResponse对象。
def process_view(request,view_func,view_args,view_kwargs):
pass
4.处理模板响应前:在每个请求上调用,返回实现了render方法的响应对象。
def process_template_response(request,response):
pass
5.处理响应后:所有响应返回浏览器之前被调用,在每个请求上调用,返回HttpResponse对象。
def process_response(request,response):
pass
6.异常处理:当视图抛出异常时调用,在每个请求上调用,返回一个HttpResponse对象。
def process_exception(request,exception):
pass
1.uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。WSGI是一种Web服务器网关接口。它是一个Web服务器(如nginx,uWSGI等服务器)与web应用(如用Flask框架写的程序)通信的一种规范。
要注意WSGI/uwsgi/uWSGI这三个概念的区分。
WSGI是一种通信协议。
uwsgi是一种线路协议而不是通信协议,在此常用于在uWSGI服务器与其他网络服务器的数据通信。
uWSGI是实现了uwsgi和WSGI两种协议的Web服务器。
nginx 是一个开源的高性能的HTTP服务器和反向代理:
1.作为web服务器,它处理静态文件和索引文件效果非常高
2.它的设计非常注重效率,最大支持5万个并发连接,但只占用很少的内存空间
3.稳定性高,配置简洁。
4.强大的反向代理和负载均衡功能,平衡集群中各个服务器的负载压力应用
django:主要是用来搞快速开发的,他的亮点就是快速开发,节约成本,,如果要实现高并发的话,就要对django进行二次开发,比如把整个笨重的框架给拆掉自己写socket实现http的通信,底层用纯c,c++写提升效率,ORM框架给干掉,自己编写封装与数据库交互的框架,ORM虽然面向对象来操作数据库,但是它的效率很低,使用外键来联系表与表之间的查询;
flask: 轻量级,主要是用来写接口的一个框架,实现前后端分离,提考开发效率,Flask本身相当于一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login),都需要用第三方的扩展来实现。比如可以用Flask-extension加入ORM、文件上传、身份验证等。Flask没有默认使用的数据库,你可以选择MySQL,也可以用NoSQL。
其WSGI工具箱用Werkzeug(路由模块),模板引擎则使用Jinja2,这两个也是Flask框架的核心。
Tornado: Tornado是一种Web服务器软件的开源版本。Tornado和现在的主流Web服务器框架(包括大多数Python的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其非阻塞的方式和对epoll的运用,Tornado每秒可以处理数以千计的连接因此Tornado是实时Web服务的一个理想框架
1.Django中耗时的任务用一个进程或者线程来执行,比如发邮件,使用celery.
2.部署django项目是时候,配置文件中设置了进程和协程的相关配置。
Django REST framework是一个强大而灵活的Web API工具。使用RESTframework的理由有:
Web browsable API对开发者有极大的好处
包括OAuth1a和OAuth2的认证策略
支持ORM和非ORM数据资源的序列化
全程自定义开发–如果不想使用更加强大的功能,可仅仅使用常规的function-based views额外的文档和强大的社区支持
Session采用的是在服务器端保持状态的方案,而Cookie采用的是在客户端保持状态的方案。但是禁用Cookie就不能得到Session。因为Session是用Session ID来确定当前对话所对应的服务器Session,而Session ID是通过Cookie来传递的,禁用Cookie相当于SessionID,也就得不到Session。