一、celerys作用：用户发起请求 request的时候 需要等待response 但是在视图函数中 有些功能执行需要时间 可能出现用户需要等待很久才会返回响应 导致用户的体验很差 还会容易出现代码中的异常网站想要隔断时间同步一次数据 但是http需要出发才能执行(1) celery任务 task本质就是一个python函数队列 queue将要执行的任务存放在对列中工人 worker负责执行队列中的任务broker负责调度 redis的缓存(2) 解决的问题可以将耗时的代码放在celery中执行celery定时执行(3) 安装pip3 install celerypip3 install celery-with-redispip3 install django-celerypip3 install redis-server(4)在settings.py文件中的install_apps添加 djceleryINSTALLED_APPS = [ ... 'App', 'djcelery', ]在底部添加如下代码#djcelery import djcelery djcelery.setup_loader() #初始化 BROKER_URL = 'redis://127.0.0.1:6379/0' #链接redis 选择数据库0 #BROKER_URL = 'redis://:密码@127.0.0.1:6379/0' CELERY_IMPORTS = ('App.task') #导入任务py文件 App是应用名称 task是任务文件名称(5) 创建task任务文件 在App下App/task.pyfrom celery import task import time #要执行的任务 @task def test(): print('today is a good day1') time.sleep(5) print('today is a good day2')(6) 执行迁移python3 manage.py migrate(7) 在project下创建celery.py文件from __future__ import absolute_import import os from celery import Celery from django.conf import settings os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'whthas_home.settings') app = Celery('portal') app.config_from_object('django.conf:settings') app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) @app.task(bind=True) def debug_task(self): print('Request: {0!r}'.format(self.request))(8) 在project/init.py文件添加如下代码from .celery import app as celery_app(9) 在视图函数中 调用费时的任务from App.task import test def index(req): test.delay() #把活添加到队列 不会阻塞 return HttpResponse('首页')(10) 启动redisredis-serverredis-cli(11) 启动服务python3 manage.py runserver(12) 启动worker在打开一个终端cd /django的工作目录python3 manage.py celery worker --loglevel=info(13)定时执行在settings.py文件中添加如下代码定时执行一个任务from datetime import timedelta CELERYBEAT_SCHEDULE = { 'schedule-test1':{ 'task':'App.task.test', #定时执行的任务 'schedule':timedelta(seconds=7), #执行间隔 } }定时执行多个任务 from datetime import timedelta CELERYBEAT_SCHEDULE = { 'schedule-test1':{ 'task':'App.task.test', 'schedule':timedelta(seconds=7), }, 'schedule-test2':{ 'task':'App.task.test2', 'schedule':timedelta(seconds=2), 'args':['xlg'] } }在task添加如下任务from celery import task import time #要执行的任务 @task def test(): print('today is a good day1') time.sleep(5) print('today is a good day2') #定时任务2 @task def test2(arg): print('{} is a very shuai'.format(arg))启动顺序python3 manage.py runserverpython3 manage.py celery worker --loglevel=info #开启异步执行调度python3 manage.py celery beat --loglevel=info #开启定时任务二、中间件作用：在请求与响应之间 进行某些操作的过滤IP限制新建一个表 限制IP访问的限制url请求比如：没登录访问需要登录的路由地址 可以重定向到登录视图缓存处理访问的时候判断访问的视图函数是否有缓存 如果有 则直接响应缓存中间件本质就是一个python类方法：process_request(self,request) 在执行视图之前被调用 每次请求都调用 url路由地址分发之前 返回None 或者 HttpResponseprocess_view(self,request,view_func,view_args) 视图函数调用之前 返回None 或者 HttpResponseprocess_template_response(self,equest,response) 视图中执行完调用 每个请求都很会调用 返回None或者 HttpResponseprocess_response(self,request,response) 响应返回浏览器之前调用 每个请求都会调用 返回HttpResponse对象process_exception(self,equest,exception) 当视图抛出异常时 调用 返回HttpResponse 对象实例：目录结构project/ App/ project/ manage.py middleware/ App/ myMiddle.pymyMiddle.py添加如下代码from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse,redirect class MyMiddle(MiddlewareMixin): def process_request(self, request): print(request.path) print(request.method) print(request.META['REMOTE_ADDR']) # if request.META['REMOTE_ADDR'] == '127.0.0.1': # if IPModel.objects.filter(ip=request.META['REMOTE_ADDR']).first(): # return HttpResponse('就不让你访问！') def process_exception(self,equest,exception): print(exception) return redirect('/')视图函数from django.shortcuts import render,HttpResponse import time,random # Create your views here. from App.task import test def index(req): # test.delay() #把活添加到队列 不会阻塞 return HttpResponse('首页') def error(req): val = random.randint(0,4) print(8/val) return HttpResponse("算个数")添加到settings.py的middle中MIDDLEWARE = [ 'middleware.App.myMiddle.MyMiddle', ]
第7节、站点、分页、文件上传及富文本编辑器
一、站点管理(1) 创建模型Grade和Students在models.py中实例class Grade(models.Model): gname = models.CharField(max_length=20) ggirlnum = models.IntegerField(default=30) gboynum = models.IntegerField(default=40) isDelete = models.BooleanField(default=False) createTime = models.DateTimeField(auto_now_add=True) def __str__(self): return self.gname class Meta: db_table = 'grade' class Students(models.Model): sname = models.CharField(max_length=10,default='xxx') ssex = models.BooleanField(default=True) sage = models.IntegerField(default=20) sinfo = models.CharField(max_length=100,default='个人简介') isDelete = models.BooleanField(default=False) sgrade = models.ForeignKey(Grade) def __str__(self): return self.sname class Meta: db_table = 'students'执行迁移python3 manage.py makemigrtionspython3 manage.py migrate(2) 配置admin应用（默认是添加好的）INSTALLED_APPS = [ 'django.contrib.admin', ](3) 创建管理员用户命令python3 manage.py createsuperuser提示为：依次输入 用户名->邮箱->密码->确认密码(4) 执行汉化在settings.py文件中修改如下代码LANGUAGE_CODE = 'zh-Hans' TIME_ZONE = 'Asia/Shanghai'(5) 访问127.0.0.1:8000/admin/(6) 在admin.py文件下添加要展示使用的模型类进行注册展示from django.contrib import admin from .models import Grade,Students # Register your models here. #注册模型类 在admin站点进行展示 admin.site.register(Grade) admin.site.register(Students)(7) Grade进行字段的展示添加等修改#创建一个后台字段展示的类 class GradeAdmin(admin.ModelAdmin): #字段显示属性 list_display = ['pk','gname','ggirlnum','gboynum','isDelete'] #过滤字段 list_filter = ['gname'] #搜索字段 search_fields = ['gname'] #分页 list_per_page = 5 #改变字段的顺序 添加 修改 # fields = ['gname','ggirlnum','gboynum','isDelete'] # 字段分组 添加 修改 fieldsets = [ ('num',{"fields":['ggirlnum','gboynum']}), ('base',{"fields":['gname','isDelete']}), ] admin.site.register(Grade,GradeAdmin)注意：fields 和 fieldsets不能同时存在(8) Students进行字段的展示添加等修改实例class StudentsAdmin(admin.ModelAdmin): # 搜索字段 search_fields = ['sname'] # 分页 list_per_page = 5 def mySex(self): if self.ssex: return '男' else: return '女' mySex.short_description = "性别" #并显示性别的男女 # list_display = ['pk','sname','ssex','sage','sgrade','isDelete'] list_display = ['pk','sname',mySex,'sage','sgrade','isDelete'] #过滤字段 list_filter = ['sname'] #动作位置 actions_on_top = True actions_on_bottom = False # 字段分组 添加 修改 fieldsets = [ ('分组', {"fields": ['sname', 'sage','ssex','sgrade','isDelete']}), ] admin.site.register(Students,StudentsAdmin)(9) 关联学生模型 实现在创建班级的时候 添加几个学生的数据实例：# class StudentsAdd(admin.TabularInline): #学生在添加时 横着显示 class StudentsAdd(admin.StackedInline): #学生在添加时 纵向显示 model = Students #关联模型 extra = 2 #数据的条数 #创建一个后台字段展示的类 class GradeAdmin(admin.ModelAdmin): inlines = [StudentsAdd](10) 使用装饰器完成注册@admin.register(Grade) #创建一个后台字段展示的类 class GradeAdmin(admin.ModelAdmin): ... @admin.register(Students) class StudentsAdmin(admin.ModelAdmin): ... # admin.site.register(Grade,GradeAdmin) # admin.site.register(Students,StudentsAdmin)二、分页(1) Paginator 类创建对象格式： Paginator(数据对象,整数)返回值： 分页对象属性：count 对象的总数num_pages 页面总数page_range 页码列表方法:page(num) page对象 参数为页码异常：当像page传递一个无效页码的时候抛出异常 InvalidPage传递参数不是一个整数时 则抛出 PageNotAnInteger当像page传递一个有效参数 但是没有对应页面的数据时 则抛出 EmptyPage(2) Page 对象Paginator(数据对象,整数) page()方法 返回page对象 不需要手动创建属性：object_list: 当前页上所有数据的列表number 当前页码数值paginator 当前的paginator对象has_next 是否有下一页has_previous 是否有上一页has_other_pages 判断是否有上一页或者下一页next_page_num 返回下一页的页码previous_page_num 返回上一页的页码views.py实例def index(req): g = Grade.objects.all() #获取所有班级数据 paninator = Paginator(g,2) #每页3条 try: page = int(req.GET.get('page',1)) #获取get传递过来的页码数 except: page = 1 p = paninator.page(page) #获取每页的对象 return render(req,'index.html',{'data':p}) #传递渲染 index.html 首页 你好，世界！ {% for grade in data.object_list %} --{{ grade.gname }}-----{{ grade.ggirlnum }}- {% endfor %} first « {% for page in data.paginator.page_range %} {{ page }} {% endfor %} » last get传参 我写了无数个面向对象的程序却还是找不到对象我会python这么美的编程语言却没能打动你的芳心我构造了许多方法却没让你爱上我你不是我的private更不是我可以调用的public你只是他的 protected我try着靠近你你却爱答不理我想except你的心但也没有finally三、文件上传配置：表单必须为post更改enctype的值存储路径创建 /static/upload配置settings.py文件MDEIA_ROOT=os.path.join(BASE_DIR,'static/upload')文件上传的属性和方法：myFile.read() 从文件中读取整个上传的数据（适用于小文件上传）myFile.chunks() 按块来返回文件 通过for循环进行迭代 将数据量大的文件按块写入到服务器中myFile.multiple_chunks() 会根据文件大于或者小于2.5M 返回True或者False 判断使用chunks还是read进行文件的上传myFile.name 获取文件上传的名称myFIle.size 返回文件的大小views.py#文件上传 def upload(req): if req.method == 'GET': return render(req,'form.html') if req.method == 'POST': file = req.FILES.get('file') # print(file.name) # print(file.size) newName = str(uuid.uuid4())+os.path.splitext(file.name)[-1] # path = os.path.join(settings.MDEIA_ROOT,file.name) path = os.path.join(settings.MDEIA_ROOT,newName) # print(path) with open(path,'wb') as f: if file.multiple_chunks(): print('chunk') for chunk in file.chunks(): f.write(chunk) else: print('read') f.write(file.read()) return HttpResponse('上传上来了')form.py Title 文件上传 {% csrf_token %} 四、富文本编辑器(1) 安装：pip3 install django-tinymce(2) 在settings.py文件中进行配置INSTALL_APPS 添加 tinymce#配置富文本 TINYMCE_DEFAULT_CONFIG = { 'theme':'advanced', 'width':600, 'height':400, }(3) 创建模型类models.py#创建富文本 编辑器存储数据的模型 from tinymce.models import HTMLField class Text(models.Model): article = HTMLField()执行迁移(4) 创建form表单 Title (5) 配置站点信息from .models import Text admin.site.register(Text)
一、系统User模型类导入：views.pyfrom django.contrib.auth.models import User(1) 用户的创建from django.contrib.auth.models import User u= User.objects.create_user(req.POST.get('username'),req.POST.get('email'),req.POST.get('userpass'))对象的保存u.save()(2) 用户认证导入：from django.contrib.auth import authenticate传入关键字参数进行用户的认证u = authenticate(username=req.POST.get('username'),password=req.POST.get('userpass'))认证结果认证成功返回对象认证失败返回None(3) 维持用户登录状态导入：from django.contrib.auth import login实例u = authenticate(username=req.POST.get('username'),password=req.POST.get('userpass')) if u:#验证通过 if u.is_active: #并且账户激活 login(req,u) #处理登录 状态保持 使用的依然是session return redirect(reverse('App:index')) return HttpResponse('authenticate用户认证')(4) 在模板和视图函数中判断登录状态和获取登录者数据index.html{% if request.user.is_authenticated %} #登录则为True 否则为False 欢迎:{{ request.user.username }} | 退出登录 {% endif %}views.pydef test(req): # print(req.user.email) if req.user.is_authenticated: print(req.user.email) #如果登录则取出登录者的邮箱信息 else: print('你没有登录') #输出没登录 return HttpResponse('测试request.user属性')(5) 登录的限制 login_required限制某些路由必须登录才能访问导入：from django.contrib.auth.decorators import login_required实例：@login_required(login_url='/login/') def test(req): return HttpResponse('当前路由必须登录才能进行访问')(6) 如果是从login_required重定向到登录模板 则登录成功后在跳转回去 否则去首页实例：def Login(req): if req.method == 'GET': req.session['next'] = req.GET.get('next','/') #/test/ / return render(req,'djangouser/login.html') if req.method == 'POST': ... return redirect(req.session.get('next'))(7) 修改密码from django.contrib.auth.hashers import make_password #修改密码 def update_password(req): u = authenticate(username='zhangsan', password='123456') # print(u) if u: if u.is_active: u.password = make_password('123456') u.save() return HttpResponse('修改成功')二、自定义用户模型给user模型添加phone和icon字段models.pyfrom django.db import models from django.contrib.auth.models import AbstractUser # Create your models here. class User(AbstractUser): phone = models.CharField(max_length=11,default='15611833906') icon = models.CharField(max_length=70,default='default.jpg')views.py代码修改如下 其余不变from App.models import User三、将用户认证进行重写 实现可以手机号码和用户名都能登录在App下新建auth.py文件 添加如下代码from django.contrib.auth.backends import ModelBackend from App.models import User class MyBackend(ModelBackend): def authenticate(self,username=None,password=None): user = None try: user = User.objects.get(username=username) except: try: user = User.objects.get(phone=username) except: return if user.check_password(password): return user return False在setting.py文件中 指定使用自定义的验证方法 authenticate#指定用户认证使用自己定义的认证类 AUTHENTICATION_BACKENDS = ('App.auth.MyBackend',)四、配置静态资源静态资源： 图片、css、js通常静态资源文件放在 static目录下目录结构：project/ App/ templates/ static/ img/ css/ js/ upload/ project/ manage.py(1) 在App下创建static静态资源目录project/ App/ static/ img/ bzs.jpeg在settings.py文件中 已经默认配置好了STATIC_URL = '/static/'在模板中使用{% load static %} #加载static标签 Title 首页 注意： 如果static静态资源目录存放在根目录下 则静态资源加载失败(2) 将static创建在项目的根目录下更改setting.py的配置在settings.py文件中添加如下代码STATIC_URL = '/static/' STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]模板中代码同上 不做任何改变 static在App下或者在根目录下 都正常展示
一、配置缓存settings.py#添加缓存的配置 CACHES = { 'default':{ #缓存的位置 'BACKEND':'django.core.cache.backends.db.DatabaseCache', 'LOCATION':'my_cache_table',#缓存的表 } }创建缓存表python3 manage.py createcachetable my_cache_table库中就会出现my_cache_table表实例：from django.shortcuts import render from django.views.decorators.cache import cache_page from App.models import User #展示所有用户数据的方法 @cache_page(60) def showUser(req): print('----能看到我几次？------') u = User.objects.all() return render(req,'showUser.html',{'data':u})二、手动添加缓存cache.set 设置缓存keyvaluetimeoutcache.get(key) 获取缓存cache.get_many() 获取多条缓存cache.set_many() 设置多条缓存cache.delete() 删除缓存cache.clear 清空缓存实例from django.core.cache import cache def showUser(req): html = cache.get('showUser') if html: return HttpResponse(html) else: print('----能看到我几次？------') u = User.objects.all() tem = loader.get_template('showUser.html') html = tem.render({'data': u}) cache.set('showUser',html,60) return HttpResponse(html)三、使用redis进行缓存安装：sudo pip3 install django-redis配置settings.py#添加缓存的配置 CACHES = { 'default':{ #reids进行缓存 'BACKEND':'django_redis.cache.RedisCache', 'LOCATION':'redis://127.0.0.1:6379/1',#设置缓存的数据库 } }其它位置的代码不需要改变 重新访问路由地址即可四、发送邮件注意：发送邮件报错：Mail from must equal authorized user，则需要设置临时环境变量 windows：set MAIL_USER=用作发送邮件的邮箱账号linux：export MAIL_USER=用作发送邮件的邮箱账号(1) 发送单封邮件settings.py配置#发送邮件配置 EMAIL_HOST = os.environ.get('MAIL_SERVER','smtp.1000phone.com') EMAIL_HOST_USER = os.environ.get('MAIL_USER','xialigang@1000phone.com') EMAIL_HOST_PASSWORD = os.environ.get('MAIL_PASSWORD','123456')view.pyfrom django.shortcuts import render,HttpResponse from django.core.mail import send_mail import os def sendMail(req): send_mail( 'Subject here', 'Here is the message.', os.environ.get('MAIL_USER'), ['793390457@qq.com'], fail_silently=False, ) return HttpResponse('发送邮件')(2) 发送多封邮件def sendManyPeople(req): message1 = ('Subject here', 'Here is the message', os.environ.get('MAIL_USER'), ['948807313@qq.com']) message2 = ('Another Subject', 'Here is another message', os.environ.get('MAIL_USER'), ['793390457@qq.com']) send_mass_mail((message1, message2), fail_silently=False) return HttpResponse('发送多封邮件')send_mass_mail()与send_mail()之间的主要区别send_mass_mail()和 send_mail()是 send_mail()打开每一个它的执行时间的邮件服务器的连接，同时send_mass_mail()使用其所有消息的单个连接。这使得 send_mass_mail()效率稍高。(3) 发送html文本内容的邮件#发送html文本 def sendHtmlMail(req): from django.core.mail import EmailMultiAlternatives subject, from_email, to = 'hello', os.environ.get('MAIL_USER'), '948807313@qq.com' html_content = ' This is an 百度 message. ' msg = EmailMultiAlternatives(subject,from_email=from_email,to=[to]) msg.attach_alternative(html_content, "text/html") msg.send() return HttpResponse('发送html文本的邮件')五、JsonResponse 响应json数据作用： 返回json数据 用于异步请求导入from django.http import JsonResponse使用def test(req): json = JsonResponse({'name':'zhangsan','age':18}) return HttpResponse(json) #{"name":"zhangsan","age":18}六、邮件进行注册认证创建用户模型创建视图函数 路由地址创建模板接受表单数据 添加到数据库生成token值发送邮件 渲染邮件模板邮件激活改变用户状态登录(1) 创建User模型class User(models.Model): username = models.CharField(max_length=20) password_hash = models.CharField(max_length=80) sex = models.BooleanField(default=True) age = models.IntegerField(default=20) # email = models.CharField(max_length=40,unique=True) email = models.CharField(max_length=40) icon = models.CharField(max_length=36,default='default.jpg') createTime = models.DateTimeField(auto_now_add=True) confirm = models.BooleanField(default=False) def __str__(self): return self.username class Meta: db_table = 'user'(2) 添加密码加密的装饰器from django.contrib.auth.hashers import make_password,check_password @property def password(self): raise AttributeError #密码加密 @password.setter def password(self,password): self.password_hash = make_password(password)(3) 创建表单 register.html 注册 登录 | 注册 {% csrf_token %} 注册 用户名： 密码： 激活邮箱： (4) 添加注册路由地址 url(r'^register/$',views.register,name='register'),(5) 视图函数#注册 def register(req): if req.method == 'GET': return render(req, 'register.html') if req.method == 'POST': u = User(username=req.POST.get('username'),password=req.POST.get('userpass'),email=req.POST.get('email')) u.save() token = u.get_token() #获取token # print(token) url = 'http://'+req.get_host()+reverse('Aft:activate',args=[token]) #生成激活的链接地址 subject, from_email, to = '账户激活', os.environ.get('MAIL_USER'),u.email html_content = loader.get_template('mail/activate.html').render({'url': url, 'username': u.username}) msg = EmailMultiAlternatives(subject, from_email=from_email, to=[to]) msg.attach_alternative(html_content, "text/html") msg.send() #发送邮件 return HttpResponse(' 注册成功')(6) 在models添加生成token的代码import uuid,hashlib from django.core.cache import cache #拿到生成的token值 def get_token(self): myuuid = uuid.uuid4() #生成唯一的uuid字符串 md5 = hashlib.md5() md5.update(str(myuuid).encode('utf-8')) token = md5.hexdigest() #生成惟一的加密字符串 # print(token) cache.set(token, {'id': self.id}, 3600) #设置存储token对应值的过期时间 return token(7) 邮寄激活的模板mail/activate.html 激活 欢迎：{{ username }} 请点击右侧激活 进行最后一步的激活操作 激活 (8) 在模型中添加激活的代码#检测token是否存在 @staticmethod def check_token(token): try: id = cache.get(token)['id'] u = User.objects.get(pk=id) u.confirm = True u.save() return True except: return False(9) 添加激活的视图函数#激活操作 def activate(req,token): if User.check_token(token): return HttpResponse('激活成功') else: return HttpResponse('激活失败')(10) 添加登录的模板 login.html 登录 登录 | 注册 {% csrf_token %} 登录 用户名： 密码： (11) 在models中添加登录处理的函数#检测密码 def checkPassword(self,password): return check_password(password,self.password_hash)(12) 添加登录的视图函数#登录 def login(req): if req.method == 'GET': return render(req,'login.html') if req.method == 'POST': u = User.objects.filter(username=req.POST.get('username')).first() if u and u.checkPassword(req.POST.get('userpass')): return HttpResponse('登录成功') else: return HttpResponse('登录失败')(13) 添加登录的路由地址url(r'^login/$',views.login,name='login'),(14) 将登录注册 添加ajax的请求处理
一、配置数据库settings.py数据库默认为sqlite数据库 更改成mysql数库实例:settings.py 77行DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'djangopython1807', 'USER':'root', 'PASSWORD':'123456', 'HOST':'127.0.0.1', 'PORT':3306, } }helloworld/init.py文件import pymysql pymysql.install_as_MySQLdb()二、ORM概述：对象->关系->映射任务：根据对象的类型生成表结构将对象、列表的操作 转换为sql语句sql语句查询到的结果转换为对象和列表优点：极大的减轻了开发人员的工作量，不会因为数据库的改变而修改代码三、模型的字段和可选条件(1) 字段类型字段名称字段说明参数AutoField一个根据实际ID自动增长的Integer field 通常不指定(自动创建主键id字段) CharFieldvarchar类型字段max_length存储值的最大长度TextFieldlongtext类型 长文本 IntegerFieldint 类型字段 存储整形 DecimailField存储浮点形 更加精准（存钱）max_digits=None 位数长度,decimal_places=None 小数的位数FloatField浮点类型 BooleanField存储Bool值 True/False NullBolleanField存储 null/True/False DateFielddate字段auto_now = False 如果对数据进行修改则会自动保存修改的时间 auto_now_add=False 会自动添加第一次保存的时间 俩个参数不能同时设置TimeFieldtime字段参数同上DateTimeFielddatetimefield参数同上(2) 字段选项可选参数参数说明null如果设置为True 则当前字段值可以为nullblank如果设置为True 则当前字段可以为空（什么值都没有）db_column设置字段名称 不设置 字段名称默认为属性名db_index常规索引unique唯一索引primary_key主键索引default默认值四、定义模型(1) 模型、属性、表之间的关联一个模型类 对应数据库中的一张表 一个类属性 对应 表中的一个字段(2) 创建我们测试的模型models.pyfrom django.db import models # Create your models here. class Test(models.Model): char = models.CharField(max_length=20,default='char的默认值',db_index=True) text = models.TextField(null=True) intger = models.IntegerField(blank=True,db_column='inte') deci = models.DecimalField(max_digits=5,decimal_places=2) float = models.FloatField() bool = models.BooleanField() null = models.NullBooleanField() date = models.DateField(auto_now=True) time = models.TimeField(auto_now=True) dateTime = models.DateTimeField(auto_now_add=True)(3) 元选项在模型类中定义一个Meta类class Test(models.Model): ... class Meta: db_table = '表名称' #表名默认为 应用名称_类名的小写（App_test）注意：如果是表已经创建完成 在次更改表名 需要重新生成迁移文件 执行迁移文件原生sql改表名: alter table a rename b;(4) 创建表生成迁移文件python3 manage.py makemigrations执行迁移文件python3 manage.py migrate五、测试数据库(1) 进入到python shell进行测试python3 manage.py shell(2) 导包from App.models import Test(3) 添加数据t = Test() t.char = 'char' t.text = 'text' t.intger = 1 t.deci = 12 t.float = 12 t.bool = True t.null = None t.save() t = Test(char='',text=''...) #也可以使用关键字参数添加数据(4) 查询数据#查询数据 def showData(req): t = Test.objects.get(pk=1) #id=1 print(t.char) print(t.text) return HttpResponse('查询数据')(5) 修改#修改数据 def update(req): t = Test.objects.get(pk=1) #id=1 t.char = '修改后的内容' t.save() return HttpResponse('修改数据')(6) 删除#删除数据 def delete(req): t = Test.objects.get(pk=2) t.delete() return HttpResponse('删除数据')六、模型成员(1) objects是Manager类的一个对，其作用是与数据库进行交互当定义模型的时候，如果没有指定模型管理器，Django会默认为当前模型类创建一个名为objects的管理器(2) 自定义模型管理器class User(models.Model): ... userobj = models.Manager() #自定义一个userobj的模型管理器 objects默认的就不存在了views.py中使用#查询数据 def showData(req): u = User.userobj.get(pk=1) u = User.objects.get(pk=1) #报错 属性错误 不存在 print(u) return HttpResponse('查询数据')(3) 自定义管理器 Manager类模型管理器是Django模型与数据库进行数据交互的接口 一个模型可以有多个模型管理器作用：向管理器类中添加额外的方法修改管理器返回的原始查询集重写get_queryset()方法实例：#重写get_queryset方法 修改原始查询集 class UserManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(isDelete=False) #创建用户表 class User(models.Model): ... objects = UserManager()使用#查询数据 def showData(req): u = User.objects.all() return HttpResponse('查询数据')(4) 创建对象目的：向数据库中添加数据注意： 不能够在自定义的模型中使用init构造方法，原因是已经在父类中models.Model中使用了1) 在模型类中添加一个方法实例models.pyclass User(models.Model): ... #自定义添加数据的类方法 调用方法为 User.addUser([args...]).save() @classmethod def addUser(cls,username='',sex=True,age=20,info='info'): obj = cls(username=username,sex=sex,age=age,info=info) return objviews.py使用def addUser(req): username = random.randrange(1,100000) age = random.randint(1,100) sex = [True,False] #使用自定义类方法 进行数据的添加 u = User.addUser(username,sex[random.randint(0,1)],age) u.save() return HttpResponse('添加user模型的数据')2) 在自定义管理器中添加方法models.py#重写get_queryset方法 修改原始查询集 class UserManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(isDelete=False) def addUser(self,username='',sex=True,age=20,info='info'): # u = self.model() #代表当前调用的模型 u = User() u.username = username u.sex = sex u.age = age u.info = info return uuser模型中class User(models.Model): ... objects = UserManager()views.py中使用def addUser(req): username = random.randrange(1,100000) age = random.randint(1,100) sex = [True,False] u = User.objects.addUser(username,sex[random.randint(0,1)],age) u.save() return HttpResponse('添加user模型的数据')七、模型查询概述：查询集表示从数据库拿到的对象的集合查询集可以有多个过滤器过滤器就是一个函数 根据所给的参数 限制返回的查询集从sql角度来说 查询集合和select语句等价 过滤器就是sql的where条件(1)返回多条数据（多个对象）1) all() 返回查询集中的所有数据类名.objects.all()返回 query_set 查询集#all 返回所有 def all(req): u = User.userobj.all() print(u) return render(req,'show.html',{'data':u})实现分页#all 返回所有 def all(req): try: page = int(req.GET.get('page')) except: page = 1 u = User.userobj.all()[(page-1)*5:page*5] #0:5 5 10 print(u) return render(req,'show.html',{'data':u})2) filter() 将符合条件的数据进行返回类名.objects.filter(属性名=属性值....)如果条件多个，逗号隔开为and模式and操作类名.objects.filter(属性名=属性值，属性名=值) == 类名.objects.filter(属性名=属性值).filter(属性名=属性值)实例：def filter(req): u = User.userobj.filter(sex=True,username__contains='1') u = User.userobj.filter(sex=True).filter(username__contains='1') return render(req,'show.html',{'data':u})3) exclude() 过滤掉符合条件的数据类名.objects.exclude(属性名=属性值....)def filter(req): u = User.userobj.exclude(sex=True,username__contains='1') u = User.userobj.exclude(sex=True).exclude(username__contains='1') return render(req,'show.html',{'data':u})4) order_by() 排序order_by('id')order_by('-id')实例：def orderBy(req): u = User.userobj.filter().order_by('-id') u = User.userobj.order_by('-id') u = User.userobj.order_by('id') return render(req,'show.html',{'data':u})5) reverse() 反转对order_by的反转def reverse(req): u = User.userobj.order_by('id').reverse() u = User.userobj.order_by('-id').reverse() u = User.userobj.order_by('-age').reverse() return render(req,'show.html',{'data':u})6) values() 返回一个列表 每条数据是一个字典def values(req): u = User.userobj.values() #默认返回所有 u = User.userobj.values('id','age') #只返回id和age字段的值 print(u) #[{'username':'张三','age':18}] return render(req,'show.html',{'data':u})7) value_list() 得到一个元组格式的数据 只有值def value_list(req): u = User.userobj.values_list() #默认返回所有 u = User.userobj.values_list('id','age')#只返回id和age字段的值 print(u) return render(req,'show.html',{'data':u})(2)返回一条数据（1个对象）1) get() 返回一个对象注意：只能匹配一条数据 如果多条则抛出 MultipleObjectsReturned 异常如果匹配数据失败 则抛出 DoesNotExist 异常只能匹配一条数据实例：def myGet(req): u = User.userobj.get(pk=1) print(u) u = User.userobj.get(id=1) print(u) u = User.userobj.get(age=43) #报错 原因：只能返回一个值 但是匹配到了多个 MultipleObjectsReturned u = User.userobj.get(id=20) #报错 DoesNotExist 匹配失败 print(u) return HttpResponse('get')2) count() 返回统计条数#返回数据条数 def count(req): u = User.userobj.count() u = User.userobj.filter(sex=True).count() print(u) return HttpResponse('返回数据的条数')3) first() 取出第一条数据def first(req): u = User.userobj.order_by('id').first() #第一条 print(u) return HttpResponse('first')4) last() 取出最后一条数据def first(req): u = User.userobj.order_by('id').last() #最后一条 print(u) return HttpResponse('first')5) exists() 判断数据是否存在 返回bool值def exists(req): u = User.userobj.filter(age=400).exists() print(u) return HttpResponse('exists')(3)比较运算1) 完全匹配运算符__exact 对大小写敏感__iexact 对大小写不敏感实例：def exact(req): u = User.userobj.filter(username__exact='abc') u = User.userobj.filter(username__iexact='abc') u = User.userobj.filter(username='abc') return render(req,'show.html',{'data':u})2) __contains 包含 大小写敏感(真敏感)def contains(req): #contains # u = User.userobj.filter(username__contains='a') u = User.userobj.filter(username__contains='A') return render(req,'show.html',{'data':u}) 3) __startswith __endswith 以...开头 以...结尾 区分大小写__istartswith 不区分大小写的 以...作为开头__iendswith 不区分大小写 以...作为结尾实例：#以...作为开头和结尾 def startend(req): u = User.objects.all() #查所有 u = User.objects.filter(username__startswith='3') u = User.objects.filter(username__startswith='a') u = User.objects.filter(username__startswith='A') u = User.objects.filter(username__istartswith='a') u = User.objects.filter(username__iendswith='C') u = User.objects.filter(username__endswith='9') u = User.objects.filter(username__startswith='5',username__endswith='5') return render(req,'show.html',{'data':u})4) null的数据的查询__isnull 值为 True/False实例#查询为空的 def null(req): #查询为null的数据 u = User.objects.filter(username__isnull=True) u = User.objects.filter(username=None) #查询不为null的数据 u = User.objects.exclude(username__isnull=True) u = User.objects.filter(username__isnull=False) return render(req,'show.html',{'data':u})5) in 是否在...里__in = [值1,值2...]实例def In(req): #在...范围内 u = User.objects.filter(id__in=[1,2,3,4]) u = User.objects.filter(pk__in=[1,2,3,4]) #不在...范围内 u = User.objects.exclude(pk__in=[1,2,3,4]) return render(req,'show.html',{'data':u})6) range 值的范围__range = [start,end]#range的使用 def Range(req): u = User.objects.filter(age__range=[20,40]) #between 20 and 40 u = User.objects.filter(age__range=[20,33]) #between 20 and 33 return render(req,'show.html',{'data':u})7) 比较运算符__gt 大于__gte 大于等于__lt 小于__lte 小于等于实例#比较运算符 def compare(req): u = User.objects.filter(id__gt=2) u = User.objects.filter(id__gte=2) u = User.objects.filter(id__lt=5) u = User.objects.filter(id__lte=5) u = User.objects.filter(id__exact=5) u = User.objects.exclude(id__exact=5) return render(req,'show.html',{'data':u})(4)聚合函数导入：from django.db.models import Avg,Max,Min,Sum,Count1) Avg 平均数#聚合函数 def jh(req): u = User.objects.aggregate(Avg('age')) return HttpResponse('值为{}'.format(u))2) Count 统计3) Max 最大from django.db.models import Avg,Count,Sum,Max,Min #聚合函数 def jh(req): u = User.objects.aggregate(Avg('age')) u = User.objects.aggregate(Sum('age')) u = User.objects.aggregate(Max('age')) return HttpResponse('值为{}'.format(u))4) Min 最小5) Sum 求和Q对象作为or查询来使用def q(req): u = User.objects.filter(Q(age__gt=20)) #这个没有and和or一说 因为就一个条件 u = User.objects.filter(Q(age__gt=20)|Q(sex=True)) #查询age大于20 或 性别为True的 # print(u) # return HttpResponse('q') # return HttpResponse('值为{}'.format(u)) return render(req,'show.html',{'data':u})F对象作用： 可以使用模型A的属性 与 模型B的属性 进行比较实例：def f(req): u = User.objects.filter(id__gte=F('age')) print(u) return HttpResponse('f')八、数据的修改(1)save()def update(req): u = User.objects.get(pk=11) u.username = 'zhangsan' u.save() return HttpResponse('save修改')(2)update()def update(req): u = User.objects.filter(id__in = [1,2,3]) u.update(sex=True) return HttpResponse('update修改多个值')区别：save() 适用于单个对象的值的修改 update() 适用于多条数据的值的修改九、模型对应关系1:1（一对一）1:N（一对多）M:N（多对多）关系：1:1和1:N共同使用的属性on_delete:models.CASCADE 默认值 当主表的数据删除，则从表数据也删除models.PROTECT 保护模式 一但主表数据被删除，从表数据为保护模式，不删除models.SET_NULL 当主表数据被删除，从表外键的字段的值将会设置为null，但是一定要将这个字段设置为null=True(1) 1对1使用OneToOneField创建1对1的模型关系 将要创建对应关系的模型添加OneToOneField创建模型 User和IdCard#创建用户表 class User(models.Model): username = models.CharField(max_length=20,db_index=True,null=True) sex = models.BooleanField(default=True) age = models.IntegerField(default=20) info = models.CharField(max_length=100,default='info') icon = models.CharField(max_length=60,default='default.jpg') isDelete = models.BooleanField(default=False) createTime = models.DateTimeField(auto_now_add=True) def __str__(self): return self.username class Meta: db_table = 'user' #1对1的表关系 class IdCard(models.Model): num = models.CharField(max_length=18) name = models.CharField(max_length=8) sex = models.BooleanField(default=True) birth = models.DateTimeField(auto_now_add=True) address = models.CharField(max_length=100,default='xxxxxx') # user = models.OneToOneField(User) #1对1的外键 默认删除 # user = models.OneToOneField(User,on_delete=models.PROTECT) #保护模式 如果删除主表中与从表对应关系的数据 则不能删除 user = models.OneToOneField(User,on_delete=models.SET_NULL,null=True) #保护模式 def __str__(self): return self.name class Meta: db_table = 'idcard'添加#添加用户信息 def adduser(req): u = User.addUser('王五') u.save() return HttpResponse('添加用户信息') #添加1对1的idcard数据 def addIdCard(req): u = User.objects.get(pk=2) idcard = IdCard(num=random.randrange(1000000000,10000000000),name='李四',user=u) idcard.save() return HttpResponse('添加卡的信息')查询#数据查询 def showOneToOne(req): idcard = IdCard.objects.first() print(idcard.user) #查询卡对应用户的对象 print(idcard.user.icon) #查询卡对应用户的对象的icon属性 u = User.objects.first() print(u.idcard) #idcard关联的数据 print(u.idcard.num) #取出idcard对象的num属性 return HttpResponse('1对1数据的查询')删除#数据的删除 def deleteOneToOne(req): #删除主表数据 从表数据随着主表数据而删除 # u = User.objects.first() u = User.objects.get(pk=2) u.delete() #删除从表数据 主表数据 没有改变 # idcard = IdCard.objects.first() # idcard.delete() return HttpResponse('删除了第一个用户的数据')(2) 1对多使用ForeignKey创建1对多的模型关系，将要创建对应关系的模型添加ForeignKey。也就是说，设置主表和从表的关系时，将外键添加到从表中创建模型 grade和students#班级表 class Grade(models.Model): gname = models.CharField(max_length=15) gnum = models.IntegerField() ggirlnum = models.IntegerField() gboynum = models.IntegerField() class Meta: db_table = 'grade' #学生表 class Students(models.Model): sname = models.CharField(max_length=10) ssex = models.BooleanField(default=True) sage = models.IntegerField(default=20) sgrade = models.ForeignKey(Grade) #1对多的外键 默认删除 # sgrade = models.ForeignKey(Grade,on_delete=models.PROTECT) #保护模式 如果删除主表中与从表对应关系的数据 则不能删除 # sgrade = models.ForeignKey(Grade,on_delete=models.SET_NULL, null=True) # 保护模式 def __str__(self): return self.sname class Meta: db_table = 'students'添加#添加grade信息 def addGrade(req): Grade(gname='python1807',gnum=63,ggirlnum=6,gboynum=57).save() Grade(gname='python1808',gnum=50,ggirlnum=2,gboynum=48).save() return HttpResponse('添加grade信息') #添加students信息 def addStudents(req): Students(sname='梁义',sgrade=Grade.objects.get(pk=1)).save() Students(sname='贾江龙',sgrade=Grade.objects.get(pk=1)).save() Students(sname='尚子义',sgrade=Grade.objects.get(pk=2)).save() Students(sname='王鹏飞',sgrade=Grade.objects.get(pk=2)).save() return HttpResponse('添加students信息')查询#1对多查询 def oneToManyShow(req): g = Grade.objects.get(pk=1) s = g.students_set.all() for i in s: print(i) return HttpResponse('查询1对多')删除#删除主表数据 默认还是 主表数据删除 从表对应数据也被删除 def deleteGrade(req): g = Grade.objects.first() name = g.gname g.delete() return HttpResponse('删除主表数据{}'.format(name))(3) 多对多使用ManyToManyField创建多对多的模型关系，将要创建对应关系的模型添加ManyToManyField创建模型 User和Posts#创建用户表 class User(models.Model): username = models.CharField(max_length=20,db_index=True,null=True) sex = models.BooleanField(default=True) age = models.IntegerField(default=20) info = models.CharField(max_length=100,default='info') icon = models.CharField(max_length=60,default='default.jpg') isDelete = models.BooleanField(default=False) createTime = models.DateTimeField(auto_now_add=True) def __str__(self): return self.username class Meta: db_table = 'user' #以下为多对多 posts关联用户 class Posts(models.Model): title = models.CharField(max_length=20,default='标题') article = models.CharField(max_length=200,default='article') createtime = models.DateTimeField(auto_now=True) users = models.ManyToManyField(User) def __str__(self): return self.title class Meta: db_table = 'posts'添加#添加grade信息 def addPosts(req): Posts(title='以后的你感谢现在拼搏的自己').save() Posts(title='阿甘正传').save() Posts(title='斗罗大陆').save() return HttpResponse('添加Posts信息')添加一个多对多的数据#添加收藏 def addColl(req): u1 = User.objects.first() p1 = Posts.objects.first() p1.users.add(u1) return HttpResponse('添加多对多的数据')添加多个多对多的数据#添加收藏 def addColl(req): u1 = User.objects.first() u2 = User.objects.last() p = Posts.objects.get(pk=2) p.users.add(u1,u2) #添加多个对象 return HttpResponse('添加多对多的数据')查询#查询 用户收藏了哪些帖子 def showPosts(req): u = User.objects.first() data = u.posts_set.all() for i in data: print(i) return HttpResponse('查询收藏了哪些帖子') #查看帖子对应多的关系 def showUsers(req): p1 = Posts.objects.first() data = p1.users.all() for i in data: print(i) return HttpResponse('查询帖子被哪个用户收藏了')删除 remove 1条数据#删除 def deleteData(req): p1 = Posts.objects.first() u1 = User.objects.first() p1.users.remove(u1) return HttpResponse('1号用户取消收藏1号帖子')remove 多条数据#删除 def deleteData(req): p2 = Posts.objects.get(pk=2) u1 = User.objects.first() u2 = User.objects.last() p2.users.remove(u1,u2) return HttpResponse('1号用户取消收藏1号帖子')
一、概述模板由俩部分组成：html代码逻辑控制代码作用：快速生成html页面优点：视图和模板可以理解为 M:N的关系 模板可以被任意视图调用 视图调用任意模板模板实现了业务逻辑和内容显示的分离二、模板的渲染(1) renderrender(request,tem_name,context=None)请求对象模板名称渲染的内容实例：url(r'^$',main.index,name='index'), def index(request): return render(request,'index.html',{'title':"首页"})(2) loader 渲染模板导入from django.template import loader实例:from django.template import loader def index(request): tem = loader.get_template('index.html') #拿到模板对象 result = tem.render({'title':"首页"}) #渲染模板 print(result) return HttpResponse(result) #响应模板三、模板中变量格式： { { 变量名称 } }就是视图像模板传递的数据注意：如果模板渲染的变量不存在 则插入空白字符模板中使用语法：可以在模板中调用方法/调用属性字典查询（不建议）数字索引四、 模板中标签格式： {% 标签名称 %}作用：在输出中创建文本控制逻辑和循环(1) if/elif/else/endif 标签可用的运算符> < >= <= == ! and or not in not in语法格式：{% if condition %} ... {% endif %}实例：{% if grade > 80 %} print({ { grade } }大于 80) {% elif grade >= 70 %} print({ { grade } }大于等于 70) {% else %} print({ { grade } }<70) {% endif %}(2) for标签A 语法格式：{% for xxx in xxx %} ... {% endfor %}实例：{% for i in lista %} { { i } } {% empty %} 当list变量不存在 则执行empty {% endfor %}B 迭代字典：{'dict':{'name':"张三",'age':18} } {#{% for key in dict %}#} #迭代拿到的是key {% for key,value in dict.items %} #拿到key和value { { key } }------{ { value } } {% endfor %}C 获取for迭代的状态变量描述forloop.counter迭代的索引从1开始forloop.counter0迭代的索引从0开始forloop.revcounter迭代的索引从最大长度递减到1forloop.revcounter0迭代的索引从最大长度递减到0forloop.first是否为第一次迭代forloop.last是否为最后一次迭代forloop.parentloop获取迭代嵌套的上一曾迭代的对象实例 {% for i in list %} {% for i in list %} { { forloop.counter } }---{ { forloop.counter0 } }---{ { forloop.revcounter } }----{ { forloop.revcounter0 } }----{ { forloop.first } }----{ { forloop.last } }---{ { forloop.parentloop.counter } } {% endfor %} {% endfor %} 注意：模板中的迭代不能使用range() 不支持for不支持和else搭配 而是和empty搭配 功能和esel一样 当迭代的变量不存在 则执行empty(3) 注释单行注释 {# 内容 #}多行注释{% comment %}​ ...{% endcomment %}(4) ifequal 标签说明: 判断俩个值是否相等 相等则为True实例{% ifequal 1 1 %} print(1==1) {% else %} print(1!=1) {% endifequal %}(5) ifnotequal 标签说明: 判断俩个值是否不相等 不相等则为True{% ifnotequal 1 1 %} print(1==1) {% else %} print(1!=1) {% endifnotequal %}五、模板的导入 include语法格式:{% include '路径/模板名称.html' %}注意：include会将导入的模板的所有代码 copy到你include的位置实例: Title {% include 'common/header.html' %} {% include 'common/footer.html' %} 六、模板的继承block 在父模板中 预留区域 使子模板可以去填充extends 继承 父模板 实现模板的复用实例：common/base.html {% block head %} {% block meta %} {% endblock %} {% block title %}Title{% endblock %} {% block styles %} {% endblock %} {% endblock %} {% block navbar %} Toggle navigation Brand Link (current) Link Dropdown Action Another action Something else here Separated link One more separated link Submit Link Dropdown Action Another action Something else here Separated link {% endblock %} {% block content %} {% block pagecontent %} {% endblock %} {% endblock %} {% block scripts %} {% endblock %} 注意：block使用和flask一样 在block的外部添加的内容不会被解析显示出来如果想复用父模板的block内的代码 需要使用 变量 block.super 进行复用{ { block.super } } == flask jinja2 { { super() } }七、过滤器语法格式: { { var|过滤器 } }作用： 在数据展示前 使用函数进行数据的修改过滤器upper 大写lower 小写capfirst 首字母大写first 第一个字符center 输出指定的长度 并把值居中{ { 'test' | center:10 } } #把test字符串填充为10个长度 居中显示testcut 查找并删除指定字符{ { ’123abc‘|cut:"abc" } } #123default 默认值 当值为undefined或bool的False时都执行默认值{ { False|default:'默认值' } }default_if_none 如果值为None则执行默认值{ { None|default_if_none:'默认值' } }divisibleby 判断值是否能被某个数整除{ { num|divisibleby:num } }escape 转换为html实体safe 不转义html标签autoescape 可以解析和不解析{% autoescape on/off %} #on不解析html代码 off解析{% endautoescape %}floatformat 保留小数位数 默认保留一位{ { 123.123|floatformat:2 } } #保留俩位小数length 计算个数random 返回列表的随机项{ { list:random } }wordcount 统计单词的个数date 格式化时间{'date':datetime.now()}{ { date|date:'Y-m-d' } }{ { date|date:'F j,Y' } }addslashes 添加斜线进行特殊字符转义join 拼接字符串striptags 去除html标签八、加减乘除(1) 加法{ { value|add:num } }{ { 5|add:5 } } 5+5=10(2) 减法{ { value|add:-num } }{ { 5|add:-5 } } 5-5=0(3) 乘法{% widthration %}{% widthratio 5 1 10 %} == (5/1)*10(4) 除法{% widthration %}{% widthratio 10 5 1 %} == (5/10)*1九、验证码def verifycode(request): # 引入绘图模块 from PIL import Image, ImageDraw, ImageFont # 引入随机函数模块 import random # 定义变量，用于画面的背景色、宽、高 bgcolor = (random.randrange(20, 100), random.randrange( 20, 100), random.randrange(20, 100)) width = 100 height = 50 # 创建画面对象 im = Image.new('RGB', (width, height), bgcolor) # 创建画笔对象 draw = ImageDraw.Draw(im) # 调用画笔的point()函数绘制噪点 for i in range(0, 100): xy = (random.randrange(0, width), random.randrange(0, height)) fill = (random.randrange(0, 255), 255, random.randrange(0, 255)) draw.point(xy, fill=fill) # 定义验证码的备选值 str = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm' # 随机选取4个值作为验证码 rand_str = '' for i in range(0, 4): rand_str += str[random.randrange(0, len(str))] # 构造字体对象 font = ImageFont.truetype(r'/home/xlg/PycharmProjects/fonts/ADOBEARABIC-BOLDITALIC.OTF', 40) # 构造字体颜色 fontcolor1 = (255, random.randrange(0, 255), random.randrange(0, 255)) fontcolor2 = (255, random.randrange(0, 255), random.randrange(0, 255)) fontcolor3 = (255, random.randrange(0, 255), random.randrange(0, 255)) fontcolor4 = (255, random.randrange(0, 255), random.randrange(0, 255)) # 绘制4个字 draw.text((5, 2), rand_str[0], font=font, fill=fontcolor1) draw.text((25, 2), rand_str[1], font=font, fill=fontcolor2) draw.text((50, 2), rand_str[2], font=font, fill=fontcolor3) draw.text((75, 2), rand_str[3], font=font, fill=fontcolor4) # 释放画笔 del draw # 存入session，用于做进一步验证 request.session['verify'] = rand_str # 内存文件操作 import io buf = io.BytesIO() # 将图片保存在内存中，文件类型为png im.save(buf, 'png') # 将内存中的图片数据返回给客户端，MIME类型为图片png return HttpResponse(buf.getvalue(), 'image/png')验证码在模板中展示url(r'^getcode/$',main.verifycode,name='verifycode'), 验证过程判断验证码判断用户名判断密码登录或者显示错误信息
一、视图的概念(1) 视图的作用接收用户的请求 并响应给用户(2) 视图函数的本质python的函数(3) 视图的响应网页重定向错误模板404 NOT_FOUND500 SERVER_ERROR400 BAD_REQUESTjson 数据二、url配置路由：处理url地址与视图函数之间的程序 称之为路由(1) 配置制定根级的url（django帮你配置好的）ROOT_URLCONF = 'helloworld.urls'(2) urlpatterns 列表装有所有路由地址的列表url 参数：regexp 正则view 视图函数名name 给当前的url起名字 （url的反向解析）url中正则的参数的使用：r 必须 转义特殊字符^ 必须 必须完全匹配$ 必须 必须完全匹配注意: 也就是正则路由存在 ^和$就是和url请求的地址完全匹配 而不是 包含关系(3) 不带参数的urlurlpattern = [ url(r'^test/$', views.test), ] views.py def test(req): return HttpResponse('test')(4) 带一个参数的urlurlpattern = [ url(r'^arg/(\d{2})/$', views.test), #参数2个数值 ] views.py def arg(req,arg1): return HttpResponse(arg1)请求地址为 :http://127.0.0.1:8000/arg/11/注意：路由地址想要带参数 则必须添加() 作为值的存储(5) 带多个参数的urlurlpattern = [ url(r'^args/(\w{2})/(\w{2})/$',views.args) #带多个参数的路由地址 url(r'^args/(\w{2})_(\w{2})/$',views.args), #带多个参数的路由地址 ] #带多个的参数的视图函数 def args(req,arg1,arg2): return HttpResponse('arg1的值为{} arg2的值为{}'.format(arg1,arg2))请求地址为:http://127.0.0.1:8000/arg/11/22/http://127.0.0.1:8000/arg/11_22/(6) 一个视图函数 是否可以有多个路由地址路由地址和flask一样，可以多个路由指向同一个视图函数三、反向解析概述： 如果模板中的链接或者使用的url为硬链接 则路由地址一旦发生改变 所有地址都要修改 增加了后期代码的维护 所以所有地址都要动态生成 减轻后期维护作用于： 模板中使用方法：在helloworld/urls.py的 include 添加namespace属性url(r'^',include('App.urls',namespace='App')),给App/urls.py 的url方法 添加name属性url(r'^test/$', views.test,name='test'), # /test/在模板中使用 反向解析 去test视图函数 去test视图函数四、request对象(1) request对象每个视图函数 都必须有一个形参 接受django传递过来的用户请求的对象 request(2) 概述服务器接收到用户请求以后 会创建出request对象 视图的第一个参数 就是request对象(3) 属性path 只请求的路径method 获取请求的方式GET 获取get请求参数获取某一个参数request.GET.get('key')如果key重名request.GET.getlist('key')POST 获取POST的请求参数FILES 获上传文件COOKIES 获取请求过来的cookiesession 获取session数据META 包含了http请求的所有header头信息格式化后显示def requestAttr(request): values = request.META.items() html = [] for k,v in values: html.append(' {} {} '.format(k,v)) # return HttpResponse('request属性') return HttpResponse(' %s '%'\n'.join(html))常用的key值REMOTE_ADDR 库户端IP地址HTTP_USER_AGENT 浏览器和系统的信息的字符串HTTP_REFERER 获取从哪里点击过啦的链接地址(4) 方法get_full_path() 获取完整的请求（不包括域名和端口）get_host() 获取主机和端口is_ajax() 判断是否为ajax请求五、HttpResponse 响应概述： 给浏览器进行响应(1) 响应的方法HttpResponse()特点： 不调用模板 直接进行内容的响应实例：from django.http import HttpResponse def index(request): return HttpResponse('响应内容')属性：res = HttpResponse()res.content 设置/获取内容res.status_code 设置/获取状态码res.charset 设置/获取字符编码方法：write() 写内容set_cookie() 设置cookiedelete_cookie() 删除cookie六、重定向 redirectHttpResponseRedirectredirect(1)HttpResponseRedirect/redirect 重定向导入:from django.http import HttpResponseRedirectfrom django.shortcuts import redirect实例测试用视图和路由地址url(r'^$',views.index,name='index'), def index(request): return render(request,'index.html') url(r'^args/(\w+)/(\d{1,2})/',views.args,name='args'), #带参数的路由地址 def args(request,name,age): return HttpResponse("name:{}\nage:{}".format(name,age))跳转无参路由地址 indexurl(r'^redirect/$',views.myRedirect,name='myRedirect'), #测试重定向的路由 #重定向测试的视图函数 def myRedirect(request): #不带参的重定向 跳转到首页 return HttpResponseRedirect('/') return redirect('/')跳转有参路由地址 args#重定向测试的视图函数 def myRedirect(request): #带参的重定向 跳转到args return HttpResponseRedirect('/args/lisi/18/') return redirect('/args/lisi/18/')(2) reverse 通过namespace 和url的name值 反向构造出路由地址reverse 和 flask中的url的作用一样导入from django.urls import reverse构造不传参路由地址reverse("App:testResponse") #动态解析路由地址 == url_for() /testresponse/构造传参路由地址reverse("App:args",args=['wangwu',20]) /args/wangwu/20/关键字参数构造路由地址将App/urls.py的url中的正则路由更改url(r'^args/(?P<name>\w+)/(?P<age>\d{1,2})/',views.args,name='args'),反向解析路由地址关键字参数reverse("App:args",kwargs={'name':'wangwu','age':20}) /args/wangwu/20/(3) redirect和reverse组合使用#重定向测试的视图函数 def myRedirect(request): #正常传参 return HttpResponseRedirect(reverse("App:args",args=['wangwu',20])) #关键字传参 return redirect(reverse("App:args",kwargs={'name':'zhaoliu','age':30}))(4) 模板中的动态生成url地址1) 无参路由首页 #/2) 构造带参路由地址args #/args/lisi/20/3) 关键字参数构造路由地址 #/args/lisi/20/注意：关键字参数的路由地址为url(r'^args/(?P<name>\w+)/(?P<age>\d{1,2})/',views.args,name='args'),七、COOKIE 操作(1) 设置cookieResponse.set_cookie(​ key,​ value,​ max_age,​ expires,​ path, 生效的路径​ domain, 生效的域名​ secure, 设置HTTPS传输​ httponly, 仅http传输 不能使用js获取cookie)过期时间都是以秒为单位的实例：#路由地址 url(r'^setcookie/',mycookie.set_cookie,name='setcookie'), #设置cookie def set_cookie(req): # return HttpResponse('set_cookie') res = HttpResponse('设置cooke') res.set_cookie('name','zhangsan') #默认浏览会话结束 return res(2) 设置cookie并设置过期时间url(r'^setcookielifetime/',mycookie.set_cookie_lifetime,name='set_cookie_lifetime'), #设置cookie并设置过期时间 def set_cookie_lifetime(req): res = HttpResponse('设置cooke并设置过期时间') # res.set_cookie('name','lisi',max_age=60) res.set_cookie('name','lisi',expires=60) return res(3) 获取cookieurl(r'^getcookie/',mycookie.get_cookie,name='get_cookie'), #获取cookie def get_cookie(req): print(req.COOKIES) value = req.COOKIES.get('name') return HttpResponse("值为{}".format(value))(4) 删除cookieurl(r'^deletecookie/',mycookie.del_cookie,name='del_cookie'), #删除cookie def del_cookie(req): res = HttpResponse('删除cookie') res.delete_cookie('name') return res八、session概述： http是无状态协议 每一次请求都是一个新的会话使用cookie和session进行用户状态的维持 在客户端或者客户端和服务器端 存储有关会话的数据存储方式：cookie 将所有数据都存储在客户端，都是明文存储，所以不要存敏感的数据，并且存储数据有大小的限制session 将数据存储在服务器端，客户端使用cookie存储session的唯一id值，sessionid(1) 开启sessionsettings.py文件INSTALLED_APPS = [ 'django.contrib.sessions', ] MIDDLEWARE = [ 'django.contrib.sessions.middleware.SessionMiddleware', ](2)使用session启用session后 每一个request请求 都有session属性(3) 设置session生成session存储所需要的系统表python3 manage.py migrate设置：request.session[key] = value#设置session def set_session(req): req.session['name'] = 'zhangsan' req.session['sex'] = 'sex' return HttpResponse('设置session')(4) 设置session并设置过期时间session默认存活时间为两周request.session.set_expiry(value)value值：integer 整数 秒0 当前浏览会话结束datetimetimedeltaNone 依赖于全局session过期#设置session并设置过期时间 def set_session_lifetime(req): req.session.set_expiry(60) #过期时间1分钟 req.session['name'] = '张三' return HttpResponse('设置session并设置过期时间')(5) 获取session#获取session def get_session(req): print(req.session) v = req.session.get('name','default') return HttpResponse('获取session-----{}'.format(v))(6) 删除 sessionclear() 清空所有session 但是不会将表中的session清除flush() 清空所有 并删除表中的session数据logout(request) 清空所有 并删除表中的session数据del request.session['name']clear 清空所有session 但是不会将表中的session清除#清除session def del_session(req): req.session.clear() #清除所有session 不删除表中数据 return HttpResponse('清除session')flush 清空所有 并删除表中的session数据#清除session def del_session(req): # req.session.flush() #清除所有session return HttpResponse('清除session')logout 清空所有 并删除表中的session数据from django.contrib.auth import logout #清除session def del_session(req): logout(req) ##清除所有session return HttpResponse('清除session')del 删除某一个session值#清除session def del_session(req): del req.session['name'] return HttpResponse('清除session')(7) 设置session的保存位置1) 默认保存在数据库的 django_session表中SESSION_ENGINE = 'django.contrib.sessions.backends.db' 2) 保存在内存中 cacheSESSION_ENGINE = 'django.contrib.sessions.backends.cache' 3) 保存在内存和表中先去内存中查找 如果不存在则去表中查找 效率高 安全性高SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'4) 使用redis缓存 session安装：pip3 install django-redis-sessions配置settings.py#使用redis缓存session SESSION_ENGINE = 'redis_sessions.session' #redis存储session SESSION_REDIS_HOST = '127.0.0.1' #主机 SESSION_REDIS_PORT = '6379' #端口 SESSION_REDIS_DB = 0 #选择数据库(8) session的全局配置SESSION_COOKIE_NAME = 'sessionid' SESSION_COOKIE_AGE = 1209600 #设置cookie存活时间 设置session的存活时间(9) session常用的操作#设置获取删除session request.session[key] = value request.session.get(key) request.session.clear() request.session.flush() logout(request) del request.session[key] #session其它操作 req.session.keys() req.session.values() req.session.items() #获取session key的值 req.session.session_key九、使用session登录实例from django.shortcuts import render,HttpResponse,redirect,reverse #登录 def login(req): # return HttpResponse('login') return render(req,'login.html') #登录处理 def dologin(req): username = req.POST.get('username') userpass = req.POST.get('userpass') if username=='zhangsan' and userpass=='123456': req.session['uid'] = 1 req.session['username'] = username return redirect(reverse('App:index')) return redirect(reverse('App:login')) #退出登录 def logout(req): req.session.flush() return HttpResponse(" 退出成功4秒后条到首页 如不能跳到首页 请手动点击首页")
一、安装命令：pip3 install django==1.11.4支持python解释器的版本为 2.7、3.4、3.5、3.6检查是否安装成功：>>> import django >>> django.get_version() 1.11.4注意：如果电脑是在windwos安装的django，所有代码书写都相同，如果django不能够运行，则查看计算机的名称是否为中文。二、创建django项目命令：django-admin startproject helloworld(项目名称)创建成功后：目录层级为helloworld/ helloworld/ __init__.py settings.py 配置文件 urls.py 路由地址文件 wsgi.py 项目的入口 项目部署的时候使用 manage.py 项目启动文件项目启动：python3 manage.py runserver [Ip:port] 127.0.0.1:8000 python3 manage.py runserver 0.0.0.0:8000 #任何地址都可以进行访问三、配置django数据库默认使用的是sqlite配置sqlite数据库代码settings.pyDATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }配置mysql数据库DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'djangopython1807',#数据库名称 'USER':'root', #用户名 'PASSWORD':'123456', #密码 'HOST':'127.0.0.1', #主机 'PORT':3306, #端口 } }在helloworld的init.py文件添加如下代码import pymysql pymysql.install_as_MySQLdb()四、想要添加你的模型,视图,url,模板,需要创建App命令：python3 manage.py startapp App(应用名称) 或者 django-admin startapp App五、添加路由地址，视图函数App/views.py 添加视图函数from django.shortcuts import render,HttpResponse # Create your views here. def index(request): return HttpResponse('hello django')render 渲染模板HttpResponse 直接构造响应helloworld/urls.py文件中from django.conf.urls import url from django.contrib import admin from App import views #导入视图函数的模块 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', views.index), #访问首页视图 ]请求地址为为：http://127.0.0.1:8000s路由地址url的注意：url方法中的^的作用就是必须以当前的路由地址作为开头 如果^ 不存在 则是包含关系实例:urlpatterns = [ url(r'^admin/', admin.site.urls), # url(r'^$', views.index), url(r'^test/$',views.test), #/test/ url(r'test/',views.test), #/test/ ]上面俩个test的路由地址区别：带^是访问时候 地址必须为 127.0.0.1:8000/test/不带^ 访问地址为 127.0.0.1:8000/abctest/ #只要路由地址包含test 就可以访问成功六、将在自己的App下 创建自己的路由文件App/urls.py代码from django.conf.urls import url from App import views urlpatterns = [ url(r'^test/$', views.test), # /test/ ]helloworld/urls.py代码from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^',include('App.urls')), ]七、配置模板目录路径：App/templates/ 模板引擎选择 djangotest.html Title test渲染的模板 views.test视图函数def test(req): return render(req,'test.html')更改settings.py的DIRS的值TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', # 'DIRS': [], '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', ], }, }, ]注意：在install_apps 下添加app的名字INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'App', #项目名称 ]渲染模板注意：变量和标签 和 flaske模板中的一样def test(req): return render(req,'test.html',{'con':'渲染的内容'}) #参数1 request 模板名称test.html Title test渲染的模板 {{ con }} 八、指定错误页面(1) 在settings.py文件中 关闭调试模式DEBUG = False注意：如果debug不改为False 则不会返回错误的模板 而是显示错误信息(2) ALLOWED_HOSTS 设置允许那些主机访问ALLOWED_HOSTS = ['*'](3) 在templates模板目录中 添加404.html当出现404时 自动返回404.html(4) request_path 展示 NOT_FOUND的路由地址实例:settings.pyDEBUG = True # DEBUG = False ALLOWED_HOSTS = ['*']404.html Title 404页面 {{ request_path }}
一、Model对数据的操作3种办法(1) 最原始的 提交 和 回滚#最原始的添加 提交或者回滚 每次都需要 @test.route('/insert_one/') def insert_one(): try: # u = User(username='zhangshang',sex=False,age=18) u = User('lisi',True,20) db.session.add(u) db.session.commit() except: db.session.rollback() return 'insert_one'注意：每次都需要提交和回滚(2) 在settings.py进行配置SQLALCHEMY_COMMIT_ON_TEARDOWN = True每次添加或者保存，修改，删除数据 都不需要commit() 或者 rollback()实例app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True #设置自动提交 #settings.py已经设置为数据自动提交 @test.route('/auto_insert_one/') def auto_insert_one(): u = User('王五',False,30) db.session.add(u) return 'insert_one'(3) 自定义增删改的基类 进行封装user.py中base类的书写class Base: #添加一条数据 def save(self): try: db.session.add(self) db.session.commit() except: db.session.rollback() #添加多条数据 @staticmethod def save_all(*args): try: db.session.add_all(args) db.session.commit() except: db.session.rollback() #自定义删除基类 def delete(self): try: db.session.delete(self) db.session.commit() except: db.session.rollback()user.py中base类的使用class User(Base,db.Model): __tablename__ = 'user' id = db.Column(db.Integer,primary_key=True) username = db.Column(db.String(12),index=True) sex = db.Column(db.Boolean,default=True) age = db.Column(db.Integer,default=20) icon = db.Column(db.String(40),default='default.jpg') def __init__(self,username,sex=True,age=18,icon='default.jpg'): self.username = username self.sex = sex self.age = age self.icon = icon蓝本文件中的使用#使用自定义的base类 进行添加 自带提交和回滚 @test.route('/self_insert_one/') def self_insert_one(): u = User('兆六',False,20) u.save() return 'insert_one' #添加多条数据 @test.route('/self_insert_many/') def self_insert_many(): sex = [True,False] u1 = User(random.randrange(1000,10000),sex[random.randint(0,1)],random.randint(1,100)) u2 = User(random.randrange(1000,10000),sex[random.randint(0,1)],random.randint(1,100)) User.save_all(u1,u2) return '添加多条' #自定义删除方法的使用 @test.route('/delete/') def delete(): u = User.query.get(2) u.delete() return '删除' #自定义修改方法的使用 @test.route('/update/') def update(): u = User.query.get(2) u.username = '张三' u.save() return '修改'二、数据的操作查询集： 数据查询的集合分类：原始查询集就是没有经过过滤器筛选的集合数据查询集经过过滤器筛选 最终拿到你的数据的集合过滤器 链式调用如： a().b().c()(1) all() 以列表的形式 得到数据查询集使用@test.route('/all/') def show(): dataList = User.query.all() print(dataList) #[<user 1>,<user 2>...] return render_template('show.html',data=dataList)(2) filter() 过滤出你要得到的数据如果没有参数 默认查询所有User.query.filter(User.username=='张',User.sex==True) #查询name为张 并且sex为True@test.route('/filter/') def filter(): data = User.query.filter() #查询所有 data = User.query.filter(User.sex==True) #查询性别为True data = User.query.filter(User.sex==True,User.age==43) #查询性别为True and age为43 print(data) return render_template('show.html',data=data)(3) filter_by() 只支持单条件查询 = #单条件查询 @test.route('/filter_by/') def filter_by(): data = User.query.filter_by() #查询所有 data = User.query.filter_by(sex=True) #查询sex为True的数据 data = User.query.filter_by(sex=True,age=43) #查询sex为True 并且 age为43的数据 print(data) return render_template('show.html', data=data)注意：因为 filyter_by的参数为**kwargs 所以只能使用关键字参数(4) offset(num) 偏移量 偏移几条数据#offset 偏移量 @test.route('/offset/<int:num>/') def offset(num): data = User.query.offset(num) return render_template('show.html', data=data)(5) limit(num) 取出num条数据#limit 偏移量 @test.route('/limit/<int:num>/') def limit(num): data = User.query.limit(num) return render_template('show.html', data=data)(6) offset().limit() 组合使用@test.route('/offsetlimit/<int:num>/') def offsetlimit(num): data = User.query.offset(num).limit(num) return render_template('show.html', data=data)(7) order_by() 排序 升序/降序升序 类名.属性名降序 -类名.属性名#order_by 排序 @test.route('/order_by/') def order_by(): # data = User.query.order_by(User.id) # data = User.query.order_by(-User.id) # data = User.query.filter_by(sex=True).order_by(-User.id) data = User.query.order_by(-User.age).limit(1) return render_template('show.html', data=data)(8) first() 取出第一条数据#取出第一条数据 @test.route('/first/') def first(): data = User.query.order_by(-User.id).first() #== data = User.query.all()[0] print(data) return 'first'(9) get() 根据id查询@test.route('/get/') def myGet(): data = User.query.get(20) print(data) return 'get'注意：如果查询不到 则为None 否则返回对象(10) contains() 包含关系就是模糊查询@test.route('/contains/') def contains(): data = User.query.filter(User.username.contains('1')) return render_template('show.html', data=data)(11) like 模糊查询@test.route('/like/') def like(): data = User.query.filter(User.username.like('%1%')) #包含1 data = User.query.filter(User.username.like('%1')) #1结尾 data = User.query.filter(User.username.like('1%')) #1开头 return render_template('show.html', data=data)(12) startswith endswith 以...开头 以...结尾@test.route('/startend/') def startend(): data = User.query.filter(User.username.startswith('张')) #以张作为开头 data = User.query.filter(User.username.endswith('六')) #以六作为结尾 return render_template('show.html', data=data)(13) 比较运算符__gt__ 大于__ge__ 大于等于__lt__ 小于__le__ 小于等于><>=<===!=data = User.query.filter(User.sex!=True) #查询所有 data = User.query.filter(User.sex!=True,User.age>=30) #查询所有 data = User.query.filter(User.age.__gt__(30)) #查询所有 data = User.query.filter(User.age.__ge__(30)) #查询所有 data = User.query.filter(User.age.__lt__(30)) #查询所有 data = User.query.filter(User.age.__le__(30)) #查询所有 data = User.query.filter(User.age.__gt__(30),User.age.__lt__(70)) #查询所有(14) in_ 和 not in@test.route('/in/') def myIn(): data = User.query.filter(User.id.in_([1,2,3,4])) #in data = User.query.filter(~User.id.in_([1,2,3,4])) #not in return render_template('show.html', data=data)(15) 查询为null的数据@test.route('/null/') def null(): data = User.query.filter(User.username.is_(None)) data = User.query.filter(User.username == None) data = User.query.filter(~User.username.isnot(None))(16) 查询不为null的@test.route('/notnull/') def notnull(): data = User.query.filter(User.username!=None) data = User.query.filter(~User.username.is_(None)) data = User.query.filter(User.username.isnot(None))(17) 逻辑与查询 and_多个条件 逗号隔开from sqlalchemy import and_实例from sqlalchemy import and_ @test.route('/and/') def myAnd(): #查询性别为True 并且名字包含1的数据 data = User.query.filter(User.username.contains('1'),User.sex==True) data = User.query.filter(and_(User.username.contains('1'),User.sex==True)) data = User.query.filter(User.username.contains('1')).filter(User.sex==True) return render_template('show.html', data=data)(18) 逻辑或 or_from sqlalchemy import or_@test.route('/or/') def myOr(): #or的使用 data = User.query.filter(or_(User.username.contains('1')，User.sex==True)) #and 和 or使用 data = User.query.filter(or_(User.username.contains('1'),User.sex==True),User.age>=60) return render_template('show.html', data=data)(19) 逻辑非 not_from sqlalchemy import not_@test.route('/not/') def myNot(): # data = User.query.filter(not_(User.username.contains('1'))) # data = User.query.filter(~(User.username.contains('1'),User.sex==True)) #错误写法 data = User.query.filter(~(User.username.contains('1'))) return render_template('show.html', data=data)注意：not_和～都只能给一个条件进行取反(20) count() 统计个数@test.route('/count/') def count(): data = User.query.filter().count() print(data) return '{}'.format(data)三、文件的迁移(falsk-migrate)(1) 安装pip install flask-migrate(2) 创建迁移对象from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate db = SQLAlchemy(app) #ORM实例化 migrate = Migrate(app,db) #实例化迁移类 from flask_migrate import MigrateCommand manager.add_command('db',MigrateCommand) #将迁移的命令添加到终端运行解析器 通过命令进行迁移(3) 创建迁移目录python3 manage.py db init (4) 生成迁移文件python3 manage.py db migrate(5) 执行迁移文件python3 manage.py db upgrade注意：如果生成迁移文件的时候报错了,将migrations目录中的版本号文件删除掉,将数据库中的迁移文件版本号的表也删除掉。如果在生成迁移文件的时候告诉你，当前模型没有任何的改变，那么可能是没有检测到模型的存在，此时去导入一下再重新生成迁移文件（这个问题不是只有flask有 在django也可能遇到）。
一、flash消息的显示概述： 当用户状态发生改变等等的处理时， 需要给用户显示出提示信息 flash就是实现这个功能的导入： from flask import flash,get_flashed_messagesflash 存数据get_flashed_messages() 获取flash存储的数据实例manage.py#ajax处理登录的视图 @app.route('/do_login/',methods=['POST']) def dologin(): # print(request.args.get('username')) username = request.form.get('username') userpass = request.form.get('userpass') if username == 'zhangsan': if userpass == '123456': flash("登录成功") # flash("登录成功2") # flash("登录成功3") # print(get_flashed_messages()) data = {'code':200} else: data = {'code':400} else: data = {'code':404} return jsonify(data)base.html{% for message in get_flashed_messages() %} × Warning! {{ message }} SS {% endfor %}二、flask-moment 时间显示的扩展库概述： 专门负责时间的显示 可以显示当前时间 可以计算时间的差值附：用法导入：from flask_moment import Momentmanage.pyfrom flask_moment import Moment #时间模块 from datetime import datetime,timedelta #导入时间模块 moment = Moment(app) manager = Manager(app) @app.route('/') def index(): nowtime = datetime.utcnow()+timedelta(seconds=-60) #前60秒的时间 return render_template('index.html',nowtime=nowtime)index.html 首页 {{ nowtime }} {{ moment(nowtime).format('L') }} {{ moment(nowtime).format('LL') }} {{ moment(nowtime).format('LLL') }} {{ moment(nowtime).format('LLLL') }} {{ moment(nowtime).format('YYYY-MM-DD') }} {{ moment(nowtime).fromNow() }} {% endblock %} {% block scripts %} {{ super() }} {{ moment.include_moment() }} #导入moment显示的js代码 {{ moment.locale('zh-CN') }} #格式化中国的时间 {% endblock %}三、文件上传1.原生文件上传(1)简单上传manage.py@ys.route('/form/',methods=['GET','POST']) def form(): # if request.method == 'POST' and request.files.get('photo'): if request.method == 'POST' and 'photo' in request.files: # print(request.files) #获取传递过来的文件 file = request.files.get('photo') #获取文件名称 filename = file.filename #存储上传的路径和名字 file.save(os.path.join(os.getcwd(),'static/upload/'+filename)) return 'ok' return render_template('ysfile/form.html')form.html 文件上传 附：python生成随机图形验证码(2)添加条件判断的上传manage.pyfrom flask import Blueprint,render_template,request,current_app import string,random,os #pip install pillow 处理图片 from PIL import Image ys = Blueprint('ys',__name__) #设置允许上传的文件类型 ALLOWED_FILE = ['jpg','jpeg','gif','png'] """ 文件上传的判断条件 有哪些？ 1.类型 2.大小 3.处理文件名的生成 获取后缀的方法？ 4.上传 5.获取到名称 在模板中展示出来 """ #生成随机文件名字的函数 def random_name(suffix,length=64): #生成大小写字母和数字的字符串 Str = string.ascii_letters+string.digits #循环生成64位长度数字和字母的字符串的随机数+后缀 return ''.join(random.choice(Str) for i in range(length))+'.'+suffix #图片缩放函数 def img_zoom(path,width=200,height=200,prefix='s_'): img = Image.open(path) print(img.size) # 获取图片的宽 高 img.thumbnail((width, height)) # 重新设计尺寸 pathSplit = os.path.split(path) # 将路径拆分成 路径和文件名 newPath = os.path.join(pathSplit[0],prefix+pathSplit[1]) #将前缀进行拼接 img.save(newPath) # 保存图片 覆盖掉原来的图片 @ys.route('/form/',methods=['GET','POST']) def form(): img_name = None if request.method == 'POST' and 'photo' in request.files: file = request.files.get('photo') #拿到上传文件 suffix = file.filename.split('.')[-1] #获取后缀 if suffix in ALLOWED_FILE: #判断是否允许的文件类型 #确保名字唯一性 while True: newName = random_name(suffix) #生成随机名字 path = os.path.join(current_app.config['UPLOADED_FOLDER'], newName) if not os.path.exists(path): break #保存 file.save(path) #将名字传递给模板进行展示 #进行图片的缩放 img_zoom(path) img_name = newName return render_template('ysfile/form.html',img_name=img_name)form.html Title {# 当文件上传失败 查看几点错误原因 methods是否为post input type=file 是否有name名称 是否更改了enctype的值 #} {% if img_name %} {# #} {% endif %} 文件上传 2.使用flask-uploads进行文件上传概述： 在文件上传时，提供了文件过滤和校验的功能导入： from flask_uploads import IMAGES,UploadSet,configure_uploads,patch_request_classmanage.pyfrom flask import Flask,request,render_template from flask_script import Manager from flask_bootstrap import Bootstrap import os from flask_uploads import IMAGES,UploadSet,configure_uploads,patch_request_class app = Flask(__name__) #设置上传文件的大小 配置 写死的 app.config['MAX_CONTENT_LENGTH'] = 1024*1024*64 #64兆 app.config['UPLOADED_FOLDER'] = os.path.join(os.getcwd(),'static/upload') #flask-uploads上传的时候 自动查找存储文件的目录 app.config['UPLOADED_PHOTOS_DEST'] = os.path.join(os.getcwd(),'static/upload') bootstrap = Bootstrap(app) file = UploadSet('photos',IMAGES) #配置文件上传 configure_uploads(app,file) #将app和配置关联到一起 patch_request_class(app,size=None) #使上传文件大小从 app.config['MAX_CONTENT_LENGTH'] 进行获取 manager = Manager(app) @app.route('/') def index(): return 'index' @app.route('/wtfrom/',methods=['GET','POST']) def wtfrom(): img_name = None if request.method == 'POST' and 'photo' in request.files: filename = file.save(request.files.get('photo')) print(filename) img_name = file.url(filename=filename) print(img_name) return render_template('ysfile/form.html',img_name=img_name) from yuanshengfile import ys # from flask_wtf_form import fwf app.register_blueprint(ys) #注册原生文件上传的蓝本 # app.register_blueprint(fwf) #注册flask-wtf文件上传的蓝本 if __name__ == '__main__': manager.run()form.html Title {# 当文件上传失败 查看几点错误原因 methods是否为post input type=file 是否有name名称 是否更改了enctype的值 #} {% if img_name %} {# #} {% endif %} 文件上传 四、flask-wtf flask-uploads flask-bootstrap 表单manage.pyfrom flask import Flask,render_template from flask_bootstrap import Bootstrap from flask_script import Manager from flask_wtf import FlaskForm from flask_wtf.file import FileField,FileRequired,FileAllowed #导入自定义文件上传的表单 所需要的字段和验证器 from wtforms import SubmitField from flask_uploads import UploadSet,IMAGES,patch_request_class,configure_uploads #文件上传扩展库 所需要的 import os,random,string from PIL import Image app = Flask(__name__) app.config['SECRET_KEY'] = 'flask-wtf' #密钥 值随便 app.config['BOOTSTRAP_SERVE_LOCAL'] = True #加载本地bootstrap样式 app.config['MAX_CONTENT_LENGTH'] = 1024*1024*64 #设置上传文件大小 app.config['UPLOADED_PHOTOS_DEST'] = os.path.join(os.getcwd(),'static/upload') #设置上传文件的保存目录 file = UploadSet('photos',IMAGES) #上传文件类型允许的设置 configure_uploads(app,file) #将配置和flask绑定 patch_request_class(app,size=None) #设置上传大小 获取MAX——CONTENT——LENGTH的大小 bootstrap = Bootstrap(app) manager = Manager(app) #配置上传表单 class FileUpload(FlaskForm): photos = FileField('上传头像',validators=[FileRequired(message='文件不能为空'),FileAllowed(file,message='只能上传图片')]) submit = SubmitField('上传') #随机名字 def random_name(suffix,length=32): Str = string.ascii_letters+string.digits return ''.join(random.choice(Str) for i in range(length))+'.'+suffix #图片缩放函数 def img_zoom(path,width=200,height=200,prefix='s_'): img = Image.open(path) print(img.size) # 获取图片的宽 高 img.thumbnail((width, height)) # 重新设计尺寸 pathSplit = os.path.split(path) # 将路径拆分成 路径和文件名 newPath = os.path.join(pathSplit[0],prefix+pathSplit[1]) #将前缀进行拼接 img.save(newPath) # 保存图片 覆盖掉原来的图片 @app.route('/form/',methods=['GET','POST']) def upload(): img_url = None form = FileUpload() if form.validate_on_submit(): photo = form.photos.data #request.files.get('photos') suffix = photo.filename.split('.')[-1] #取出后缀 while True: #确保生成的名字唯一性 filename = random_name(suffix) path = os.path.join(app.config['UPLOADED_PHOTOS_DEST'],filename) if not os.path.exists(path): break #保存图片 并使用生成的随机名字 file.save(photo,name=filename) #进行图片的缩放 img_zoom(path) #进行图片的缩放 img_zoom(path,300,300,'m_') #获取上传图片的url地址 img_url = file.url(filename) return render_template('form.html',form=form,img_url=img_url) if __name__ == '__main__': manager.run()form.html{% extends 'bootstrap/base.html' %} {% block title %} 最终版 文件上传 {% endblock %} {% from 'bootstrap/wtf.html' import quick_form %} {% block content %} {% if img_url %} {% endif %} 文件上传 {{ quick_form(form) }} {% endblock %}五、设置临时的环境变量ubuntu：设置 export 名=值获取 echo $名windwos：设置 set 名=值获取 set名六、发送邮件(flask-mail)manage.pyfrom flask import Flask,render_template from flask_bootstrap import Bootstrap from flask_script import Manager from flask_mail import Mail,Message import os,time app = Flask(__name__) app.config['MAIL_SERVER'] = os.environ.get('MAIL_SERVER','smtp.1000phone.com') app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME','xialigang@1000phone.com') app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD','123456') bootstrap = Bootstrap(app) manager = Manager(app) #发送邮件对象 mail = Mail(app) @app.route('/send_mail/') def send_mail(): msg = Message(subject='账户激活',recipients=['948807313@qq.com'],sender=app.config['MAIL_USERNAME']) msg.html = render_template('send_mail.html') mail.send(message=msg) # time.sleep(2) return '发送邮件' if __name__ == '__main__': manager.run()异步发送 开启线程from flask import Flask,render_template from flask_bootstrap import Bootstrap from flask_script import Manager from flask_mail import Mail,Message import os,time from threading import Thread #导入线程模块 app = Flask(__name__) app.config['MAIL_SERVER'] = os.environ.get('MAIL_SERVER','smtp.1000phone.com') app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME','xialigang@1000phone.com') app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD','123456') bootstrap = Bootstrap(app) manager = Manager(app) #发送邮件对象 mail = Mail(app) def send_mail_async(msg): #管理程序上下文 with app.app_context(): mail.send(message=msg) @app.route('/send_mail/') def send_mail(): msg = Message(subject='账户激活',recipients=['948807313@qq.com'],sender=app.config['MAIL_USERNAME']) msg.html = render_template('send_mail.html') thr = Thread(target=send_mail_async,args=(msg,)) thr.start() #开启线程 # time.sleep(2) return '发送邮件' if __name__ == '__main__': manager.run()