django
参考:http://www.cnblogs.com/wupeiqi/articles/5237704.html
http://www.cnblogs.com/wupeiqi/articles/5341480.html
http://www.cnblogs.com/wupeiqi/articles/5246483.html
客户端访问服务器的时候,访问对应函数,函数会返回字符串到客户端
1、django请求生命周期:
-》URL对应关系(匹配) -》 视图函数 -》返回用户字符串;
-》URL对应关系(匹配) -》 视图函数 -》打开一个HTML文件,读取内容
安装
mysite mysite #对整个程序进行配置 -init -setting #配置文件 -url #URL对应关系 -wsgi #遵循WSGI规范,uwsgi + nginx -manage.py #管理Django程序: -python manage.py -python manage.py startapp xx 创建app -python manage.py makemigrations -python manage.py migrate
wsgi:遵循wsgi规则的是以下东西
'cgi'
: CGIServer,
'flup'
: FlupFCGIServer,
'wsgiref'
: WSGIRefServer,
'waitress'
: WaitressServer,
'cherrypy'
: CherryPyServer,
'paste'
: PasteServer,
'fapws3'
: FapwsServer,
'tornado'
: TornadoServer,
'gae'
: AppEngineServer,
'twisted'
: TwistedServer,
'diesel'
: DieselServer,
'meinheld'
: MeinheldServer,
'gunicorn'
: GunicornServer,
'eventlet'
: EventletServer,
'gevent'
: GeventServer,
'geventSocketIO'
:GeventSocketIOServer,
'rocket'
: RocketServer,
'bjoern'
: BjoernServer,
'auto'
: AutoServer,
pip3 install django
安装完毕后,python目录就会增加两个文件,然后将这个目录C:\Python36\Scripts增加到环境变量
django-admin.exe startproject laoniu
运行命令提示符,D盘目录将会增加laoniu文件夹;
命令提示符,进入该目录,输入命令python manage.py runserver 127.0.0.1:8001
pycharm启用django
选中对应项目,然后启动(修改访问端口也是这里硒鼓)
若是没有对应django server,需要编辑结构,选中左上角的+,增加上去
创建app
chouti
-chouti
-配置
-主站 app
-后台管理 app
python manage.py startapp cmdb
python manage.py startapp openstack
python manage.py startapp makemigrations
python manage.py startapp xxxx
app:
makemigrations: 修改数据库表结构的记录
admin Django为我们提供的后台管理
apps 配置当前app
models ORM,写指定的类,通过命令可以创建数据库结构
tests 单元测试
views 业务代码
1.配置模板的路径
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR),"templates"], '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', ], }, }, ]
2.配置静态目录
静态文件对应客户端请求,需要在settings配置文件最后加上
STATICFIES_DIRS = (
# 这里必须要有逗号
os.path.join(BASE_DIR,'static'),
)
settings文件注释 MIDDLEWARE 的'django.middleware.csrf.CsrfViewMiddleware',
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
4、编写程序
a.url.py
/inde/ -> func
b. views.py(参数是必须的,包含了所有的客户端请求信息)
def func(request):
...
return HttpResponse('字符串') return HttpResponse(bytes('字符串')),可以返回字符串以及字节
return render(request,'index.html',{{''}}) 渲染页面
return ret('URL') 页面跳转
c. 模板语言
return render(request,'index.html',{{'l1':[11,22,33]}})
{%for item in..%}
<h1>{{item}}</h1>
{{endfor}}
只要有for就有forloop
forloop.counter counter的意思是循环一次+1,初始值为0
forloop.revcounter counter的意思是循环一次-1,最后值为0
forloop last
{{for}}
{{if num = 1}}
return true
{{endif}}
{{endfor}}
request.Get: 获取数据
request.POAT: 提交数据
request.FILES #获取文件信息
u = request.POST.get('user') #get只能获取一个值 radio
v = request.POST.getlist('favor') #getlist 获取多个值,列表;一般用于CheckBox,select-option多选组合等
# django处理文件一般是用request.FILES,request.FILES.get是获取文件信息,默认返回是文件名称 obj = request.FILES.get('file') print(obj,type(obj)) import os file_path = os.path.join('upload',obj.name) #上传文件 f = open(file_path,mode='wb') # chunks 相当于一段段获取文件信息 for i in obj.chunks(): f.write(i) f.close()
#要上传文件,需要再form上面加上enctype="multipart/form-data"#}
<form action="/login/" method="post" enctype="multipart/form-data"> </form>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {#要上传文件,需要再form上面加上enctype="multipart/form-data"#} <form action="/login/" method="post" enctype="multipart/form-data"> <p> <input type="text"name="user" placeholder="用户名"/> </p> <p> <input type="password"name="pwd" placeholder="密码"/> </p> <p> 男<input type="radio" name="gender" value="1" /> 女<input type="radio" name="gender" value="2" /> 中<input type="radio" name="gender" value="3" /> </p> <p> 篮球<input type="checkbox" name="favor" value="11" /> 足球<input type="checkbox" name="favor" value="22" /> 排球<input type="checkbox" name="favor" value="33" /> </p> <p> {# 多了multiple,可以多选,所以后端必须写收取多个值的getlist#} <select name="city" multiple> <option value="sh">上海</option> <option value="bj">北京</option> <option value="tj">天津</option> </select> </p> <p> <input type="file" value="上传文件" name="file" /> </p> <input type="submit" value="提交" /> </form> </body> </html>
获取字典信息:
user_dict.keys #字典的key
user_dict.values #字典的value
user_dict.items #字典的key和value
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <ul> {% for k in user_dict.keys %} <li>{{ k }}</li> {% endfor %} <p></p> {% for v in user_dict.values %} <li>{{ v }}</li> {% endfor %} <p></p> {% for k,v in user_dict.items %} <li>{{ k }} - {{ v }}</li> {% endfor %} </ul> </body> </html>
类的操作:
客户端发送信息到服务器,经过from django.views import View的View的dispatch,将方法转换为小写英文之后,进行反射到对应的方法
def dispatch(self, request, *args, **kwargs): ''' 调用父类中的dispatch,进行重写,这样可以实现类似装饰器那样的功能 ''' print('before') result = super(Home,self).dispatch(request, *args, **kwargs) print('after') return result
from django.shortcuts import render from django.shortcuts import HttpResponse # Create your views here. def index(request): return HttpResponse('Index') from django.views import View class Home(View): def dispatch(self, request, *args, **kwargs): ''' 调用父类中的dispatch,进行重写,这样可以实现类似装饰器那样的功能 ''' print('before') result = super(Home,self).dispatch(request, *args, **kwargs) print('after') return result def get(self,request): ''' 如果是get方法获取,则执行这个方法 :param request: :return: ''' print(request.method) return render(request,'home.html') def post(self,request): ''' 如果是post方法获取,则执行这个方法 :param request: :return: ''' print(request.method) return render(request,'home.html')
"""day19 URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.0/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path from migrations import views urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), # 关联类的固定写法,关联类Home的as_view方法 path('home/', views.Home.as_view()), ]
一、路由系统,URL
1、url(r'^index/', views.index), url(r'^home/', views.Home.as_view()), 2、url(r'^detail-(\d+).html', views.detail), 3、url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)(推荐使用这个,配合下图的代码使用)
4、url('index/',views.index,name='indexx'),
url.py
url(r'^datail-(\d+).html', views.datail),
views.py
def datail(request,nid):
user_info = USER_DICT[nid]
return render(request,'detail.html',{"user_info":user_info})
index.html
{% for k,v in user_dict.items %}
<li> <a target="_blank" href="/datail-{{ k }}.html">{{ v.username }}</a></li>
{% endfor %}
建议使用的方法:
url.py: url('index/',views.index,name='indexx'),
<form action='{% url "indexx" %}' method="post"> <p> <input type="text" name="user" placeholder="用户名" /> </p> <p> <input type="text" name="email" placeholder="邮箱" /> </p> <p> <input type="submit" value="提交" /> </p> </form>
name:
对URL路由关系进行命名,以后可以根据此名称生成自己想要的URL
url('index/',views.index,name='indexx')
url('index/(\d+)/(\d+)/',views.index,name='indexx')
url('index/(?P<pid>\d+)/(?P<uid>\d+)/',views.index,name='indexx')
模板语言:
{% url "indexx" %}
{% url "indexx 3 4" %}
注意:request.path_info #当前的URL
当请求过来的时候,优先匹配project同名目录下的urls.py,然后再分发给其他目录下的urls.py
默认值
二、视图
三、模板
四、ORM操作
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'back_logs', 'USER':'root', 'PASSWORD': 'Choice123', 'HOST':'localhost', 'PORT':'3306' } } # 如果想用mysql数据库 # DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.mysql', # 'NAME': 'dbname', # 'USER':'root', # 'PASSWORD': 'XXX', # 'HOST':'', # 'PORT':',' # } # }
修改之后,需要再init.py文件里面写入代码
import pymysql
pymysql.install_as_MySQLdb()
select * from tb where id > 1
#对应关系
models.tb.objects.filter(id__gt=1) #id大于1
models.tb.objects.filter(idt=1) #id等于1
models.tb.objects.filter(id__lt=1) #id小于1
创建类
1、根据类自动创建数据库表
#app下的models.py 先写类
# 必须要继承models.Model # 表名叫:app01_userinfo class UserInfo(models.Model): # id列,自增,主键(django自动创建) # 用户名列,字符串类型,指定长度 username = models.CharField(max_length=32) # 密码列,字符串类型,指定长度 password = models.CharField(max_length=64)
注册app:
settings.py文件下,找到INSTALLED_APPS,增加app目录名称(# django会根据这里找app01目录下的migrations)
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # django会根据这里找app01目录下的migrations 'app01', ]
然后执行命令:
python manage.py makemigrations
python manage.py migrate
model操作
参考:https://www.cnblogs.com/wupeiqi/articles/6216618.html
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # 如果想用mysql数据库 # DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.mysql', # 'NAME': 'dbname', # 'USER':'root', # 'PASSWORD': 'XXX', # 'HOST':'', # 'PORT':',' # } # }
注意:如果需要使用mysql,但是我们之前使用的是pymysql,不是django默认的MySQLdb模块连接mysql,所以需要在project同名文件夹下的__init__.py文件下增加代码
import pymysql
pymysql.install_as_MySQLdb()
2、根据类对数据库表中的数据进行各种操作
from django.shortcuts import render from django.shortcuts import HttpResponse from django.shortcuts import redirect # Create your views here. def login(request): return HttpResponse('login') from app01 import models def orm(request): # 创建信息方法一(推荐使用) models.UserInfo.objects.create( username = 'root', password='123' ) # 方法一可以写成 # dic = {'username' : 'root','password':'123'} # models.UserInfo.objects.create(**dic) # 创建信息方法二 # obj = models.UserInfo(username = 'root', password='123') # obj.save() return HttpResponse('orm')
v = models.Business.objects.all()
# 查找特定的列,类似select id,caption from business
v = models.Business.objects.all().values('id','caption')
from django.shortcuts import render from django.shortcuts import HttpResponse from django.shortcuts import redirect # Create your views here. def login(request): return HttpResponse('login') from app01 import models def orm(request): # 创建信息方法一(推荐使用) # models.UserInfo.objects.create( # username = 'root', # password='123' # ) # 方法一可以写成 # dic = {'username' : 'root','password':'123'} # models.UserInfo.objects.create(**dic) # 创建信息方法二 # obj = models.UserInfo(username = 'root', password='123') # obj.save() # 查 # 表里面所有的数据都被取出,返回QuerySet类型,理解为列表[obj,obj,obj] # result = models.UserInfo.objects.all() # print(result) # for row in result: # print(row.id,row.username,row.password) # 根据条件查出表里的数据,返回QuerySet类型 result = models.UserInfo.objects.filter(username='root') for row in result: print(row.id, row.username, row.password) return HttpResponse('orm')
from django.shortcuts import render from django.shortcuts import HttpResponse from django.shortcuts import redirect # Create your views here. def login(request): return HttpResponse('login') from app01 import models def orm(request): # 创建信息方法一(推荐使用) # models.UserInfo.objects.create( # username = 'root', # password='123' # ) # 方法一可以写成 # dic = {'username' : 'root','password':'123'} # models.UserInfo.objects.create(**dic) # 创建信息方法二 # obj = models.UserInfo(username = 'root', password='123') # obj.save() # 查 # 表里面所有的数据都被取出,返回QuerySet类型,理解为列表[obj,obj,obj] # result = models.UserInfo.objects.all() # print(result) # for row in result: # print(row.id,row.username,row.password) # 根据条件查出表里的数据,返回QuerySet类型 # result = models.UserInfo.objects.filter(username='root') # for row in result: # print(row.id, row.username, row.password) # 删除 # 删除表的所有数据 models.UserInfo.objects.all().delete() # 删除表里id为1的数据 models.UserInfo.objects.filter(id=1).delete() return HttpResponse('orm')
from django.shortcuts import render from django.shortcuts import HttpResponse from django.shortcuts import redirect # Create your views here. def login(request): return HttpResponse('login') from app01 import models def orm(request): # 创建信息方法一(推荐使用) # models.UserInfo.objects.create( # username = 'root', # password='123' # ) # 方法一可以写成 # dic = {'username' : 'root','password':'123'} # models.UserInfo.objects.create(**dic) # 创建信息方法二 # obj = models.UserInfo(username = 'root', password='123') # obj.save() # 查 # 表里面所有的数据都被取出,返回QuerySet类型,理解为列表[obj,obj,obj] # result = models.UserInfo.objects.all() # print(result) # for row in result: # print(row.id,row.username,row.password) # 根据条件查出表里的数据,返回QuerySet类型 # result = models.UserInfo.objects.filter(username='root') # for row in result: # print(row.id, row.username, row.password) # 删除 # # 删除表的所有数据 # models.UserInfo.objects.all().delete() # # # 删除表里id为1的数据 # models.UserInfo.objects.filter(id=1).delete() # 更新 # 表中所有数据的列password改为666 models.UserInfo.objects.all().update(password=666) # 表中id为3 的行,password字段改为6669 models.UserInfo.objects.filter(id=3).update(password=6669) return HttpResponse('orm')
from django.shortcuts import render from app01 import models # Create your views here. def business(request): # 获取数据,保存为queryset列表 v = models.Business.objects.all() # 查找特定的列,类似select id,caption from business,返回的是字典 v2 = models.Business.objects.all().values('id','caption') # 查询获取的结果,返回的是元组 v3 = models.Business.objects.all().values_list('id','caption') return render(request,'business.html',{'v':v,"v2":v2,"v3":v3})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>业务线列表(对象)</h1> {% for row in v %} <ul>{{ row.id }}-{{ row.caption }}-{{ row.code }}</ul> {% endfor %} <h1>业务线列表(字典)</h1> {% for row in v2 %} <ul>{{ row.id }}-{{ row.caption }}</ul> {% endfor %} <h1>业务线列表(元组)</h1> {% for row in v3 %} <ul>{{ row.0 }}-{{ row.1 }}</ul> {% endfor %} </body> </html>
外键:
# 与表Business关联,to是关联的表,to_field是关联的字段
b = models.ForeignKey(to="Business",to_field='id',on_delete=models.CASCADE)
如果没有明确写明主键,默认id就是外键
当删除关联表中的数据时,当前表与其关联的行的行为 - models.CASCADE,删除关联数据,与之关联也删除 - models.DO_NOTHING,删除关联数据,引发错误IntegrityError - models.PROTECT,删除关联数据,引发错误ProtectedError - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空) - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值) - models.SET,删除关联数据, a. 与之关联的值设置为指定值,设置:models.SET(值) b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
from django.db import models # Create your models here. class Business(models.Model): # 没写id,所以django自动生成 # caption = models.CharField(max_length=32) # 设置显示文字是英文还是中文; # null=True可以为空 # default='默认值' 设置新增列的默认值 code = models.CharField(max_length=32,null=True,default='默认值') class Host(models.Model): # django会自动生成id,但是也能自己写,需要加上primary_key=True,AutoField整形自增 nid = models.AutoField(primary_key=True) # 主机名,字符串,最大长度32位;db_index=True代表创建索引 hostname = models.CharField(max_length=32,db_index=True) # ip,字符串类型,但是django会自动帮我验证,protocol='both'意思是ipv4以及ipv6都支持 ip = models.GenericIPAddressField(protocol='both',db_index=True) # 端口,数字类型 port = models.IntegerField() # 与表Business关联,to是关联的表,to_field是关联的字段 b = models.ForeignKey(to="Business",to_field='id',on_delete=models.CASCADE)
用.(点)获取关联表信息
用双下划线__获取字符串里面的跨表信息
# 因为引号里面是字符串,所以使用双下杠__引用对应对象下的字段,得到结果为字典类型
v2 = models.Business.objects.all().values('nid', 'hostname', 'b_id', 'b__caption')
print(type(v2))
创建多对多:
方式一:自定义关系表
from django.db import models # Create your models here. class Business(models.Model): # 没写id,所以django自动生成 # caption = models.CharField(max_length=32) # 设置显示文字是英文还是中文; # null=True可以为空 # default='默认值' 设置新增列的默认值 code = models.CharField(max_length=32,null=True,default='默认值') class Host(models.Model): # django会自动生成id,但是也能自己写,需要加上primary_key=True,AutoField整形自增 nid = models.AutoField(primary_key=True) # 主机名,字符串,最大长度32位;db_index=True代表创建索引 hostname = models.CharField(max_length=32,db_index=True) # ip,字符串类型,但是django会自动帮我验证,protocol='both'意思是ipv4以及ipv6都支持 ip = models.GenericIPAddressField(protocol='both',db_index=True) # 端口,数字类型 port = models.IntegerField() # 与表Business关联,to是关联的表,to_field是关联的字段 b = models.ForeignKey(to="Business",to_field='id',on_delete=models.CASCADE) class Application(models.Model): ''' 应用 ''' name = models.CharField(max_length=32) class HostToApp(models.Model): ''' host app关联 ''' hobj = models.ForeignKey(to=Host,to_field='nid',on_delete=models.CASCADE) aobj = models.ForeignKey(to=Application,to_field='id',on_delete=models.CASCADE)
方式二:自动创建关系表
缺点:无法直接对第三张表进行操作
from django.db import models # Create your models here. class Business(models.Model): # 没写id,所以django自动生成 # caption = models.CharField(max_length=32) # 设置显示文字是英文还是中文; # null=True可以为空 # default='默认值' 设置新增列的默认值 code = models.CharField(max_length=32,null=True,default='默认值') class Host(models.Model): # django会自动生成id,但是也能自己写,需要加上primary_key=True,AutoField整形自增 nid = models.AutoField(primary_key=True) # 主机名,字符串,最大长度32位;db_index=True代表创建索引 hostname = models.CharField(max_length=32,db_index=True) # ip,字符串类型,但是django会自动帮我验证,protocol='both'意思是ipv4以及ipv6都支持 ip = models.GenericIPAddressField(protocol='both',db_index=True) # 端口,数字类型 port = models.IntegerField() # 与表Business关联,to是关联的表,to_field是关联的字段 b = models.ForeignKey(to="Business",to_field='id',on_delete=models.CASCADE) class Application(models.Model): ''' 应用 ''' name = models.CharField(max_length=32) # 第三张表自动生成 r = models.ManyToManyField('Host')
obj = Application.objects.get(id=1)
obj.name
若需要对第三表操作,则使用如下方法:
增加:
obj.r.add(1) 增加关系1对1
obj.r.add(2) 增加关系1对二
obj.r.add(2,3,4) 增加关系1对2,1对3,1对4
obj.r.add(*[1,2,3,4]) 增加关系1对1,1对2,1对3,1对4
删除:
obj.r.remove(1) 删除关系1对1
obj.r.remove(2,4) 删除关系1对2,1对4
obj.r.remove(*[1,2,3]) 删除关系1对1,1对2,1对3
obj.r.clear() 删除只要application是1的关系
obj.r.set([3,5,7]) 删除除了1对3,1对5,1对7之外所有的关系
获取:
obj.r.all() 这里就是增加 b_list = models.Host.objects.all() 后面all的方法;obj.r相当于 models.Host.objects。
model操作补充
单表
1.修改表名;类下定义一个类,Meta
2.联合索引;
from django.db import models # Create your models here. class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) email = models.CharField(max_length=32) class Meta: # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名 db_table = "table_name" # 联合索引 # 最左前缀的模式:select * from table_name where username ='xx' # select * from table_name where username ='xx' and email = 'xx' # 前面两个都很快,但是如果没有了最左的那个,这里是uername,速度会非常慢 index_together = [ # ("pub_date", "deadline"), ("username", "email"), ] # 联合唯一索引 unique_together = (("driver", "restaurant"),) # admin中显示的表名称,admin里面就会变成上课记录s verbose_name = '上课记录' # verbose_name加s,表名就会变成上课记录 verbose_name_plural = '上课记录'
一对多,一对一,多对多
django现在的版本会对外键关联的表的数据都删除
ForeignKey(ForeignObject) # ForeignObject(RelatedField) to, # 要进行关联的表名 to_field=None, # 要关联的表中的字段名称 on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为 - models.CASCADE,删除关联数据,与之关联也删除 - models.DO_NOTHING,删除关联数据,引发错误IntegrityError - models.PROTECT,删除关联数据,引发错误ProtectedError - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空) - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值) - models.SET,删除关联数据, a. 与之关联的值设置为指定值,设置:models.SET(值) b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象) def func(): return 10 class MyModel(models.Model): user = models.ForeignKey( to="User", to_field="id" on_delete=models.SET(func),) related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件: # 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') db_constraint=True # 是否在数据库中创建外键约束 parent_link=False # 在Admin中是否显示关联数据 OneToOneField(ForeignKey) to, # 要进行关联的表名 to_field=None # 要关联的表中的字段名称 on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为 ###### 对于一对一 ###### # 1. 一对一其实就是 一对多 + 唯一索引 # 2.当两个类之间有继承关系时,默认会创建一个一对一字段 # 如下会在A表中额外增加一个c_ptr_id列且唯一: class C(models.Model): nid = models.AutoField(primary_key=True) part = models.CharField(max_length=12) class A(C): id = models.AutoField(primary_key=True) code = models.CharField(max_length=1) ManyToManyField(RelatedField) to, # 要进行关联的表名 related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件: # 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段 # 做如下操作时,不同的symmetrical会有不同的可选字段 models.BB.objects.filter(...) # 可选字段有:code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=True) # 可选字段有: bb, code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=False) through=None, # 自定义第三张表时,使用字段用于指定关系表 through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表 from django.db import models class Person(models.Model): name = models.CharField(max_length=50) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField( Person, through='Membership', through_fields=('group', 'person'), ) class Membership(models.Model): group = models.ForeignKey(Group, on_delete=models.CASCADE) person = models.ForeignKey(Person, on_delete=models.CASCADE) inviter = models.ForeignKey( Person, on_delete=models.CASCADE, related_name="membership_invites", ) invite_reason = models.CharField(max_length=64) db_constraint=True, # 是否在数据库中创建外键约束 db_table=None, # 默认创建第三张表时,数据库中表的名称
class UserType(models.Model): name = models.CharField(max_length=32) class User(models.Model): user = models.CharField(max_length=32) pwd = models.CharField(max_length=64) ut = models.ForeignKey( to='UserType', to_field='id', on_delete=models.CASCADE )
# 正向操作 v = User.objects.all() for item in v: item.user item.pwd item.ut.name User.objects.all().values('user','ut__name') # 反向操作 v = UserType.objects.all() for item in v: item.name item.id # 当前类型对应的所有用户的集合 item.user_set.all() # 表名__字段 反向查找内容 UserType.objects.all().values('name','user__pwd')
如果加上related_name='b',反向查找就会将表名变更为b,如:UserType.objects.all().values('name','b__pwd')
Ajax:
参考:https://www.cnblogs.com/wupeiqi/articles/5703697.html
建议:永远让服务器端返回一个字典,使用return HttpResponse(json.dumps(字典))
不能用redirect
悄悄的提交,用Ajax $.ajax({ url:"/host", type:"POST" data:{"k1":123,"k2":"root"} success:function(data){ //函数等服务器返回信息后,自动触发,返回的数据会放到data里,所以需要一个参数 } }) location.reload() Jqery刷新页面
location.href = "某个地址" 跳转到其他页面
$.get(url='xxx',data={})
$.getJson
$.post
不管是哪个方法,都调用了$.ajax方法
ajax return的时候用HttpResponse()
js转换json
var obj = JSON.parse() 字符串转换为其他
JSON.stringfy() 转换为字符串
traditional:true 允许发送列表
dataType: 写上这句,ajax会自动对接从服务器接收到的字符串反序列化
$(function () { $('#add_submit_ajax').click(function () { $.ajax({ url:'/ajax_add_app', {# data:{'user':123,'host_list':[1,2,3]},#} data:$('#add_form').serialize(), type:"POST", {# 允许发送列表#} traditional:true, {# 写上这句就能让其自动反序列化,所以传递进入函数的就变成了对象#} dataType:"JSON", success:function (obj) { console.log(obj) location.reload() }, {# 若是拿去数据不成功的时候执行的函数#} error:function () { } }) }); }
要想知道request对象里面有什么东西,就要知道这个对象是从哪个类生成的,然后查看对应类的函数,如type(request)查出对应类,然后导入查看
{# 若是要用POST方式发送的情况,必须要写上请求头说明发送的方式告知后端如何获取信息 #}
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="Ajax1" onclick="Ajax1()" /> <script> function Ajax1() { var xhr = new XMLHttpRequest(); {# 指定发送方式,以及发送到哪里 true是否异步#} xhr.open('GET','/ajax_json/',true); xhr.onreadystatechange = function () { if(xhr.readyState = 4){ //有四种状态,当readyState等于4的时候就是接收数据完毕状态,显示对应的值 {# console.log(xhr.responseText);#} var obj = JSON.parse(xhr.responseText); console.log(obj); } }; {# 发送请求头#} xhr.setRequestHeader('k1','v1'); {# 若是要用POST方式发送的情况,必须要写上请求头说明发送的方式告知后端如何获取信息 #} xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8'); {# 发送数据#} xhr.send("name=root;pwd=123"); } </script> </body> </html>
def ajax_json(request): ret = {'status':True,'data':None} import json return HttpResponse(json.dumps(ret))
发送文件时机: iframe =》jQuery(依赖FormData),XMLHttpRequest(FormData)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .upload{ {# position: absolute;#} display: inline-block; padding: 10px; background-color: brown; top:0; bottom: 0; right: 0; left:0; z-index:90; } .file{ position: absolute; width: 100px; height: 50px; opacity: 0; top:0; bottom: 0; right: 0; left:0; z-index:100; } </style> </head> <body> <div style="position: relative;width: 100px;height: 50px;"> <input class="file" type="file" id="fafa" name="ff" /> <a class="upload">上传</a> </div> <input type="button" value=" 提交" onclick="xhrSubmit();" /> <input type="button" value=" JQ提交" onclick="JQSubmit();" /> <hr> <form action="/upload_file/" method="post"target="ifm1" enctype="multipart/form-data"> {% csrf_token %} <iframe id="ifm1" name="ifm1"></iframe> <input type="file" name="fafa" /> <input type="submit" onclick="iframeSubmit();" value="Form提交" /> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function JQSubmit() { {# $('#fafa')[0]相当于下面#} {# .files[0];代表要上传的文件对象#} var file_obj = document.getElementById('fafa').files[0]; var fd = new FormData(); fd.append('fafa',file_obj); fd.append('username','root'); $.ajax({ url:'/upload_file/', type:'POST', data:fd, {# processData:false, contentType:false,表名上传文件的时候不要做特殊处理,这样才能正确传递文件#} processData:false, contentType:false, sucess:function (arg,a1,a2) { console.log(arg); console.log(a1); console.log(a2); } }) } function xhrSubmit() { {# $('#fafa')[0]相当于下面#} {# .files[0];代表要上传的文件对象#} var file_obj = document.getElementById('fafa').files[0]; var fd = new FormData(); fd.append('fafa',file_obj); fd.append('username','root'); var xhr = new XMLHttpRequest(); xhr.open('POST','/upload_file/',true); xhr.onreadystatechange = function () { if(xhr.readyState = 4){ var obj = Json.parse(xhr.responseText); } }; xhr.send(fd); } {# 前面两种方法都存在浏览器兼容问题,而这个 iframe提交文件,兼容性强#} function iframeSubmit() { $('#ifm1').load(function () { {# iframe比较特殊,需要先用$('#ifm1').contents()找到下面对应的HTML,然后找里面body的内容#} var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); }) } </script> </body> </html>
增加了预览图片,以及选中文件就上传
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .upload{ {# position: absolute;#} display: inline-block; padding: 10px; background-color: brown; top:0; bottom: 0; right: 0; left:0; z-index:90; } .file{ position: absolute; width: 100px; height: 50px; opacity: 0; top:0; bottom: 0; right: 0; left:0; z-index:100; } </style> </head> <body> <div style="position: relative;width: 100px;height: 50px;"> <input class="file" type="file" id="fafa" name="ff" /> <a class="upload">上传</a> </div> <input type="button" value=" 提交" onclick="xhrSubmit();" /> <input type="button" value=" JQ提交" onclick="JQSubmit();" /> <hr> <form id="fm1" action="/upload_file/" method="post"target="ifm1" enctype="multipart/form-data"> {% csrf_token %} <iframe id="ifm1" name="ifm1" style="display: none"></iframe> <input type="file" name="fafa" onchange="changeUpload();"/> <input type="submit" onclick="iframeSubmit();" value="Form提交" /> </form> <div id="preview"> </div> <script src="/static/jquery-1.12.4.js"></script> <script> function changeUpload() { {# 让form表单改变就提交#} $('#ifm1').load(function () { {# iframe比较特殊,需要先用$('#ifm1').contents()找到下面对应的HTML,然后找里面body的内容#} var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); {# 将原来的图片清空了,才能显示新图片#} $('#preview').empty(); {# 建立图片标签#} var imgTag = document.createElement('img'); {# 因为服务器传递过来的数据是没有前面的/,所以需要加上#} imgTag.src='/'+obj.data; $('#preview').append(imgTag); }); $('#fm1').submit(); } function JQSubmit() { {# $('#fafa')[0]相当于下面#} {# .files[0];代表要上传的文件对象#} var file_obj = document.getElementById('fafa').files[0]; var fd = new FormData(); fd.append('fafa',file_obj); fd.append('username','root'); $.ajax({ url:'/upload_file/', type:'POST', data:fd, {# processData:false, contentType:false,表名上传文件的时候不要做特殊处理,这样才能正确传递文件#} processData:false, contentType:false, sucess:function (arg,a1,a2) { console.log(arg); console.log(a1); console.log(a2); } }) } function xhrSubmit() { {# $('#fafa')[0]相当于下面#} {# .files[0];代表要上传的文件对象#} var file_obj = document.getElementById('fafa').files[0]; var fd = new FormData(); fd.append('fafa',file_obj); fd.append('username','root'); var xhr = new XMLHttpRequest(); xhr.open('POST','/upload_file/',true); xhr.onreadystatechange = function () { if(xhr.readyState = 4){ var obj = Json.parse(xhr.responseText); } }; xhr.send(fd); } {# 前面两种方法都存在浏览器兼容问题,而这个 iframe提交文件,兼容性强#} function iframeSubmit() { $('#ifm1').load(function () { {# iframe比较特殊,需要先用$('#ifm1').contents()找到下面对应的HTML,然后找里面body的内容#} var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); {# 将原来的图片清空了,才能显示新图片#} $('#preview').empty(); {# 建立图片标签#} var imgTag = document.createElement('img'); {# 因为服务器传递过来的数据是没有前面的/,所以需要加上#} imgTag.src='/'+obj.data; $('#preview').append(imgTag); }) } </script> </body> </html>
from django.shortcuts import render,HttpResponse from django import forms from django.forms import fields from django.forms import fields as Ffields from app01 import models # Create your views here. # 避免跟modelform的属性冲突,更名为Fwidgets from django.forms import widgets as Fwidgets # # modelform方式 class UserInfoModelForm(forms.ModelForm): # 自定义字段,跟保存在数据库上没关系,例如一个月内免登陆的CheckBox is_rmb = Ffields.CharField( widget=Fwidgets.CheckboxInput() ) class Meta: # 这里指定字段对应的表 model =models.UserInfo # __all__代表多有的字段 fields = '__all__' # 只显示的字段 # fields = ['username','email'] # 排除字段,其他的显示 # exclude = ['email'] # 显示标签更名 labels = { 'username':'用户名', 'email':'邮箱' } # help_texts = { 'username':'帮助信息' } # 将原来的CharField改为为Textarea widgets = { 'username':Fwidgets.Textarea(attrs={'class':'c1'}) } error_messages = { '__all__':'所有字段共同的错误', # email的错误信息 'email':{ 'required':'邮箱不能为空', 'invalid':'邮箱格式错误' } } # 更改格式, # field_classes = { # # 将email的格式从邮箱给为url格式,这里是填写类,不是带括号的对象 # 'email': Ffields.URLField # } # form方式 class UserInfoForm(forms.Form): # 定义字段 username = fields.CharField(max_length=32,label='用户名') email = fields.EmailField(label='邮件') # 将数据库的id caption字段作为下拉显示 user_type = fields.ChoiceField( choices = models.UserType.objects.values_list('id','caption'), label='类型' ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) # 这样子就能更新数据库不需要重启程序就能更新数据 self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption') def index(request): if request.method == 'GET': # 创建对象,会在前段自动生成对应的标签 obj = UserInfoModelForm() return render(request,'index.html',{'obj':obj}) # return render(request,'index.html') elif request.method == 'POST': # 创建对象,会在前段自动生成对应的标签 obj = UserInfoModelForm(request.POST) if obj.is_valid(): # obj.save() # 上面一句包含了下面三句代码,只不过默认传入commit=True instance = obj.save(False) instance.save() obj.save_m2m() # print(obj.is_valid()) # print(obj.cleaned_data) # print(obj.errors) # obj.cleaned_data return render(request, 'index.html', {'obj': obj}) def user_list(request): li = models.UserInfo.objects.all().select_related('user_type') return render(request,'user_list.html',{'li':li}) def user_edit(request,nid): # 获取当前id对象的用户信息 # 显示用户已经存在的数据 if request.method == "GET": user_obj = models.UserInfo.objects.filter(id=nid).first() mf = UserInfoModelForm(instance=user_obj) return render(request,'user_edit.html',{'mf':mf,'nid':nid}) elif request.method == 'POST': user_obj = models.UserInfo.objects.filter(id=nid).first() # instance=user_obj)告诉数据库要更新的是哪个对象 mf = UserInfoModelForm(request.POST,instance=user_obj) if mf.is_valid(): mf.save() else: print(mf.errors.as_json()) return render(request, 'user_edit.html', {'mf': mf, 'nid': nid}) def ajax(request): return render(request,'ajax.html') def ajax_json(request): ret = {'status':True,'data':request.POST.get('username')} import json return HttpResponse(json.dumps(ret)) def upload(request): return render(request,'upload.html') def upload_file(request): username = request.POST.get('username') fafa = request.FILES.get('fafa') import os img_path = os.path.join('static','imgs',fafa.name) print(img_path) # img_path = fafa.name with open(img_path,'wb') as f: for item in fafa.chunks(): f.write(item) ret = {'code':True,'data':img_path} print(username,fafa) import json return HttpResponse(json.dumps(ret))
session+验证码图片
1.创建一张图片
2.在图片中写入随机字符串
3.将图片写入到指定文件中
4.打开制定目录文件,读取内容
5.HTTPResponse(data)
需要用到session,check_code.py(依赖:Pillow,字体文件),点一次就变化的话,需要src属性后面加?
HTML模板继承
注意:只能继承一个模板
头顶要写上继续哪个模板 {% extends '模板名 %}
{% extends 'master.html' %}
被继承的模板写成:{% block 模板名%} {% endblock %}
{% block content %} {% endblock %}
继承的模板写成 (block模块位置是没所谓的)
{% block 模板名%} 替换的内容 {% endblock %}
模板的导入(导入可以导入多个模板)
{% include '模板名' %}
{% include 'tag.html' %}
<form> <input type="text" /> <input type="submit" /> </form>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% include 'tag.html' %} {% include 'tag.html' %} </body> </html>
django自带的方法:
帮助方法:
{{ item.event_start|date:"Y-m-d H:i:s"}}
{{ bio|truncatewords:"30" }} # 获取前30个字符,进行分割
{{ my_list|first|upper }} # 第一个字符转换为大写
{{ name|lower }} #转换为小写
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p></p> {{ name }} <div></div> {{ name | lower }} </body> </html>
自定义simple_tag
优点:参数任意
缺点:不能作为if条件
1.在某个APP目录下创建一个目录templatetags(必须是这个名字)
2.templatetags目录下创建.py文件
3.创建template对象 必须为register 请参考下面代码
from django import template from django.utils.safestring import mark_safe # 装饰器,名字不能修改,必须为register register = template.Library() @register.simple_tag def houyafan(a1,a2): return a1 + a2
4.settings注册app
5.HTML文件顶部写上{% load py文件名 %}: {% load xxoo %}
6.{% 函数名 参数a1 参数a2 %} {% houyafan 2 5 %}
自定义simple_filter
优点:能作为if条件
缺点:参数任意,不能加空格
步骤与simple_tag一样,
写法:
{{ '参数1'|函数名:'参数2,参数三' }}
{{ '字符串'|filter_test:'相加,参数三' }}
from django import template from django.utils.safestring import mark_safe # 装饰器,名字不能修改,必须为register register = template.Library() # filter最多传递两个值 @register.filter def filter_test(a1,a2): return a1 + a2
{% load xxoo %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% houyafan 2 5 %} {# 不能加空格#} {{ '字符串'|filter_test:'相加' }} {# 如果需要传递三个以上参数,只能这样弄#} {# 这种方式一般用于if else里面#} {{ '字符串'|filter_test:'相加,参数三' }} {% if '字符串'|filter_test:'相加' %} 显示 {% endif %} {# {% include 'tag.html' %}#} {# {% include 'tag.html' %}#} {#<p></p>#} {# {{ name }}#} {#<div></div>#} {# {{ name | lower }}#} </body> </html>
分页
XSS攻击:默认传递带有HTML语言的字符串是不安全的,不会做解析
后端需要加上
from django.utils.safestring import mark_safe
page_str='''<a href="/user_list/?p=2">1 </a>'''
page_str = mark_safe(page_str)
前端需要这样写
{{ page_str|safe }}
from django.shortcuts import render,HttpResponse from django.shortcuts import redirect from django.utils.safestring import mark_safe from app01 import models import json # Create your views here. def business(request): # 获取数据,保存为queryset列表 v = models.Business.objects.all() # 查找特定的列,类似select id,caption from business,返回的是字典 v2 = models.Business.objects.all().values('id','caption') # 查询获取的结果,返回的是元组 v3 = models.Business.objects.all().values_list('id','caption') return render(request,'business.html',{'v':v,"v2":v2,"v3":v3}) def host(request): if request.method == "GET": v = models.Business.objects.filter(host__nid__gt=0) # # 因为引号里面是字符串,所以使用双下杠__引用对应对象下的字段,得到结果为字典类型 # v2 = models.Business.objects.all().values('nid', 'hostname', 'b__id', 'b__caption') # print(type(v2)) # for row in v2: # print(row['nid'], row['hostname'], row['b_id'], row['b__caption']) # # 因为引号里面是字符串,所以使用双下杠__引用对应对象下的字段,得到结果为元组,下标安装下方的写的参数从0排序+1 # v3 = models.Business.objects.all().values_list('nid', 'hostname', 'b_id', 'b__caption') # print(type(v3)) b_list = models.Host.objects.all() for row in b_list: print(row.hostname) return render(request, 'host.html', {"v": v,'b_list':b_list}) # return render(request,'host.html',{"v":v,"v2":v2,"v3":v3}) elif request.method == 'POST': h = request.POST.get('hostname') i = request.POST.get('ip') p = request.POST.get('port') b = request.POST.get('b_id') print(h) print(i) print(p) print(b) models.Host.objects.create(hostname = h, ip = i, port = p, b_id = b ) return redirect('/host/') def test_ajax(request): # request.GET.get('pwd',sep='\t')获取pwd的值,并且隔开 # print(request.method,request.GET.get('user'),request.GET.get('pwd',sep='\t')) ret = {'status': True, 'error': None, 'data': None} try: h = request.POST.get('hostname') i = request.POST.get('ip') p = request.POST.get('port') b = request.POST.get('b_id') print(h) print(i) print(p) print(b) if h and len(h) > 5: models.Host.objects.create(hostname=h, ip=i, port=p, b_id=b ) else: ret['status'] = False ret['error'] = '太短了' except Exception as e: ret['status'] = False ret['error'] = '请求错误' return HttpResponse(json.dumps(ret)) def app(request): if request.method == 'GET': app_list = models.Application.objects.all() for row in app_list: print(row.name,row.r.all()) host_list = models.Host.objects.all() return render(request,'app.html',{'app_list':app_list,'host_list':host_list}) elif request.method == 'POST': app_name = request.POST.get('app_name') host_list = request.POST.getlist('host_list') print(app_name,host_list) obj = models.Application.objects.create(name = app_name) obj.r.add(*host_list) return redirect('/app/') def ajax_add_app(request): ret = {'status':True,'error':None,"data":None} app_name = request.POST.get('app_name') host_list =request.POST.getlist('host_list') obj = models.Application.objects.create(name=app_name) obj.r.add(*host_list) return HttpResponse(json.dumps(ret)) def index(request): name = 'QWERTYU' return render(request,'index.html',{'name':name}) LIST = [] for i in range(109): LIST.append(i) def user_list(request): # 当前页,获取p的值,若没有值的时候,默认为1 current_page = request.GET.get('p',1) # 传递过来的是字符串,这边是数字计算的 current_page = int(current_page) start = (current_page-1) * 10 end = current_page * 10 li = LIST[start:end] all_count = len(LIST) # divmod方法是除以多少余多少,这里是除以10,余多少。y为余数 count,y = divmod(all_count,10) # 如果有余数,分页数需要+1 if y: count +=1 page_list = [] for i in range(1,count+1): # 如果i等于当前页。将当前页颜色变一下 if i == current_page: temp = '<a class="page active" href="/user_list/?p=%s">%s</a>' %(i,i) else: temp = '<a class="page" href="/user_list/?p=%s">%s</a>' %(i,i) page_list.append(temp) page_str = " ".join(page_list) page_str = mark_safe(page_str) return render(request,'user_list.html',{'li':li,'page_str':page_str})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .pagenation .page{ display: inline-block; padding: 5px; background-color: grey; margin: 5px; } .pagenation .page.active{ background-color: brown; color: white; } </style> </head> <body> <ul> {% for item in li %} {% include 'li.html' %} {% endfor %} </ul> <div class="pagenation"> {{ page_str }} </div> </body> </html>
"""day20 URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.0/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^user_list/$', views.user_list), ]
from django.shortcuts import render,HttpResponse from django.shortcuts import redirect from django.utils.safestring import mark_safe from app01 import models import json # Create your views here. def business(request): # 获取数据,保存为queryset列表 v = models.Business.objects.all() # 查找特定的列,类似select id,caption from business,返回的是字典 v2 = models.Business.objects.all().values('id','caption') # 查询获取的结果,返回的是元组 v3 = models.Business.objects.all().values_list('id','caption') return render(request,'business.html',{'v':v,"v2":v2,"v3":v3}) def host(request): if request.method == "GET": v = models.Business.objects.filter(host__nid__gt=0) # # 因为引号里面是字符串,所以使用双下杠__引用对应对象下的字段,得到结果为字典类型 # v2 = models.Business.objects.all().values('nid', 'hostname', 'b__id', 'b__caption') # print(type(v2)) # for row in v2: # print(row['nid'], row['hostname'], row['b_id'], row['b__caption']) # # 因为引号里面是字符串,所以使用双下杠__引用对应对象下的字段,得到结果为元组,下标安装下方的写的参数从0排序+1 # v3 = models.Business.objects.all().values_list('nid', 'hostname', 'b_id', 'b__caption') # print(type(v3)) b_list = models.Host.objects.all() for row in b_list: print(row.hostname) return render(request, 'host.html', {"v": v,'b_list':b_list}) # return render(request,'host.html',{"v":v,"v2":v2,"v3":v3}) elif request.method == 'POST': h = request.POST.get('hostname') i = request.POST.get('ip') p = request.POST.get('port') b = request.POST.get('b_id') print(h) print(i) print(p) print(b) models.Host.objects.create(hostname = h, ip = i, port = p, b_id = b ) return redirect('/host/') def test_ajax(request): # request.GET.get('pwd',sep='\t')获取pwd的值,并且隔开 # print(request.method,request.GET.get('user'),request.GET.get('pwd',sep='\t')) ret = {'status': True, 'error': None, 'data': None} try: h = request.POST.get('hostname') i = request.POST.get('ip') p = request.POST.get('port') b = request.POST.get('b_id') print(h) print(i) print(p) print(b) if h and len(h) > 5: models.Host.objects.create(hostname=h, ip=i, port=p, b_id=b ) else: ret['status'] = False ret['error'] = '太短了' except Exception as e: ret['status'] = False ret['error'] = '请求错误' return HttpResponse(json.dumps(ret)) def app(request): if request.method == 'GET': app_list = models.Application.objects.all() for row in app_list: print(row.name,row.r.all()) host_list = models.Host.objects.all() return render(request,'app.html',{'app_list':app_list,'host_list':host_list}) elif request.method == 'POST': app_name = request.POST.get('app_name') host_list = request.POST.getlist('host_list') print(app_name,host_list) obj = models.Application.objects.create(name = app_name) obj.r.add(*host_list) return redirect('/app/') def ajax_add_app(request): ret = {'status':True,'error':None,"data":None} app_name = request.POST.get('app_name') host_list =request.POST.getlist('host_list') obj = models.Application.objects.create(name=app_name) obj.r.add(*host_list) return HttpResponse(json.dumps(ret)) def index(request): name = 'QWERTYU' return render(request,'index.html',{'name':name}) LIST = [] for i in range(500): LIST.append(i) # def user_list(request): # # 当前页,获取p的值,若没有值的时候,默认为1 # current_page = request.GET.get('p',1) # # 传递过来的是字符串,这边是数字计算的 # current_page = int(current_page) # start = (current_page-1) * 10 # end = current_page * 10 # # li = LIST[start:end] # # all_count = len(LIST) # # divmod方法是除以多少余多少,这里是除以10,余多少。y为余数 # count,y = divmod(all_count,10) # # 如果有余数,分页数需要+1 # if y: # count +=1 # # page_list = [] # for i in range(1,count+1): # # 如果i等于当前页。将当前页颜色变一下 # if i == current_page: # temp = '<a class="page active" href="/user_list/?p=%s">%s</a>' %(i,i) # else: # temp = '<a class="page" href="/user_list/?p=%s">%s</a>' %(i,i) # page_list.append(temp) # # page_str = " ".join(page_list) # page_str = mark_safe(page_str) # # return render(request,'user_list.html',{'li':li,'page_str':page_str}) def user_list(request): # 当前页,获取p的值,若没有值的时候,默认为1 current_page = request.GET.get('p',1) # 传递过来的是字符串,这边是数字计算的 current_page = int(current_page) start = (current_page-1) * 10 end = current_page * 10 li = LIST[start:end] all_count = len(LIST) # divmod方法是除以多少余多少,这里是除以10,余多少。y为余数 total_count,y = divmod(all_count,10) # 如果有余数,分页数需要+1 if y: total_count +=1 page_list = [] # 显示页面当前页的前后五页 # start_index = current_page - 5 # end_index = current_page + 5 +1 if total_count < 11: start_index = 0 end_index = total_count else: if current_page <= 6 : start_index = 1 end_index = 11 else: start_index = current_page - 5 end_index = current_page +5 +1 if (current_page + 5) > total_count: start_index = total_count - 11 +1 end_index = total_count +1 for i in range(start_index,end_index): # 如果i等于当前页。将当前页颜色变一下 if i == current_page: temp = '<a class="page active" href="/user_list/?p=%s">%s</a>' %(i,i) else: temp = '<a class="page" href="/user_list/?p=%s">%s</a>' %(i,i) page_list.append(temp) page_str = " ".join(page_list) page_str = mark_safe(page_str) return render(request,'user_list.html',{'li':li,'page_str':page_str})
from django.shortcuts import render,HttpResponse from django.shortcuts import redirect from django.utils.safestring import mark_safe from app01 import models import json # Create your views here. def business(request): # 获取数据,保存为queryset列表 v = models.Business.objects.all() # 查找特定的列,类似select id,caption from business,返回的是字典 v2 = models.Business.objects.all().values('id','caption') # 查询获取的结果,返回的是元组 v3 = models.Business.objects.all().values_list('id','caption') return render(request,'business.html',{'v':v,"v2":v2,"v3":v3}) def host(request): if request.method == "GET": v = models.Business.objects.filter(host__nid__gt=0) # # 因为引号里面是字符串,所以使用双下杠__引用对应对象下的字段,得到结果为字典类型 # v2 = models.Business.objects.all().values('nid', 'hostname', 'b__id', 'b__caption') # print(type(v2)) # for row in v2: # print(row['nid'], row['hostname'], row['b_id'], row['b__caption']) # # 因为引号里面是字符串,所以使用双下杠__引用对应对象下的字段,得到结果为元组,下标安装下方的写的参数从0排序+1 # v3 = models.Business.objects.all().values_list('nid', 'hostname', 'b_id', 'b__caption') # print(type(v3)) b_list = models.Host.objects.all() for row in b_list: print(row.hostname) return render(request, 'host.html', {"v": v,'b_list':b_list}) # return render(request,'host.html',{"v":v,"v2":v2,"v3":v3}) elif request.method == 'POST': h = request.POST.get('hostname') i = request.POST.get('ip') p = request.POST.get('port') b = request.POST.get('b_id') print(h) print(i) print(p) print(b) models.Host.objects.create(hostname = h, ip = i, port = p, b_id = b ) return redirect('/host/') def test_ajax(request): # request.GET.get('pwd',sep='\t')获取pwd的值,并且隔开 # print(request.method,request.GET.get('user'),request.GET.get('pwd',sep='\t')) ret = {'status': True, 'error': None, 'data': None} try: h = request.POST.get('hostname') i = request.POST.get('ip') p = request.POST.get('port') b = request.POST.get('b_id') print(h) print(i) print(p) print(b) if h and len(h) > 5: models.Host.objects.create(hostname=h, ip=i, port=p, b_id=b ) else: ret['status'] = False ret['error'] = '太短了' except Exception as e: ret['status'] = False ret['error'] = '请求错误' return HttpResponse(json.dumps(ret)) def app(request): if request.method == 'GET': app_list = models.Application.objects.all() for row in app_list: print(row.name,row.r.all()) host_list = models.Host.objects.all() return render(request,'app.html',{'app_list':app_list,'host_list':host_list}) elif request.method == 'POST': app_name = request.POST.get('app_name') host_list = request.POST.getlist('host_list') print(app_name,host_list) obj = models.Application.objects.create(name = app_name) obj.r.add(*host_list) return redirect('/app/') def ajax_add_app(request): ret = {'status':True,'error':None,"data":None} app_name = request.POST.get('app_name') host_list =request.POST.getlist('host_list') obj = models.Application.objects.create(name=app_name) obj.r.add(*host_list) return HttpResponse(json.dumps(ret)) def index(request): name = 'QWERTYU' return render(request,'index.html',{'name':name}) LIST = [] for i in range(500): LIST.append(i) # def user_list(request): # # 当前页,获取p的值,若没有值的时候,默认为1 # current_page = request.GET.get('p',1) # # 传递过来的是字符串,这边是数字计算的 # current_page = int(current_page) # start = (current_page-1) * 10 # end = current_page * 10 # # li = LIST[start:end] # # all_count = len(LIST) # # divmod方法是除以多少余多少,这里是除以10,余多少。y为余数 # count,y = divmod(all_count,10) # # 如果有余数,分页数需要+1 # if y: # count +=1 # # page_list = [] # for i in range(1,count+1): # # 如果i等于当前页。将当前页颜色变一下 # if i == current_page: # temp = '<a class="page active" href="/user_list/?p=%s">%s</a>' %(i,i) # else: # temp = '<a class="page" href="/user_list/?p=%s">%s</a>' %(i,i) # page_list.append(temp) # # page_str = " ".join(page_list) # page_str = mark_safe(page_str) # # return render(request,'user_list.html',{'li':li,'page_str':page_str}) # def user_list(request): # ''' # 特定为10页的时候 # :param request: # :return: # ''' # # 当前页,获取p的值,若没有值的时候,默认为1 # current_page = request.GET.get('p',1) # # 传递过来的是字符串,这边是数字计算的 # current_page = int(current_page) # start = (current_page-1) * 10 # end = current_page * 10 # # li = LIST[start:end] # # all_count = len(LIST) # # divmod方法是除以多少余多少,这里是除以10,余多少。y为余数 # total_count,y = divmod(all_count,10) # # 如果有余数,分页数需要+1 # if y: # total_count +=1 # # page_list = [] # # 显示页面当前页的前后五页 # # start_index = current_page - 5 # # end_index = current_page + 5 +1 # if total_count < 11: # start_index = 0 # end_index = total_count # # else: # if current_page <= 6 : # start_index = 1 # end_index = 11 # else: # start_index = current_page - 5 # end_index = current_page +5 +1 # if (current_page + 5) > total_count: # start_index = total_count - 11 +1 # end_index = total_count +1 # # # for i in range(start_index,end_index): # # 如果i等于当前页。将当前页颜色变一下 # if i == current_page: # temp = '<a class="page active" href="/user_list/?p=%s">%s</a>' %(i,i) # else: # temp = '<a class="page" href="/user_list/?p=%s">%s</a>' %(i,i) # page_list.append(temp) # # page_str = " ".join(page_list) # page_str = mark_safe(page_str) # # return render(request,'user_list.html',{'li':li,'page_str':page_str}) def user_list(request): ''' :param request: :return: ''' # 当前页,获取p的值,若没有值的时候,默认为1 current_page = request.GET.get('p',1) # 传递过来的是字符串,这边是数字计算的 current_page = int(current_page) start = (current_page-1) * 10 end = current_page * 10 li = LIST[start:end] all_count = len(LIST) # divmod方法是除以多少余多少,这里是除以10,余多少。y为余数 total_count,y = divmod(all_count,10) # 如果有余数,分页数需要+1 if y: total_count +=1 page_list = [] # 显示页码多少个,这里是11,建议使用基数 perpage_num = 11 # 显示页面当前页的前后五页 # start_index = current_page - 5 # end_index = current_page + 5 +1 if total_count < perpage_num: start_index = 0 end_index = total_count else: if current_page <= (perpage_num+1)/2 : start_index = 1 end_index = perpage_num else: start_index = current_page - (perpage_num-1)/2 end_index = current_page +(perpage_num-1)/2 +1 if (current_page + (perpage_num-1)/2) > total_count: start_index = total_count - perpage_num +1 end_index = total_count +1 if current_page ==1: # javascript:void(0);这个代表什么都不干 prev = '<a class="page active" href="javascript:void(0);">上一页</a>' else: prev = '<a class="page active" href="/user_list/?p=%s">上一页</a>' %(current_page-1) page_list.append(prev) for i in range(int(start_index),int(end_index)): # 如果i等于当前页。将当前页颜色变一下 if i == current_page: temp = '<a class="page active" href="/user_list/?p=%s">%s</a>' %(i,i) else: temp = '<a class="page" href="/user_list/?p=%s">%s</a>' %(i,i) page_list.append(temp) if current_page == total_count: nex = '<a class="page active" href="javascript:void(0)">下一页</a>' else: nex = '<a class="page active" href="/user_list/?p=%s">下一页</a>' % (current_page + 1) page_list.append(nex) # 跳转 jump = ''' <input type = 'text'/><a onclick='jumpTo(this,"/user_list/?p=");'id='ii1'>GO</a> <script> function jumpTo(ths,base){ var val = ths.previousSibling.value; location.href = base + val; } </script> ''' page_list.append(jump) page_str = " ".join(page_list) page_str = mark_safe(page_str) return render(request,'user_list.html',{'li':li,'page_str':page_str})
from django.utils.safestring import mark_safe class Page: def __init__(self,current_page,data_count,per_page_count = 10, pager_num = 7): ''' :param current_page: 当前页 :param data_count: 分页总数 :param per_page_count: 每一页显示多少行,这里默认10行 :param pager_num: 分页显示多少页,这里默认7页 ''' self.current_page = current_page self.data_count = data_count self.per_page_count = per_page_count self.pager_num = pager_num # @property意思是将方法变成属性,不再需要写括号 @property def start(self): ''' 分割总行数的开始 :return: ''' return (self.current_page - 1) * self.per_page_count @property def end(self): ''' 分割总行数的结束 :return: ''' return self.current_page * self.per_page_count @property def total_count(self): ''' 计算分页页数 :return: ''' # divmod是将data_count除以per_page_count,计算出值余多少,值传入v,余数传入y v,y = divmod(self.data_count,self.per_page_count) # 如果有余数,需要增加一页分页 if y: v +=1 return v def page_str(self,base_url): ''' :param base_url:跳转的地址 :return: ''' # 传递到前端的列表,用于保存数据 page_list = [] # 如果分页总数少于默认的7页,就显示所有分页 if self.total_count < self.per_page_count: start_index = 1 end_index = self.total_count + 1 else: # 如果当前页在显示分页数的一半内 if self.current_page <= (self.pager_num + 1)/2: start_index = 1 end_index = self.pager_num + 1 else: start_index = self.current_page - (self.pager_num -1)/2 end_index = self.current_page + (self.pager_num + 1)/2 # 处理最后的分页,如果当前页+默认显示页的一半大于总分页数,不会再向后增加页数 if (self.current_page + (self.pager_num -1)/2) > self.total_count: start_index = self.total_count - self.pager_num +1 end_index = self.total_count +1 # 当前页是第一页的情况,上一页失效 if self.current_page == 1: prev = '<a class="page" href="javascript:void(0);">上一页</a>' else: prev = '<a class="page" href="%s?p=%s">上一页</a>' %(base_url,self.current_page-1) page_list.append(prev) for i in range(int(start_index),int(end_index)): # 当前页显示的分页样式不一样 if i == self.current_page: temp = '<a class="page active" href="%s?p=%s">%s</a>' % (base_url, i,i) else: temp = '<a class="page" href="%s?p=%s">%s</a>' % (base_url, i,i) page_list.append(temp) if self.current_page == self.total_count: nex = '<a class="page" href="javascript:void(0);">下一页</a>' else: nex = '<a class="page" href="%s?p=%s">下一页</a>' %(base_url,self.current_page+1) page_list.append(nex) jump = ''' <input type = 'text'/><a onclick='jumpTo(this,"%s?p=");'id='ii1'>GO</a> <script> function jumpTo(ths,base){ var val = ths.previousSibling.value; location.href = base + val; } </script> '''%(base_url) page_list.append(jump) page_str = mark_safe(" ".join(page_list)) return page_str
LIST = [] for i in range(500) LIST.append(i) def user_list(request): current_age = request.GET.get('p',1) current_age = int(current_age) page_obj = Page(current_age,len(LIST)) data = LIST[page_obj.start,page_obj.end] page_str = page_obj.page_str('/user_list/') return render(request,'user_list.html',{'li':data,'page_str':page_str})
cookie
客户端浏览器上的一个文件
cookie的简单应用
res = redirect('/index/')
# 设定cookie user 为u
res.set_cookie('user111',u) #res.set_cookie('key','value'),默认情况下,关闭浏览器cookie就失效
# 获取当前已经登陆的用户信息
v = request.COOKIES.get('user111')
rep = HttpResponse(...) 或 rep = render(request, ...) rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt='加密盐',...) 参数: key, 键 value='', 值 max_age=None, 超时时间,秒多少秒之后失效 expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)指定某个时间超时 path='/', Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问 domain=None, Cookie生效的域名 secure=False, https传输 httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
引入jquery的cookie插件
<script src="/static/jquery-1.12.4.js"></script>
{# 必须在引入jQuery后面写 #}
<script src="/static/jquery.cookie.js"></script>
就能使用$.cookie()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .pagenation .page{ display: inline-block; padding: 5px; background-color: grey; margin: 5px; } .pagenation .page.active{ background-color: brown; color: white; } </style> </head> <body> <ul> {% for item in li %} {% include 'li.html' %} {% endfor %} </ul> <div> <select id="s1" onchange="changePageSize(this)"> <option value="10">10</option> <option value="30">30</option> <option value="50">50</option> <option value="100">100</option> </select> </div> <div class="pagenation"> {{ page_str }} </div> <script src="/static/jquery-1.12.4.js"></script> {# 必须在引入jQuery后面写 #} <script src="/static/jquery.cookie.js"></script> <script> $(function(){ {# {'path': "/user_list/`"});加入这个就,就能使得对当前url有影响,其他的不影响#} var v = $.cookie('per_page_count', {'path': "/user_list/`"}); $('#ps').val(v); }); function changePageSize(ths){ var v = $(ths).val(); console.log(v); $.cookie('per_page_count',v, {'path': "/user_list/"}); location.reload(); } {# $(function () {#} {# var v = $.cookie('per_page_count');#} {# var v = document.cookie('per_page_count');#} {# $('#s1').val(v);#} {# });#} {##} {# function changePageSize(ths) {#} {# var v = $(ths).val();#} {# var v = $('#s1').val();#} {# console.log(v);#} {# $.cookie('per_page_count',v);#} {# temp = 'per_page_count'+v +';';#} {# console.log(temp);#} {# document.cookie = temp;#} {##} {# 刷新#} {# location.reload();#} {# }#} </script> </body> </html>
from django.shortcuts import render,HttpResponse from django.shortcuts import redirect from django.utils.safestring import mark_safe from app01 import models from utils import pagination import json # Create your views here. def business(request): # 获取数据,保存为queryset列表 v = models.Business.objects.all() # 查找特定的列,类似select id,caption from business,返回的是字典 v2 = models.Business.objects.all().values('id','caption') # 查询获取的结果,返回的是元组 v3 = models.Business.objects.all().values_list('id','caption') return render(request,'business.html',{'v':v,"v2":v2,"v3":v3}) def host(request): if request.method == "GET": v = models.Business.objects.filter(host__nid__gt=0) # # 因为引号里面是字符串,所以使用双下杠__引用对应对象下的字段,得到结果为字典类型 # v2 = models.Business.objects.all().values('nid', 'hostname', 'b__id', 'b__caption') # print(type(v2)) # for row in v2: # print(row['nid'], row['hostname'], row['b_id'], row['b__caption']) # # 因为引号里面是字符串,所以使用双下杠__引用对应对象下的字段,得到结果为元组,下标安装下方的写的参数从0排序+1 # v3 = models.Business.objects.all().values_list('nid', 'hostname', 'b_id', 'b__caption') # print(type(v3)) b_list = models.Host.objects.all() for row in b_list: print(row.hostname) return render(request, 'host.html', {"v": v,'b_list':b_list}) # return render(request,'host.html',{"v":v,"v2":v2,"v3":v3}) elif request.method == 'POST': h = request.POST.get('hostname') i = request.POST.get('ip') p = request.POST.get('port') b = request.POST.get('b_id') print(h) print(i) print(p) print(b) models.Host.objects.create(hostname = h, ip = i, port = p, b_id = b ) return redirect('/host/') def test_ajax(request): # request.GET.get('pwd',sep='\t')获取pwd的值,并且隔开 # print(request.method,request.GET.get('user'),request.GET.get('pwd',sep='\t')) ret = {'status': True, 'error': None, 'data': None} try: h = request.POST.get('hostname') i = request.POST.get('ip') p = request.POST.get('port') b = request.POST.get('b_id') print(h) print(i) print(p) print(b) if h and len(h) > 5: models.Host.objects.create(hostname=h, ip=i, port=p, b_id=b ) else: ret['status'] = False ret['error'] = '太短了' except Exception as e: ret['status'] = False ret['error'] = '请求错误' return HttpResponse(json.dumps(ret)) def app(request): if request.method == 'GET': app_list = models.Application.objects.all() for row in app_list: print(row.name,row.r.all()) host_list = models.Host.objects.all() return render(request,'app.html',{'app_list':app_list,'host_list':host_list}) elif request.method == 'POST': app_name = request.POST.get('app_name') host_list = request.POST.getlist('host_list') print(app_name,host_list) obj = models.Application.objects.create(name = app_name) obj.r.add(*host_list) return redirect('/app/') def ajax_add_app(request): ret = {'status':True,'error':None,"data":None} app_name = request.POST.get('app_name') host_list =request.POST.getlist('host_list') obj = models.Application.objects.create(name=app_name) obj.r.add(*host_list) return HttpResponse(json.dumps(ret)) LIST = [] for i in range(500): LIST.append(i) # def user_list(request): # # 当前页,获取p的值,若没有值的时候,默认为1 # current_page = request.GET.get('p',1) # # 传递过来的是字符串,这边是数字计算的 # current_page = int(current_page) # start = (current_page-1) * 10 # end = current_page * 10 # # li = LIST[start:end] # # all_count = len(LIST) # # divmod方法是除以多少余多少,这里是除以10,余多少。y为余数 # count,y = divmod(all_count,10) # # 如果有余数,分页数需要+1 # if y: # count +=1 # # page_list = [] # for i in range(1,count+1): # # 如果i等于当前页。将当前页颜色变一下 # if i == current_page: # temp = '<a class="page active" href="/user_list/?p=%s">%s</a>' %(i,i) # else: # temp = '<a class="page" href="/user_list/?p=%s">%s</a>' %(i,i) # page_list.append(temp) # # page_str = " ".join(page_list) # page_str = mark_safe(page_str) # # return render(request,'user_list.html',{'li':li,'page_str':page_str}) # def user_list(request): # ''' # 特定为10页的时候 # :param request: # :return: # ''' # # 当前页,获取p的值,若没有值的时候,默认为1 # current_page = request.GET.get('p',1) # # 传递过来的是字符串,这边是数字计算的 # current_page = int(current_page) # start = (current_page-1) * 10 # end = current_page * 10 # # li = LIST[start:end] # # all_count = len(LIST) # # divmod方法是除以多少余多少,这里是除以10,余多少。y为余数 # total_count,y = divmod(all_count,10) # # 如果有余数,分页数需要+1 # if y: # total_count +=1 # # page_list = [] # # 显示页面当前页的前后五页 # # start_index = current_page - 5 # # end_index = current_page + 5 +1 # if total_count < 11: # start_index = 0 # end_index = total_count # # else: # if current_page <= 6 : # start_index = 1 # end_index = 11 # else: # start_index = current_page - 5 # end_index = current_page +5 +1 # if (current_page + 5) > total_count: # start_index = total_count - 11 +1 # end_index = total_count +1 # # # for i in range(start_index,end_index): # # 如果i等于当前页。将当前页颜色变一下 # if i == current_page: # temp = '<a class="page active" href="/user_list/?p=%s">%s</a>' %(i,i) # else: # temp = '<a class="page" href="/user_list/?p=%s">%s</a>' %(i,i) # page_list.append(temp) # # page_str = " ".join(page_list) # page_str = mark_safe(page_str) # # return render(request,'user_list.html',{'li':li,'page_str':page_str}) # def user_list(request): # ''' # # :param request: # :return: # ''' # # 当前页,获取p的值,若没有值的时候,默认为1 # current_page = request.GET.get('p',1) # # 传递过来的是字符串,这边是数字计算的 # current_page = int(current_page) # start = (current_page-1) * 10 # end = current_page * 10 # # li = LIST[start:end] # # all_count = len(LIST) # # divmod方法是除以多少余多少,这里是除以10,余多少。y为余数 # total_count,y = divmod(all_count,10) # # 如果有余数,分页数需要+1 # if y: # total_count +=1 # # page_list = [] # # 显示页码多少个,这里是11,建议使用基数 # perpage_num = 11 # # 显示页面当前页的前后五页 # # start_index = current_page - 5 # # end_index = current_page + 5 +1 # if total_count < perpage_num: # start_index = 0 # end_index = total_count # # else: # if current_page <= (perpage_num+1)/2 : # start_index = 1 # end_index = perpage_num # else: # start_index = current_page - (perpage_num-1)/2 # end_index = current_page +(perpage_num-1)/2 +1 # if (current_page + (perpage_num-1)/2) > total_count: # start_index = total_count - perpage_num +1 # end_index = total_count +1 # if current_page ==1: # # javascript:void(0);这个代表什么都不干 # prev = '<a class="page active" href="javascript:void(0);">上一页</a>' # else: # prev = '<a class="page active" href="/user_list/?p=%s">上一页</a>' %(current_page-1) # page_list.append(prev) # # for i in range(int(start_index),int(end_index)): # # 如果i等于当前页。将当前页颜色变一下 # if i == current_page: # temp = '<a class="page active" href="/user_list/?p=%s">%s</a>' %(i,i) # else: # temp = '<a class="page" href="/user_list/?p=%s">%s</a>' %(i,i) # page_list.append(temp) # if current_page == total_count: # nex = '<a class="page active" href="javascript:void(0)">下一页</a>' # else: # nex = '<a class="page active" href="/user_list/?p=%s">下一页</a>' % (current_page + 1) # page_list.append(nex) # # 跳转 # jump = ''' # <input type = 'text'/><a onclick='jumpTo(this,"/user_list/?p=");'id='ii1'>GO</a> # <script> # function jumpTo(ths,base){ # var val = ths.previousSibling.value; # location.href = base + val; # } # </script> # # ''' # page_list.append(jump) # # page_str = " ".join(page_list) # page_str = mark_safe(page_str) # return render(request,'user_list.html',{'li':li,'page_str':page_str}) def user_list(request): current_page = request.GET.get('p', 1) current_page = int(current_page) val = request.COOKIES.get('per_page_count') print(val) page_obj = pagination.Page(current_page, len(LIST),val) data = LIST[page_obj.start:page_obj.end] page_str = page_obj.page_str("/user_list/") # data = [4,5,6] # page_str = [1,2,3] return render(request, 'user_list.html', {'li': data, 'page_str': page_str}) user_info = { 'user':{"pwd":"123"} } def index(request): # 获取当前已经登陆的用户信息 v = request.COOKIES.get('user111') if not v: return redirect('/login/') return render(request,'index.html',{'name':v}) def login(request): if request.method == 'GET': return render(request,'login.html') elif request.method == 'POST': u = request.POST.get('user') p = request.POST.get('pwd') dic = user_info.get(u) if not dic: return render(request,'login.html') if dic['pwd'] == p: res = redirect('/index/') # 设定cookie user 为u res.set_cookie('user111',u) res.set_cookie('key','value') return res else: return render(request,'login.html')
带签名的cookie
基于cookie做用户验证时,不适合存放敏感信息,例如账号密码,银行余额等
优点:存储数据的压力放到客户端上
FVB与MVB装饰器实现用户认证
def auth(func): ''' 装饰器,如果发现cookie存储的不是用户名,则需要用户登录 :param func: :return: ''' def inner(request,*args,**kwargs): # 获取当前已经登陆的用户信息 v = request.COOKIES.get('user111') if not v: return redirect('login') return func(request,*args,**kwargs) return inner @auth def index(request): # 获取当前已经登陆的用户信息,因为写了装饰器,所以不需要了 v = request.COOKIES.get('user111') if not v: return redirect('/login/') return render(request,'index.html',{'name':v})
def auth(func): ''' 装饰器,如果发现cookie存储的不是用户名,则需要用户登录 :param func: :return: ''' def inner(request,*args,**kwargs): # 获取当前已经登陆的用户信息 v = request.COOKIES.get('user111') if not v: return redirect('login') return func(request,*args,**kwargs) return inner from django import views from django.utils.decorators import method_decorator # 在类上面写上这个@method_decorator(auth,name="dispatch")。相当于,在下写了第一个继承的函数 @method_decorator(auth,name="dispatch") class Order(views.View): # 这里写一个之后,因为所有函数都先执行dispatch的,所以就类里面的所有函数都需要验证 @method_decorator(auth) def dispatch(self, request, *args, **kwargs): return super(Order,self).dispatch(request, *args, **kwargs) # 写在方法上,是单独对这个方法使用验证 @method_decorator(auth) def get(self,request): # 获取当前已经登陆的用户信息 v = request.COOKIES.get('user111') return render(request, 'index.html', {'name': v}) def post(self,request): # 获取当前已经登陆的用户信息 v = request.COOKIES.get('user111') return render(request, 'index.html', {'name': v})
session
cookie是保存在用户浏览器端的键值对
session是保存在服务器端的键值对
session依赖于cookie
注意:使用session之前,必须要进入到对应目录下执行代码
python manage.py makemigrations
python manage.py migrate
session的id默认情况下Django的放在数据库里面的
session默认存在两周
建立session:
# 生成随机字符串
# 写到用户浏览器cookie
# 保存到session中
# 在随机字符串对应的字典中设置相关内容
request.session['username'] = user #设置session
request.session['username'] #获取session
服务器session
request.session.get('username',None) #获取session,如果不存在,默认设置为None
request.session.clear #用于注销,删除当前cookie
在配置文件中设置默认操作,放在settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
from django.shortcuts import render,redirect,HttpResponse # Create your views here. def login(request): if request.method == 'GET': return render(request,'login.html') elif request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') if user == 'root' and pwd == '123': # 生成随机字符串 # 写到用户浏览器cookie # 保存到session中 # 在随机字符串对应的字典中设置相关内容 request.session['username'] = user request.session['is_login'] = True return redirect('/index/') else: return render(request, 'login.html') def index(request): # 获取当前用户的随机字符串 # 根据随机字符串获取对应的信息 if request.session['is_login']: return HttpResponse(request.session['username']) else: return HttpResponse('gun')
session类型
python manage.py makemigrations python manage.py migrateDjango默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。 a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认) b. 使用 def index(request): # 获取、设置、删除Session中数据 request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在则不设置 del request.session['k1'] #删除单个session request.session.clear (request.session.session_key) #用于注销 # 所有 键、值、键值对 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 用户session的随机字符串 request.session.session_key # 将所有Session失效日期小于当前日期的数据删除 request.session.clear_expired() # 检查 用户session的随机字符串 在数据库中是否 request.session.exists("session_key") # 删除当前用户的所有Session数据 request.session.delete("session_key") request.session.set_expiry(value) * 如果value是个整数,session会在些秒数后失效。 * 如果value是个datatime或timedelta,session就会在这个时间后失效。 * 如果value是0,用户关闭浏览器session就会失效。 * 如果value是None,session会依赖全局session失效策略。
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。 a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串 SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径 SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名 SESSION_COOKIE_SECURE = False # 是否Https传输cookie SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输 SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期 SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存
a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串 SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径 SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名 SESSION_COOKIE_SECURE = False # 是否Https传输cookie SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输 SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期 SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存
a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
session验证码
后续不上
CSRF
原理:第一次访问的时候,获取字符串,post请求的时候,将字符串带上发送过去
对get请求没有限制,对post请求才有限制
为了避免post请求的时候报403错误,需要再form表单里面加上{% csrf_token %}
ajax请求的话,需要加上headers:{'X-CSRFtoken':$.cookie('csrftoken')},
或者直接加上全局函数
{# 全局变量,对函数内所有ajax有效#}
$.ajaxSetup({
beforeSend:function (xhr,settings) {
{# 设置请求头#}
xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));
}
});
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/login/" method="post"> <input type="text" name="user" /> <input type="password" name="pwd" /> <input type="checkbox" name="rmb" value="1" />3秒钟免登陆 <input type="submit" value="提交"/> <input id="btn1" type="button" value="按钮1"/> <input id="btn2" type="button" value="按钮2"/> {% csrf_token %} </form> <script src="/static/jquery-1.12.4.js"></script> <script src="/static/jquery.cookie.js"></script> <script> $(function () { {# 全局变量,对函数内所有ajax有效#} $.ajaxSetup({ beforeSend:function (xhr,settings) { {# 设置请求头#} xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken')); } }); $('#btn1').click(function () { {# var csrftoken = $.cookie('csrftoken');#} $.ajax({ url:'/login/', type:'POST', data:{'user':'root','pwd':'123'}, {# 发送post请求的时候,需要加上才放置csrf阻止,由于上面$.ajaxSetup已经配置,所以不需要单独配置#} {# headers:{'X-CSRFtoken':$.cookie('csrftoken')},#} success:function (data) { console.log(1) } }); $('#btn2').click(function () { {# var csrftoken = $.cookie('csrftoken');#} $.ajax({ url:'/login/', type:'POST', data:{'user':'root','pwd':'123'}, {# 发送post请求的时候,需要加上才放置csrf阻止#} {# headers:{'X-CSRFtoken':$.cookie('csrftoken')},#} success:function (data) { console.log(2) } }) }) }); }) </script> </body> </html>
全局:
settings.py里面的MIDDLEWARE下
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
@csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
@csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
局部的例子如下
中间件
中间件拥有的函数(名字不能修改):
class Row1(MiddlewareMixin): def process_request(self,request): print("row1_process_request") def process_response(self,request,response): print('row1_process_response') return response
中间件的一般逻辑如下图
Django1.10版本之前,若是遇到有return的process_request情况
Django1.10版本后,若是遇到有return的process_request情
中间件是在settings.py的MIDDLEWARE配置的,配置路径,到类
from django.utils.deprecation import MiddlewareMixin class Row1(MiddlewareMixin): def process_request(self,request): print("row1_process_request") def process_response(self,request,response): print('row1_process_response') return response class Row2(MiddlewareMixin): def process_request(self,request): print("row2_process_request") def process_response(self,request,response): print('row2_process_response') return response class Row3(MiddlewareMixin): def process_request(self,request): print("row3_process_request") def process_response(self,request,response): print('row3_process_response') return response
多了process_view
def process_view(self,request,view_func,view_func_args,view_func_kwargs): ''' :param request: :param view_func: 访问的时候对应views.py里面的函数 :param view_func_args: views.py里面的函数的参数 :param view_func_kwargs: views.py里面的函数的参数(字典) :return: ''' print('row1_process_view')
多了process_exception,若views.py里面对应的函数出现异常,会一个个中间件寻找能处理的异常函数,若没有,则页面报错,若存在,则返回对应的信息给前端
def process_exception(self,request,exception): ''' view里面对应的函数出现异常的时候执行 :param exception: 对应异常 :return: ''' if isinstance(exception,ValueError): # 假设login函数出现异常,又没有处理,只需要这里返回信息,页面不会显示返回的信息 print('row3_process_exception') return HttpResponse('出问题了')
from django.utils.deprecation import MiddlewareMixin class Row1(MiddlewareMixin): def process_request(self,request): print("row1_process_request") def process_view(self,request,view_func,view_func_args,view_func_kwargs): ''' :param request: :param view_func: 访问的时候对应views.py里面的函数 :param view_func_args: views.py里面的函数的参数 :param view_func_kwargs: views.py里面的函数的参数(字典) :return: ''' print('row1_process_view') def process_response(self,request,response): print('row1_process_response') return response from django.shortcuts import HttpResponse class Row2(MiddlewareMixin): def process_request(self,request): print("row2_process_request") # return HttpResponse('走') def process_view(self, request, view_func, view_func_args, view_func_kwargs): print('row2_process_view') def process_response(self,request,response): print('row2_process_response') return response class Row3(MiddlewareMixin): def process_request(self,request): print("row3_process_request") def process_view(self,request,view_func,view_func_args,view_func_kwargs): print('row3_process_view') def process_response(self,request,response): print('row3_process_response') return response def process_exception(self,request,exception): ''' view里面对应的函数出现异常的时候执行 :param exception: 对应异常 :return: ''' if isinstance(exception,ValueError): # 假设login函数出现异常,又没有处理,只需要这里返回信息,页面不会显示返回的信息 print('row3_process_exception') return HttpResponse('出问题了')
from django.shortcuts import render,redirect,HttpResponse # Create your views here. def login(request): int('dsd') return render(request,'login.html')
缓存
配置:
# 此为开始调试用,实际内部不做任何操作 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎 'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期) 'OPTIONS':{ 'MAX_ENTRIES': 300, # 最大缓存个数(默认300) 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3) }, 'KEY_PREFIX': '', # 缓存key的前缀(默认空) 'VERSION': 1, # 缓存key的版本(默认1) 'KEY_FUNCTION' 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】) } } # 自定义key def default_key_func(key, key_prefix, version): """ Default function to generate keys. Constructs the key used by all other methods. By default it prepends the `key_prefix'. KEY_FUNCTION can be used to specify an alternate function with custom key making behavior. """ return '%s:%s:%s' % (key_prefix, version, key) def get_key_func(key_func): """ Function to decide which key function to use. Defaults to ``default_key_func``. """ if key_func is not None: if callable(key_func): return key_func else: return import_string(key_func) return default_key_func
# 此缓存将内容保存至内存的变量中 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-snowflake', } } # 注:其他配置同开发调试版本
# 此缓存将内容保存至文件 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': '/var/tmp/django_cache', } } # 注:其他配置同开发调试版本
# 此缓存将内容保存至数据库 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': 'my_cache_table', # 数据库表 } } # 注:执行创建表命令 python manage.py createcachetable
# 此缓存使用python-memcached模块连接memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'unix:/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': [ '172.19.26.240:11211', '172.19.26.242:11211', ] } }
# 此缓存使用pylibmc模块连接memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': [ '172.19.26.240:11211', '172.19.26.242:11211', ] } }
CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100} # "PASSWORD": "密码", } } }
应用
使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存 MIDDLEWARE = [ #这个中间件只有一个process_response,进来的时候不需要经过它 'django.middleware.cache.UpdateCacheMiddleware', # 其他中间件... #这里只有process_view,出去的时候不需要经过 'django.middleware.cache.FetchFromCacheMiddleware', ] CACHE_MIDDLEWARE_ALIAS = "" CACHE_MIDDLEWARE_SECONDS = "" CACHE_MIDDLEWARE_KEY_PREFIX = ""
# 单视图,整个页面的缓存,设置为10秒,这里的优先级比默认的高 from django.views.decorators.cache import cache_page @cache_page(10) def cache(request): import time ctime = time.time() return render(request,'cache.html',{'ctime':ctime})
局部缓存在html写,需要导入
{% load cache %}
在需要缓存的地方上写,单位是秒,这里缓存10秒
{% cache 10 c1 %}
<h1>{{ ctime }}</h1>
{% endcache %}
{% load cache %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>{{ ctime }}</h1> <h1>{{ ctime }}</h1> {% cache 10 c1 %} <h1>{{ ctime }}</h1> {% endcache %} </body> </html>
信号
(可以做日志)
Model signals pre_init # django的modal执行其构造方法前,自动触发 post_init # django的modal执行其构造方法后,自动触发 pre_save # django的modal对象保存前,自动触发 post_save # django的modal对象保存后,自动触发 pre_delete # django的modal对象删除前,自动触发 post_delete # django的modal对象删除后,自动触发 m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发 class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发 Management signals pre_migrate # 执行migrate命令前,自动触发 post_migrate # 执行migrate命令后,自动触发 Request/response signals request_started # 请求到来前,自动触发 request_finished # 请求结束后,自动触发 got_request_exception # 请求异常后,自动触发 Test signals setting_changed # 使用test测试修改配置文件时,自动触发 template_rendered # 使用test测试渲染模板时,自动触发 Database Wrappers connection_created # 创建数据库连接时,自动触发
对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:
使用:
from django.core.signals import request_finished from django.core.signals import request_started from django.core.signals import got_request_exception from django.db.models.signals import class_prepared from django.db.models.signals import pre_init, post_init from django.db.models.signals import pre_save, post_save from django.db.models.signals import pre_delete, post_delete from django.db.models.signals import m2m_changed from django.db.models.signals import pre_migrate, post_migrate from django.test.signals import setting_changed from django.test.signals import template_rendered from django.db.backends.signals import connection_created def callback(sender, **kwargs): print("xxoo_callback") print(sender,kwargs) # xxoo.connect(callback) # xxoo指上述导入的内容 # 例如: pre_init.connect(callback)
init.py导入sy.py
from app01 import models def sigin(request): obj = models.UserInfo(username='root') print('end') obj.save() obj = models.UserInfo(username='root') obj.save() obj = models.UserInfo(username='root') obj.save()
自定义信号
1.定义信号
2.触发信号
3.信号中注册函数
sg.py加上这个
import django.dispatch pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
注册对应函数
def callback(sender, **kwargs): print("callback") print(sender,kwargs) pizza_done.connect(callback)
def sigin(request): from sg import pizza_done # sender随意些,后面的传递参数内容 pizza_done.send(sender='sddsfs', toppings=123, size=456) return HttpResponse('ok')
form表单验证
参考:http://www.cnblogs.com/wupeiqi/articles/6144178.html
1.验证用户请求
2.生成HTML标签,保留上一次填写的记录
{{obj.user}}
3.显示错误信息{{ obj.errors.user.0 }}
<p>{{ obj.user }}{{ obj.errors.user.0 }}</p>
4.从数据库获取信息好返回到前端
rom django import forms from django.forms import fields class FM(forms.Form): # 这里的变量与前端form里面的name一致才能获取对应的值 # user = forms.CharField() # 可以自定义对应错误信息 user = forms.CharField(error_messages={'required':'用户名不能为空。'}) # pwd = forms.CharField() pwd = forms.CharField( max_length=12, min_length=6, error_messages={'required':'密码不能为空。','min_length':'密码长度不能少于6','max_length':'密码长度不能大于12'} ) # 单选下拉 city1 = fields.ChoiceField( choices=[(0,'上海'),(1,'广州'),(2,'东莞')] ) # 多选下拉 city2 = fields.MultipleChoiceField( choices=[(0, '上海'), (1, '广州'), (2, '东莞')] ) # email = forms.EmailField() email = forms.EmailField(error_messages={'required':'邮箱不能为空。','invalid':'邮箱格式错误'}) def fm(request): if request.method == 'GET': # 从数据库中获取到数据 dic = { 'user':'root', 'pwd':'123123', 'email':'sada@111', 'city1':1, 'city2':[1,2] } # obj = FM() # 将获取到的数据传递到类FM obj = FM(initial=dic) return render(request,'fm.html',{'obj':obj}) elif request.method == 'POST': # 获取用户所有数据 # 每条数据请求的验证 # 成功后,获取所有的正确的信息 # 如果失败,显示错误信息 # 这次请求是post里面的数据,所以传入request.POST obj = FM(request.POST) r1= obj.is_valid() print(r1) if r1: print(obj.cleaned_data) else: # obj.errors是字典 print(obj.errors) print(obj.errors.as_json()) print(obj.errors['user']) print(obj.errors['user'][0]) return render(request,'fm.html',{'obj':obj}) return redirect('/fm/')
先导入对应forms,然后生成类
from django import forms(不建议使用)
from django.forms import fields(建议使用这个)
from django import forms class FM(forms.Form): # 这里的变量与前端form里面的name一致才能获取对应的值 # user = forms.CharField() # 可以自定义对应错误信息 user = forms.CharField(error_messages={'required':'用户名不能为空。'}) # pwd = forms.CharField() pwd = forms.CharField( max_length=12, min_length=6, error_messages={'required':'密码不能为空。','min_length':'密码长度不能少于6','max_length':'密码长度不能大于12'} ) # email = forms.EmailField() email = forms.EmailField(error_messages={'required':'邮箱不能为空。','invalid':'邮箱格式错误'}) def fm(request): if request.method == 'GET': obj = FM() return render(request,'fm.html',{'obj':obj}) elif request.method == 'POST': # 获取用户所有数据 # 每条数据请求的验证 # 成功后,获取所有的正确的信息 # 如果失败,显示错误信息 # 这次请求是post里面的数据,所以传入request.POST obj = FM(request.POST) r1= obj.is_valid() print(r1) if r1: print(obj.cleaned_data) # 这样就能创建用户对象了 models.UserInfo.objects.create(**obj.cleaned_data) else: # obj.errors是字典 print(obj.errors) print(obj.errors.as_json()) print(obj.errors['user']) print(obj.errors['user'][0]) return render(request,'fm.html',{'obj':obj}) return redirect('/fm/')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/fm/" method="post"> {% csrf_token %} {# 能自动生成标签,并且在新浏览器里面有特定的错误功能 ,建议使用这个,定制性比较好#} {{ obj.user }} <p>{{ obj.user }}{{ obj.errors.user.0 }}</p> <p>{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p> <p>{{ obj.email }}{{ obj.errors.email.0 }}</p> <p><input type="submit" value="确定" /> {# *********************************#} {# {{ obj.as_ul }}#} {# ****************table需要加上table标签*****************#} {# <table>#} {# {{ obj.as_table }}#} {# </table>#} {##} {# *********************************#} {# {{ obj.as_p }}#} </form> </body> </html>
from django.shortcuts import render,redirect,HttpResponse # Create your views here. def login(request): int('dsd') return render(request,'login.html') # 单视图,整个页面的缓存,设置为10秒,这里的优先级比默认的高 # from django.views.decorators.cache import cache_page # @cache_page(10) def cache(request): import time ctime = time.time() return render(request,'cache.html',{'ctime':ctime}) from app01 import models def sigin(request): from sg import pizza_done # sender随意些,后面的传递参数内容 pizza_done.send(sender='sddsfs', toppings=123, size=456) obj = models.UserInfo(username='root') print('end') obj.save() obj = models.UserInfo(username='root') obj.save() obj = models.UserInfo(username='root') obj.save() return HttpResponse('ok') from django import forms # 多行文本导入,插件 from django.forms import widgets # 建议将forms改为fields from django.forms import fields class FM(forms.Form): # 这里的变量与前端form里面的name一致才能获取对应的值 # user = forms.CharField() # 可以自定义对应错误信息 # 字段本身只做验证 user = fields.CharField(error_messages={'required':'用户名不能为空。'}) # pwd = forms.CharField() pwd = fields.CharField( max_length=12, min_length=6, error_messages={'required':'密码不能为空。','min_length':'密码长度不能少于6','max_length':'密码长度不能大于12'}, # 密码框 # widget = widgets.PasswordInput # 如果想定制样式 widget = widgets.PasswordInput(attrs={'class':'c2'}) ) # email = forms.EmailField() email = fields.EmailField(error_messages={'required':'邮箱不能为空。','invalid':'邮箱格式错误'}) text1 = fields.CharField( # attrs={'class':'c1'}定义样式为c1 widget = widgets.Textarea(attrs={'class':'c1'}) ) def fm(request): if request.method == 'GET': obj = FM() return render(request,'fm.html',{'obj':obj}) elif request.method == 'POST': # 获取用户所有数据 # 每条数据请求的验证 # 成功后,获取所有的正确的信息 # 如果失败,显示错误信息 # 这次请求是post里面的数据,所以传入request.POST obj = FM(request.POST) r1= obj.is_valid() print(r1) if r1: print(obj.cleaned_data) # 这样就能创建用户对象了 models.UserInfo.objects.create(**obj.cleaned_data) else: # obj.errors是字典 print(obj.errors) print(obj.errors.as_json()) print(obj.errors['user']) print(obj.errors['user'][0]) return render(request,'fm.html',{'obj':obj}) return redirect('/fm/')
初始化操作:
def fm(request): if request.method == 'GET': # 从数据库中获取到数据 dic = { 'user':'root', 'pwd':'123123', 'email':'sada@111', 'city1':1, 'city2':[1,2] } # obj = FM() # 将获取到的数据传递到类FM obj = FM(initial=dic) return render(request,'fm.html',{'obj':obj})
modelform(耦合性太强,小的程序才用)
参考:https://www.cnblogs.com/wupeiqi/articles/6229414.html
# modelform方式 class UserInfoModelForm(forms.ModelForm): class Meta: # 这里指定字段对应的表 model =models.UserInfo # __all__代表多有的字段 fields = '__all__' # 只显示的字段 # fields = ['username','email'] # 排除字段,其他的显示 exclude = ['email']
# # modelform方式 class UserInfoModelForm(forms.ModelForm): class Meta: # 这里指定字段对应的表 model =models.UserInfo # __all__代表多有的字段 fields = '__all__' # 只显示的字段 # fields = ['username','email'] # 排除字段,其他的显示 # exclude = ['email'] # 显示标签更名 labels = { 'username':'用户名', 'email':'邮箱' } # help_texts = { 'username':'帮助信息' } # 将原来的CharField改为为Textarea widgets = { 'username':Fwidgets.Textarea(attrs={'class':'c1'}) } error_messages = { '__all__':'所有字段共同的错误', # email的错误信息 'email':{ 'required':'邮箱不能为空', 'invalid':'邮箱格式错误' } } # 更改格式, field_classes = { # 将email的格式从邮箱给为url格式,这里是填写类,不是带括号的对象 'email': Ffields.URLField }
1.可以生产HTML标签:class Meta的参数
2.页面显示带默认值,就需增加instance参数如:mf = xxxModelForm(instance = ModelObj)
3.额外的标签:is_rmb = Ffields.CharField( widget=Fwidgets.CheckboxInput() )
4.各种验证 is_valid() - > 各种钩子
5.mf.save(),可以拆开
instance = obj.save(False)
instance.save()
obj.save_m2m()
from django.shortcuts import render from django import forms from django.forms import fields from django.forms import fields as Ffields from app01 import models # Create your views here. # 避免跟modelform的属性冲突,更名为Fwidgets from django.forms import widgets as Fwidgets # # modelform方式 class UserInfoModelForm(forms.ModelForm): # 自定义字段,跟保存在数据库上没关系,例如一个月内免登陆的CheckBox is_rmb = Ffields.CharField( widget=Fwidgets.CheckboxInput() ) class Meta: # 这里指定字段对应的表 model =models.UserInfo # __all__代表多有的字段 fields = '__all__' # 只显示的字段 # fields = ['username','email'] # 排除字段,其他的显示 # exclude = ['email'] # 显示标签更名 labels = { 'username':'用户名', 'email':'邮箱' } # help_texts = { 'username':'帮助信息' } # 将原来的CharField改为为Textarea widgets = { 'username':Fwidgets.Textarea(attrs={'class':'c1'}) } error_messages = { '__all__':'所有字段共同的错误', # email的错误信息 'email':{ 'required':'邮箱不能为空', 'invalid':'邮箱格式错误' } } # 更改格式, # field_classes = { # # 将email的格式从邮箱给为url格式,这里是填写类,不是带括号的对象 # 'email': Ffields.URLField # } # form方式 class UserInfoForm(forms.Form): # 定义字段 username = fields.CharField(max_length=32,label='用户名') email = fields.EmailField(label='邮件') # 将数据库的id caption字段作为下拉显示 user_type = fields.ChoiceField( choices = models.UserType.objects.values_list('id','caption'), label='类型' ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) # 这样子就能更新数据库不需要重启程序就能更新数据 self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption') def index(request): if request.method == 'GET': # 创建对象,会在前段自动生成对应的标签 obj = UserInfoModelForm() return render(request,'index.html',{'obj':obj}) # return render(request,'index.html') elif request.method == 'POST': # 创建对象,会在前段自动生成对应的标签 obj = UserInfoModelForm(request.POST) if obj.is_valid(): # obj.save() # 上面一句包含了下面三句代码,只不过默认传入commit=True instance = obj.save(False) instance.save() obj.save_m2m() # print(obj.is_valid()) # print(obj.cleaned_data) # print(obj.errors) # obj.cleaned_data return render(request, 'index.html', {'obj': obj}) def user_list(request): li = models.UserInfo.objects.all().select_related('user_type') return render(request,'user_list.html',{'li':li}) def user_edit(request,nid): # 获取当前id对象的用户信息 # 显示用户已经存在的数据 if request.method == "GET": user_obj = models.UserInfo.objects.filter(id=nid).first() mf = UserInfoModelForm(instance=user_obj) return render(request,'user_edit.html',{'mf':mf,'nid':nid}) elif request.method == 'POST': user_obj = models.UserInfo.objects.filter(id=nid).first() # instance=user_obj)告诉数据库要更新的是哪个对象 mf = UserInfoModelForm(request.POST,instance=user_obj) if mf.is_valid(): mf.save() else: print(mf.errors.as_json()) return render(request, 'user_edit.html', {'mf': mf, 'nid': nid})
form
UserInfoForm 继承Form,又继承BaseForm(方法所在)
from django.shortcuts import render from django import forms from django.forms import fields from app01 import models # Create your views here. # # modelform方式 # class UserInfoModelForm(forms.ModelForm): # # class Meta: # # 这里指定字段对应的表 # model =models.UserInfo # # __all__代表多有的字段 # fields = '__all__' # # # 只显示的字段 # # fields = ['username','email'] # # 排除字段,其他的显示 # exclude = ['email'] # form方式 class UserInfoForm(forms.Form): # 定义字段 username = fields.CharField(max_length=32,label='用户名') email = fields.EmailField(label='邮件') # 将数据库的id caption字段作为下拉显示 user_type = fields.ChoiceField( choices = models.UserType.objects.values_list('id','caption'), label='类型' ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) # 这样子就能更新数据库不需要重启程序就能更新数据 self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption') def index(request): if request.method == 'GET': # 创建对象,会在前段自动生成对应的标签 obj = UserInfoForm() return render(request,'index.html',{'obj':obj}) # return render(request,'index.html') elif request.method == 'POST': # 创建对象,会在前段自动生成对应的标签 obj = UserInfoForm(request.POST) obj.is_valid() # obj.cleaned_data return render(request, 'index.html', {'obj': obj})
select_related()
使用外键.出数据的情况,Django会导致请求数据库过多,例如,下面一个循环,就进行了11次请求,效率不高
但是,如果后面加上select_related(),就会将表关联的数据一次拿出来了。当然,这样有所有的数据,所以会导致请求的数据过多,因此,可以增加对应的参数select_related('ut')
prefetch_related
users = models.User.objects.filter(id__gt=30).prefetch_related('ut') 会执行两次SQL请求
# select * from users; where id > 30;
# 获取上一步骤中所有的ut_id = [1,2]
# select * from user_type where id in[1,2],所以下面就能直接从内存获取数据,而不需要再执行SQL请求
for row in users:
print(row.user,row.pwd,row.ut_id)
print(row.ut.name)
obj.full_clean()会对内容进行验证,若错误,则会抛出异常
步骤:每个字段的正则验证
clean钩子
可以利用继续的clean()方法,自定义错误
kindEditor(视频132)
参考:http://www.cnblogs.com/wupeiqi/articles/6307554.html
官网:http://kindeditor.net/demo.php
初始化参数:http://kindeditor.net/docs/option.html
组合查询
开始的做法
from django.shortcuts import render from app01 import models # Create your views here. def article(request,*args,**kwargs): # print(request.path_info) # from django.urls import reverse # # 反转获取url # url = reverse('article',kwargs=kwargs) # print(url) print(args) condition = {} for k,v in kwargs.items(): kwargs[k] = int(v) # print(type(k)) if v == '0': # print('什么都不做') pass else: condition[k] = v # {'article_type_id': '1', 'category_id': '0'} print(kwargs) article_type_list = models.ArticleType.objects.all() category_list = models.Category.objects.all() result = models.Article.objects.filter(**condition) return render(request, 'article.html', {'result':result, 'article_type_list':article_type_list, 'category_list':category_list, 'arg_dict':kwargs })
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .condition a{ display: inline-block; padding: 3px 5px; border: 1px solid #DDDDDD; margin: 5px; } .condition a.active{ background-color: green; } </style> </head> <body> <h1>过滤条件</h1> <div class="condition"> <div> {% if arg_dict.article_type_id == 0 %} <a class="active" href="/article-0-{{ arg_dict.category_id }}/">全部</a> {% else %} <a href="/article-0-{{ arg_dict.category_id }}/">全部</a> {% endif %} {% for row in article_type_list %} {% if row.id == arg_dict.article_type_id %} <a class="active" href="/article-{{ row.id }}-{{ arg_dict.category_id }}/">{{ row.caption }}</a> {% else %} <a href="/article-{{ row.id }}-{{ arg_dict.category_id }}/">{{ row.caption }}</a> {% endif %} {% endfor %} </div> <div> {% if arg_dict.category_id == 0 %} <a class="active" href="/article-{{ arg_dict.article_type_id }}-0/">全部</a> {% else %} <a href="/article-{{ arg_dict.article_type_id }}-0/">全部</a> {% endif %} {% for row in category_list %} {% if row.id == arg_dict.category_id %} <a class="active" href="/article-{{ arg_dict.article_type_id }}-{{ row.id }}/">{{ row.caption }}</a> {% else %} <a href="/article-{{ arg_dict.article_type_id }}-{{ row.id }}/">{{ row.caption }}</a> {% endif %} {% endfor %} </div> </div> <h1>查询结果</h1> <ul> {% for row in result %} <li>{{ row.id }}-{{ row.title }}</li> {% endfor %} </ul> </body> </html>
优化:
在app01建立新目录templatetags,建立任意.py文件,然后建立模板
from django import template register = template.Library() # 注册成模板 @register.simple_tag def filter_all(): return '....'
HTML文件头部写 {% load py文件名 %} 如:{% load filter %}
输出:{% 函数名 %} {% filter_all %}
from django import template from django.utils.safestring import mark_safe register = template.Library() # 注册成模板 @register.simple_tag def filter_all(arg_dict,k): ''' 因为内容以来于arg_dict,所以传递入参数 {% if arg_dict.article_type_id == 0 %} <a class="active" href="/article-0-{{ arg_dict.category_id }}/">全部</a> {% else %} <a href="/article-0-{{ arg_dict.category_id }}/">全部</a> {% endif %} :return: ''' if k == 'article_type_id': n1 =arg_dict['article_type_id'] n2=arg_dict['category_id'] if n1 ==0: ret = '<a class="active" href="/article-0-%s/">全部</a>' % n2 else: ret = '<a href="/article-0-%s/">全部</a>' % n2 else: n1 = arg_dict['category_id'] n2 = arg_dict['article_type_id'] if n1 == 0: ret = '<a class="active" href="/article-%s-0/">全部</a>' % n2 else: ret = '<a href="/article-%s-0/">全部</a>' % n2 # if arg_dict['article_type_id'] == 0: # ret='<a class="active" href="/article-0-%s/">全部</a>'%(arg_dict['category_id']) # else: # ret='<a href="/article-0-%s/">全部</a>'%(arg_dict['category_id']) return mark_safe(ret) @register.simple_tag def filter_article_type(arg_dict,article_type_list): ''' {% for row in article_type_list %} {% if row.id == arg_dict.article_type_id %} <a class="active" href="/article-{{ row.id }}-{{ arg_dict.category_id }}/">{{ row.caption }}</a> {% else %} <a href="/article-{{ row.id }}-{{ arg_dict.category_id }}/">{{ row.caption }}</a> {% endif %} {% endfor %} :return: ''' ret = [] for row in article_type_list: if row.id == arg_dict['article_type_id']: temp = '<a class="active" href="/article-%s-%s/">%s</a>' %(row.id,arg_dict['category_id'],row.caption) else: temp = '<a href="/article-%s-%s/">%s</a>' %(row.id,arg_dict['category_id'],row.caption) ret.append(temp) return mark_safe(''.join(ret)) # @register.simple_tag # def filter_article_type(arg_dict,article_type_list): # ''' # {% for row in article_type_list %} # {% if row.id == arg_dict.article_type_id %} # <a class="active" href="/article-{{ row.id }}-{{ arg_dict.category_id }}/">{{ row.caption }}</a> # {% else %} # <a href="/article-{{ row.id }}-{{ arg_dict.category_id }}/">{{ row.caption }}</a> # {% endif %} # {% endfor %} # :return: # ''' # ret = [] # for row in article_type_list: # if row.id == arg_dict['article_type_id']: # temp = '<a class="active" href="/article-%s-%s/">%s</a>' %(row.id,arg_dict['category_id'],row.caption) # else: # temp = '<a href="/article-%s-%s/">%s</a>' %(row.id,arg_dict['category_id'],row.caption) # # ret.append(temp) # # return mark_safe(''.join(ret))
from django.shortcuts import render from app01 import models # Create your views here. def article(request,*args,**kwargs): # print(request.path_info) # from django.urls import reverse # # 反转获取url # url = reverse('article',kwargs=kwargs) # print(url) print(args) condition = {} for k,v in kwargs.items(): kwargs[k] = int(v) # print(type(k)) if v == '0': # print('什么都不做') pass else: condition[k] = v # {'article_type_id': '1', 'category_id': '0'} print(kwargs) article_type_list = models.ArticleType.objects.all() category_list = models.Category.objects.all() result = models.Article.objects.filter(**condition) return render(request, 'article.html', {'result':result, 'article_type_list':article_type_list, 'category_list':category_list, 'arg_dict':kwargs })
{% load filter %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .condition a{ display: inline-block; padding: 3px 5px; border: 1px solid #DDDDDD; margin: 5px; } .condition a.active{ background-color: green; } </style> </head> <body> <h1>过滤条件</h1> <div class="condition"> <div> {% filter_all arg_dict 'article_type_id' %} {% filter_article_type arg_dict article_type_list %} {# {% if arg_dict.article_type_id == 0 %}#} {# <a class="active" href="/article-0-{{ arg_dict.category_id }}/">全部</a>#} {# {% else %}#} {# <a href="/article-0-{{ arg_dict.category_id }}/">全部</a>#} {# {% endif %}#} {# {% for row in article_type_list %}#} {# {% if row.id == arg_dict.article_type_id %}#} {# <a class="active" href="/article-{{ row.id }}-{{ arg_dict.category_id }}/">{{ row.caption }}</a>#} {# {% else %}#} {# <a href="/article-{{ row.id }}-{{ arg_dict.category_id }}/">{{ row.caption }}</a>#} {# {% endif %}#} {# {% endfor %}#} </div> <div> {% filter_all arg_dict 'category_id' %} {# {% if arg_dict.category_id == 0 %}#} {# <a class="active" href="/article-{{ arg_dict.article_type_id }}-0/">全部</a>#} {# {% else %}#} {# <a href="/article-{{ arg_dict.article_type_id }}-0/">全部</a>#} {# {% endif %}#} {% for row in category_list %} {% if row.id == arg_dict.category_id %} <a class="active" href="/article-{{ arg_dict.article_type_id }}-{{ row.id }}/">{{ row.caption }}</a> {% else %} <a href="/article-{{ arg_dict.article_type_id }}-{{ row.id }}/">{{ row.caption }}</a> {% endif %} {% endfor %} </div> </div> <h1>查询结果</h1> <ul> {% for row in result %} <li>{{ row.id }}-{{ row.title }}</li> {% endfor %} </ul> </body> </html>
JSONP
是一种请求方式
因为浏览器的同源策略(阻止Ajax请求,无法阻止<scritp src...>请求)
巧妙:
创建script标签
src=远程地址
返回的数据必须是js格式的
只能发GET请求
后续补充
注意地方:
1、写url的时候,建议增加结尾符合$,否则business_add地址永远无法执行