Django
Django项目是一个python定制框架,采用了MVT的框架模式,即模型M,视图V和模板T
本质还是MVC(Models、Views、Controller)
Django项目的创建
-
命令行式
#1.cmd >>django-admin startproject project_name #2.切换到项目文件夹下 #>>python2 manage.py runserver 127.0.0.1:8000(可指定ip地址) >>python3 manage.py runserver #3.创建应用(django支持多应用开发) >>python3 manage.py startapp app_name ''' 注意: 1.不会自动创建templates文件夹 2.配置文件中不会自动书写templates文件路径 '''
Django中的app
Django是一个以开发app为主要功能的web框架
一个app是一套Django功能的集合,通常包括模型和视图,按python的包结构的方式存在
Django为app提供了前期的环境配置
*创建好的app需要在Django配置文件中注册方可生效
Django框架的分层
Django框架就是为了开发app,而app的工作过程本质就是根据不同的请求返回不同的数据
Django框架将工作过程分为四层:
- 路由层 urls.py 根据不同的地址执行不同的视图函数u
- 视图层 views.py 定义处理业务逻辑的视图函数
- 模型层 models.py 和数据库交互
- 模板层 templates.py 存储返回给浏览器的html文件
请求生命周期
Django文件功能
Django项目名(根目录)
项目同名的文件夹
settings.py 暴露给用户可以配置的配置文件
urls.py 路由和视图函数的对应关系
manage.py
Django的入口文件
应用名文件夹
migrations文件夹 所有数据库的相关操作记录
admin.py Django-admin后台管理
apps.py 注册app使用
models.py 存放数据库所有有关的模型类
tests.py 测试文件
views.py 处理业务逻辑的视图函数
基本操作
#HttpRespnonse 返回字符串
def httpresp(request):
return HttpRespnonse('这是一个字符串')
#render 返回html文件,可以给html页面传值
def ren(request):
user_dic = {'username':'slk'}
return render(request,'login.html',{'user_info':user_dic})
#redirect 重定向,可以是本网站的路径后缀,也可以是全路径
def home(request):
return redirect('https://baidu,com')
retur redirect('/add_user/') #如果是本网站路径后缀要加斜杠
注意事项
前期配置相关
-
静态文件配置
-
默认情况下,所有的html文件都是放在templates文件夹内
-
静态文件是指网站所用到的提前写好的css、js、第三方的前端模块以及图片等静态资源
-
默认情况下,网站所用到的静态文件资源全部放在static文件夹(需要手动创建)下,static文件夹下可以在细分css文件夹、js文件夹、font文件夹、img文件夹、Bootstrap文件夹以及fontawesome文件夹等
-
路径配置
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ]
-
静态文件夹的动态绑定
#在html的py文件中 {% load static %} <link rel="stylesheet" href="{% static 'css文件相对路径' %}"> <script src="{% static 'js文件相对路径' %}"></script>
-
-
前期在向后端提交post请求出现403,需要在配置文件中注释一行内容
# 中间件 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', ]
-
连接数据库
Django自带SQLite
在右侧点击Database;第一次连接某个数据库时,需要下载驱动
Django只会帮你建表,数据库需要手动创建,一个项目用一个数据库#配置文件 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 指定数据库类型 'NAME': 'day49', # 指定库的名字 'USER':'root', # 注意 键必须是全大写 'PASSWORD':'123qwe', 'HOST':'127.0.0.1', 'PORT':3306, 'CHARSET':'utf8' } } #更改连接模块 #在项目名下的__init__.py 或 应用名下的__init__.py 中 import pymysql pymysql.install_as_MySQLdb()
-
orm 对象关系映射 缺点:封装程度太高,效率偏低;一个项目对应一个数据库
-
取消django自动浏览器加斜杠的功能:
#settings APPEND_SLASH = False
数据库相关
-
夺命13条
-
# all() 查询所有 返回Queryset对象 res = models.Table.objects.all()
-
# filter() 筛选 相当于sql中的where关键字 res = models.Table.objects.filter(pk=1,)
-
# get() 筛选 获取到的是对象本身 条件不存在直接报错 res = models.Table.objects.get(title='西游记',)
-
# first() 取queryset中的第一个数据对象 res = models.Books.objects.filter(title='西游记').first()
-
# last() 取queryset中的最后一个数据对象 res = models.Books.objects.filter(title='西游记').last()
-
# count() 统计数据的个数 数字 num = models.Books.objects.count() print(type(num))
-
# values() 获取数据对象中指定的字段的值 返回queryset对象 列表套字典 res = models.Books.objects.values('title','price') print(res) # <QuerySet [{'title': '三国演义', 'price': Decimal('222.66')}, {'title': '红楼梦', 'price': Decimal('888.99')}, {'title': '西游记', 'price': Decimal('444.66')}, {'title': '西游记', 'price': Decimal('666.22')}]>
-
# values_list() 获取数据对象中指定的字段的值 返回queryset对象 列表套元祖 res = models.Books.objects.values_list('title','price') print(res) #<QuerySet [('三国演义', Decimal('222.66')), ('红楼梦', Decimal('888.99')), ('西游记', Decimal('444.66')), ('西游记', Decimal('666.22'))]>
-
# order_by() 按照指定的字段排序 res = models.Books.objects.order_by('price') # 默认是升序 res1 = models.Books.objects.all().order_by('price') # 默认是升序 两者等价 下面的方式 语义更明确 # 降序 字段前面加负号 res1 = models.Books.objects.all().order_by('-price') print(res1)
-
# reverse() 颠倒顺序 前提是跌倒的对象必须有顺序(提前排序之后才能跌倒) res = models.Books.objects.all() res1 = models.Books.objects.all().reverse() res2 = models.Books.objects.all().order_by('price') res3 = models.Books.objects.all().order_by('price').reverse() print(res2,res3)
-
# exclude() 排除什么什么之外 queryset对象 res = models.Books.objects.all().exclude(title='三国演义') print(res) <QuerySet [<Books: 红楼梦>, <Books: 西游记1>, <Books: 西游记2>]>
-
# exists() 判断查询结果是否有值 返回结果是一个布尔值 鸡肋 res = models.Books.objects.filter(pk=1).exists() print(res)
-
# distinct() 对查询结果进行去重操作 去重的前提:数据必须是完全想要的情况下 才能够去重(容易忽略主键),多和values()连用 res = models.Books.objects.values('title','price') res = models.Books.objects.values('title','price').distinct() print(res)
-
小结:
-
返回QuerySet对象的方法:
all(),filter(),exclude(),order_by(),reverse(),ditince()
-
特殊的QuerySet:
values 返回列表套字典 values_list 返回列表套元组
-
返回具体对象:
get(),first(),last()
-
返回布尔值:
exists()
-
返回数字:
count()
-
-
urls相关
-
url正则匹配
-
首页地址
url(r'^$', views.home, name='home'),
models相关
-
数据库中已有记录,要新建字段
- 设置默认值,default=xxx
- 允许控制,null=True
- 根据报错提示,给默认值
-
CharField字段,必须要有max_length属性
-
INtegerField字段,默认长度11位
-
与数据库结构相关的修改,必须要有数据库迁移命令,将操作同步到数据库中
>>python manage.py makemigrations >>python manage.py migrate
-
默认帮你定义了id(主键),自定义的是主键AutoField()
-
添加外键
# 一对多 models.ForeignKey(to='表',to_field='字段',to_delete='级联操作') # 默认关联主键字段 #默认级联删除和更新(models.CASCADE),只在应用层生效,在db层(数据库直接操作)RESTRICT(受限制)
# 多对多,建议建在查询频率较高的表中,虚拟字段,在表中看不见,orm会自动创建一张关系表 models.ManyToManyField(to='表') ************************************************************************************** # through参数 可以来自定义的多对多关系的第三张表 # Artical表 tags = models.ManyToManyField( to='Tag',through='Article2Tag', through_fields=('article','tags') ) # 自定义的Artical2Tag表 class Article2Tag(models.Model): '''文章to标签表''' article = models.ForeignKey(to='Article') tags = models.ForeignKey(to='Tag')
# 一对一,建议建在查询频率较高的表中 models.OneToOneField(to='表') # 外键+唯一,不推荐 models.FoeignKey(to='表',db_constraint='unique')
-
choice参数
可以明确列出用户的所有选择
先定义好对应关系,在通过choices参数来指定关系
-
auth模块:自动生成的包含各种用户信息的表
from django.contrib import auth
# 没有自定义用户表时 from django.contrib.auth.models import User # 创建普通用户 密码自动加密 User.objects.create_user( username=username, password=password ) # 创建超级用户 需要邮箱数据 User.objects.create_superuser( username=username, password=password, email='123@qq.com' ) # 校验用户 from django.contrib import auth user_obj = auth.authenticate( request, username=username, password=password ) # 保存用户状态 执行了这句话,之后在任意位置就可通过 request.user获得当前登陆的用户对象 auth.login(request,user_obj) #只能使用调用一次? # 判断用户登陆 request.user.is_authenticated() # 校验密码 request.user.check_password(old_password) # 修改密码 request.user.set_password(new_password) request.user.save() #注销用户 没有登陆也不会报错 auth.logout(request)
# 自定义继承user表的用户表,会保留原有的字段 from django.contrib.auth.models import AbstractUser class Userinfo(AbstractUser): '''用户信息表''' phone = models.BigIntegerField(null=True) # auto_now_add会在创建时添加时间,auto_now会在创建和修改时修改时间 register_time = models.DateField(auto_now_add=True) # 一定要注意 还需要去配置文件中配置 # 这么写完之后 之前所有的auth模块功能全都以你写的表为准 AUTH_USER_MODEL = 'app01.Userinfo' # 应用名.表名
views相关
-
获取请求方式
type_of_request = request.method(都是大写)
-
获取请求数据
#如果是a标签中href中携带的数据也用GET #当请求方式是GET时,一般使用render返回页面 name = request.GET.get('name') #当请求方式时POST时,一般使用redirect重定向一个页面 name = request.POST.get('name') #使用get()默认拿到列表的最后一个 request.GET.getlist() request.POST.getlist()
-
数据库操作
#增 new_obj = models.ClassName.objects.create(**kwargs) #删 根据filter查询的结果批量操作 models.ClassName.objects.filter(**kwargs).delete() #改 根据filter查询结果批量操作 models.ClassName.objects.filter(**kwargs).update(key=value) #查,支持切片,但不持支负数切片 obj_list = models.ClassName.objects.filter(**kwargs) obj = obj_list.first() all_obj_list = models.ClassName.objects.all() #等价于 all_obj_list = models.ClassName.objects.filter()
前后端传输数据编码格式
前后端交互是一个数据编码格式,针对不同的数据类型,后端会进行不同的处理
- a标签href参数:get
- form表单:get/post
- ajax:get/post
#获取方式
request.POST
request.GET
request.FILES
#三种格式
urlencoded
formdata
application/json
- form表单默认的编码方式是urlencoded,对应的数据格式username=jason&password=123,Django中会自动解析,并封装到POST中
- form表单发送文件编码格式ContentType: multipart/formdata,针对formdata格式的数据,在浏览器上是无法查看到的;Django后端只要数据满足urlencoded格式,就会自动帮你解析到request.POST中;如果是文件对象,Django也会自动识别并封装到request.FILES中
- form表单无法发送json格式的数据,只能借助ajax
- ajax能发送urlencoded、formdata、application/json三种格式数据;ajaz默认的编码格式是urlencoded,Django后端也是将数据解析到request.POST中
Ajax
Asynchronous(异步) Javascript And XML
ajax可以只刷新页面局部
当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应
Ajax基本语法结构
$.ajax({
url:'',
type:'post',
data:{'i1':$('#d1').val(),},
success:function (data) {
$('#d3').val(data)
}
})
Ajax传输json格式数据
Django后端针对json格式的数据,不会做任何处理,只会放到requset.body中,需要手动处理
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
contentType:'application/json', # 1.注意点1
data:JSON.stringify({'username':'jason','password':'123'}), # 2.注意点2
success:function (data) {
alert(123)
}
})
})
Ajax传输文件数据
借助于内置对象new,该对象既可以携带文件数据,也支持普通的键值对
$('#d1').click(function () {
// 先生成一个内置对象
var MyFormData = new FormData();
// 1. 先添加普通的键值
MyFormData.append('username','jason'); // 添加了一组普通的简直对
MyFormData.append('password','123');
// 2. 添加文件数据
MyFormData.append('myfile',$('#d2')[0].files[0]); // 如何获取input框中文件对象$('#d1')[0].files[0]
$.ajax({
url:'',
type:'post',
data:MyFormData, # 1
// 发送文件必须要指定的两个参数
contentType:false, // 不适用任何编码 MyFormData对象内部自带编码 django后端能够识别 # 2
processData:false, // 不要处理数据 # 3
success:function (data) {
}
})
})
orm相关
-
only
only方法返回的是一个queryset对象,本质上是列表套对象;该对象内只含有only括号内所指定的属性
-
defer
defer返回的是一个queryset对象,本质是列表套对象;该对象只含有除了defer括号内所指定的属性
-
select_related
括号内只能放外键字段,并且外键字段只能是一对一或一对多;
内部是连表操作;
返回的结果是一个queryset,列表套对象;
该数据对象后取当前表中的数据或关联表中的数据,不会再走数据库;
主要耗时在连表操作;
-
prefetch_related
括号内外键字段,类型全部支持;
内部是子查询;
返回结果是queryset,列表套对象;
该数据对象后取当前表中的数据或关联表中的数据,不会再走数据库;
主要耗时在查询次数;
前端js相关
-
获取input框中文件对象
$('#d2')[0].files[0])
-
序列化表单内键值对
{# 自动序列化form表单内键值对 #} $.each($('#myform').serializeArray(), function (index, obj) { MyFormData.append(obj.name, obj.value) });
-
利用内置对象FormData传文件
$('#submit').click(function () { {# FormData既可以传普通键值对,也可传文件对对象 #} let MyFormData = new FormData(); {# 自动序列化form表单内键值对 #} $.each($('#myform').serializeArray(), function (index, obj) { MyFormData.append(obj.name, obj.value) }); MyFormData.append('avatar', $('#mdd')[0].files[0]); console.log($('#mdd')[0].files[0]); $.ajax({ url:'', type:'post', data:MyFormData, {# 发送文件一定要指定两个参数 #} processData:false, contentType:false, success:function (data) { if (data.code == 1000){ window.location.href = data.url }else{ // index是报错字段,obj是数组形式的报错信息 $.each(data.msg, function (index, obj) { /* 上面for循环渲染的input框,foo.auto_id给每个input框添 加'id_fieldname'形式的id #}*/ let targetId = '#id_' + index; {# 当输入有误时,打印错误信息并是对应的输入框变红 #} $(targetId).next().text(obj[0]).parent().addClass('has-error') }) } } }) });
其他
-
django是默认重启的,内有检测机制,实时检测所有文件的变化
-
form表单默认请求方式是get请求,也能携带极小量的数据而且不安全
<a href="http://127.0.0.1:8000/login/?username=jason&password=jason123"></a>
-
web身份校验(cookie、session、token)
- cookie:Cookie指的是浏览器里能永久存储的一种数据,是浏览器实现的一种数据存储功能。Cookie是由服务端生成,发送给浏览器,浏览器把Cookie以key-value的形式保存到某个目录下的文本文件内,下一次请求同一个网站的时候会把该Cookie发送给服务端。由于Cookie是存在客户端上的,所以浏览器加入了一些限制确保Cookie不会被恶意使用,同时不会占据太多的磁盘空间,每个域的Cookie的数量都是有限的
- session:会话。Coookie中存放着一个sessionID,请求时会发送这个sessionID;session因为请求(request对象)而产生;session是一个容器,相当于一个字典,可以存放会话过程中的任何对象;session的创建与使用总是在服务端,浏览器从来没有得到过session对象;session是一种http存储机制,目的是为了武装http提供持久机制
- token:令牌,是用户身份的验证方式。可以在token中包含足够多的信息,以便在后续请求中减少查询数据库的几率;