zoukankan      html  css  js  c++  java
  • Django

    django项目就类似于一所大学,各个app 就相当于二级学院

    以登录功能为例走一个django项目(今日内容 引子)

    1|0关于静态资源访问

     

    你可能会发现,在我们目前的 django 项目中的 html 模板中链入的 css 、js (这里只服务器本地的,CDN等除外)明明路径是对的,请求得到的却是 404 资源不存在

    1|1为什么要配置静态文件才能获取静态资源


    用户可以访问的资源,都在 url 中

    ​ 只有 url 中开设(配置)相关的资源你才能访问到(不然就可以根据路径把网站源码都拿过去了)

    ​ 后端资源一般都需要手动指定是否需要暴露给用户

    配置完之后也只有输入完整的文件路径才能访问到(也相对是一种保护措施)

    对于前端已经写好了的文件,我们只是拿过来使用,那么这些文件都可以称之为 “静态文件

    html文件默认全部放在 templates 文件夹下(并且,如果是命令行创建的项目,并不会自带 templates 文件夹,自己创建的就需要去配置文件里配置)

    1|2常见的静态文件种类


    • css

    • js

    • iamge (图片)

    • bootstrap、fontawesome等前端框架,已经写好了的

      ​ bootstrap-3.3.7-dist,bootstrap 是依赖于 jquery的,所以在导bootstrap 之前要先导入 jquery

    1|3如何配置来开启访问权限


    默认的 django 项目 是没有 static 这个文件的,需要自己手动创建 static 文件夹,然后需要去 settings.py 文件配置 static 静态资源相关

    # ... 差不多在 settings.py 文件的最下面 STATIC_URL = '/static/' # 接口前缀(跟请求路径相关) # 只要你想访问静态文件中的资源,路径就必须以 /static/ 开头 # STATIC_URL = '/xxx/' # 引用静态文件资源的地方要改成 /xxx/.... # 下面这个是要手动配置的,手动将所有的静态资源文件暴露给用户 STATICFILES_DIRS = [ # 跟实际文件的查找位置相关 # 这里可以配置很多个,就类似于操作系统环境变量的查找,依次去文件夹里找 os.path.join(BASE_DIR, "static"), # 真正的文件夹路径 ]

    创建完 static文件夹后,一般还会再在里面手动创建三个文件夹

    • css 放当前网站所有的 样式 文件(自己写的)
    • js 放当前网站所有的 js 文件(自己写的)
    • image 放当前网站所有的 图片 文件

    1|4禁用浏览器缓存


    写 django 项目最好禁用掉浏览器缓存,不然可能写的代码页面上缓存看不到效果、变化(资源加载地址等等)

    要开着 F12开发者工具查看 *****

    1|5django的自动重启机制(热启动)


    实时监测文件代码变化,只要有变化,就会自动重启,可能代码还没有写完就会自动报错(如果有语法错误可能不会自动重启,遇到逻辑错误就会重启)

    1|6静态文件接口动态解析


    如果你的产品经理要让你上1000个静态资源的前缀改了,再改回来,总之就是改来改去,怎么办?

    备注:这个一般是结合 static 静态文件配置来用的

    使用静态文件接口动态解析

    ...html代码(这一块一般在 head 标签里引用) {% load static %} <-- 开启静态文件接口动态解析 --> <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> ...html代码

    2|0向服务器发送数据


    2|1利用 form 表单默认的 get 请求携带


    form 表单提交方式默认是 get 请求,携带数据的方式是 url 问号后面跟数据(浏览器地址栏直接拼接也是一样的,本质都是发送一个请求过去,数据都封装成了请求的数据格式)

    ?username=jason&password=123

    2|2form 表单改用 post 请求提交数据


    1. 把html模版中 form 表单的 method 改成 post(method=‘post’)
    2. 去 settings.py 里 把 CSRF 这个中间件禁用掉

    2|3回顾:action提交地址的三种写法


    • 不写的情况下 默认往当前地址提交(url)
    • 还可以写后缀/index/ (django项目常用这种)
    • 还可以写全路径

    2|4代码区分请求方式


    request.method 能够获取前端请求方式(并且是全大写的字符串 POST、GET)

    def test_request_way(request): print(request.method, type(request.method)) # GET <class 'str'> # 直接浏览器敲 http://127.0.0.1:8000/test_request_way/ 的方绘制 return HttpResponse('alallala')

    推荐写法

    可以根据这个来判断请求方式,对于不同的请求方式作出不同的处理

    def del_user(request): if request. method == 'POST': # post 请求的逻辑处理 return HttpResponse('这是一个 POST 请求!') # get 请求的逻辑处理(如果是 post,上面就已经return 了,不会执行到这里) return HttpResponse('这是一个 GET 请求!')

    3|0获取请求带过来的数据


    WSGI帮忙封装了 request 等,也经过了 Django后端,才有了request 这个对象(请求相关内容 全在 environ 里面)

    GET、POST

    3|1request.POST


    获取前端表单 POST 提交的所有数据(就类似于一个大字典)

    取数据

    request.POST.get('username') # 虽然value是一一个列表但是默认只取列表最后一个元素 password = request.POST['password'] # --->强烈不建议你使用中括号的形式取值,不存在会直接报错 # 如果想直接把列表全部拿出来 --> request.POST.getlist('hobby') # 获取用户爱好、下拉框的选项

    3|2request.GET


    获取前端 GET 提交的所有数据(就类似于一个大字典)

    取数据

    request.GET.get('username') # 虽然value是一一个列表但是默认只取列表最后一个元素 # 如果没有 get 请求携带的数据,就是一个空字典 password = request.GET['password'] # --->强烈不建议你使用中括号的形式取值,不存在会直接报错 # 如果想直接把列表全部拿出来 --> request.GET.getlist('hobby') # 获取用户爱好、下拉框的选项

    4|0pycharm 图形化工具连接数据库


    4|1准备工作,安装插件


    然后安装一下插件( downloads...)

    4|2配置连接信息


    一定要注意选择那个 MySQL for 5.1(mysql 版本不高的时候),就两个选项反正不行换一个试试嘛

    不然 Test Connection 可能会报错

    4|3图形页面基本操作


    不是重点,鼠标悬浮上去都有提示,自己看吧。。。

    过滤多余的字符编码之类的?

    不显示数据表?

    5|0修改 django 项目配置(应用mysql)


    django 默认使用的是自带的 sqlite 数据库(一种小型的做测试用的数据库)

    要让 django 项目应用其他数据库(mysql),需要做如下两步配置

    5|1在 settings.py 里面配置数据库连接信息


    配置的时候 key 必须全大写

    ... 省略一堆 配置信息 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 直接把原来的 sqlite3 改成 mysql # mysql 相关配置信息 'HOST': '127.0.0.1', 'PORT': 3306, 'USER': 'root', 'PASSWORD': '000000', 'NAME': 'day51', # 数据库名 'CHARSET': 'utf8' } } ... 其他配置信息

    5|2指定数据库“软件”?


    项目名下的 __init__.py 文件或者是应用名文件下的 __init__.py 文件下加入一段代码(指定使用的数据库软件?

    django 默认用 MySQLdb 连数据库的(需要自己引入,MySQLdb 比较老了,兼容性也不太好,所以要自己指定)

    import pymysql pymysql.install_as_MySQLdb() # 把 pymysql 装成 MySQLdb 或者 取别名成 MySQLdb ?

    6|0django ORM


    跟之前 手撸ORM 核心思路一样,只不过这个更加强大而已(强大不知道多少倍去了)

    关系映射: 表 ---> 类 一条条记录 ---> 对象 字段对应的值 ---> 对象的属性

    6|1在models.py 里创表模型类


    django 会默认给你的表创建一个名为 id 的主键字段,所以可以不写这个 id 主键

    ​ 但如果不是名为 id (是 s_id) 那还是得自己写,一旦你已经指定了主键字段 那么 django 就不会主动再给你创建了

    注意点

    • CharField 必须指定 max_length 参数,不指定会报错
    • 字段修改的注意点(下面有展开介绍)
    • 其他注意点 ...

    app01/models.py

    from django.db import models # Create your models here. class User(models.Model): # 将id字段设置为User表主键字段 在django orm中 你可以不写主键字典 django会默认给你的表创建一个名为id的主键字段 # id = models.AutoField(primary_key=True) # 一旦你自己指定了主键字段 那么django就不会自动再帮你创建了 username = models.CharField(max_length=32) # username varchar(32) CharField必须要指定max_length参数 # password = models.IntegerField() # password int password = models.CharField(max_length=64) # addr = models.CharField(max_length=32,default='China') # default该字段默认值 # age = models.IntegerField(null=True) # 该字段允许为空 def __str__(self): # 重写了对象的 __str__ 方法,这样后面打印对象的时候就是这个字符串了 return '我是user表中的对象:%s' % self.username

    6|2创建表、修改表--数据库迁移命令(同步到数据库)


    python3 manage.py makemigrations 记录数据库迁移

    仅仅是在 migrations 文件夹中 记录数据库的修改,并不会直接操作数据库

    ​ 在当前 app 的 migration 文件夹下会多出一个 .py 文件(记录数据库更改)

    python3 manage.py migrate 将数据库修改记录(migrations 中的记录)真正同步到数据库

    ​ 要等一会儿(第一次执行数据库迁移(还是同步啊?没试)命令会自动创建一堆表(django需要依赖的表),后续就是更新多出来的这几张表的记录了)

    6|3简便写法


    这里写会有提示,但还是要会自己完整写, 万一面试让手写呢?

    makemigrations 记录数据库迁移

    会产生类似如下的文件

    app01/migrations/0008_auto_20190916_2358.py

    # -*- coding: utf-8 -*- # Generated by Django 1.11.11 on 2019-09-16 23:58 from __future__ import unicode_literals from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('app01', '0007_remove_user_addr'), ] operations = [ migrations.AlterField( model_name='user', name='password', field=models.IntegerField(), ), ]

    首次创建表时(写模型类时)

    app01/migrations/0001_initial.py

    # -*- coding: utf-8 -*- # Generated by Django 1.11.11 on 2019-09-16 04:29 from __future__ import unicode_literals from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='User', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('username', models.CharField(max_length=32)), ('password', models.IntegerField()), ], ), ]

    migrate 同步到数据库

    新增或者更新新出的那些 表的记录

    注意

    只要动了models 中跟数据库相关的代码,就必须重新执行上面的两条命令,缺一不可

    特殊点--表名会自动加上模块的前缀

    自动加前缀,可以方便协同开发,解耦合,合在一起就行了(那大家都创 app01 呢?)

    6|4表字段的增删改


    改完后必须执行数据库迁移的那两条命令

    而且一般也不会让你去动表结构,表是在开发之前就要定下来的!

    增加表字段

    当表里已经有记录时,后续还要想添加字段,需要指定默认值 或者 允许新增字段为空

    1.给新增的字段设置默认值 addr = models.CharField(max_length=32,default='China') # default该字段默认值 2.给新增的字段设置成可以为空 age = models.IntegerField(null=True) # 该字段允许为空

    当没有记录 或者 表还未被创建时,则不会有上述问题

    删除表字段

    1. 直接在表模型类里 加注释 / 删除
    2. 重新执行两条命令即可

    强调!:执行完之后,表中该字段所对应的所有数据全部清空

    ​ ---》 没事儿别瞎注释!或者删除(这不仅仅是python代码,还牵连着数据库

    并且一般也不会真正意义上的删除(除非设计不合理)

    改字段

    结合新增字段和删除字段(小推测,未实践)

    6|5数据的增删改查(ORM)


    导入 models 里面的表

    查数据(跟前面手动封装的一样)

    from app01 import models # ORM操作需要使用 models 类中的名字

    查记录

    get(拿到一个对象,对象没有会报错,不推荐)

    models.User.objects.get(username=username, 条件2)

    1568616896305

    filter(拿到列表,可以放多个参数(条件))

    models.User.objects.filter(username=username, password=password, 条件3)

    返回的是一个列表(QuerySet),里面放的才是一个个的对象

    当查询条件不存在时,不会报错,只会返回一个空列表

    filter 括号内支持写多个参数,并且参数之间是 and 关系

    print(res.query) 可以打印查询语句(只有 QuerySet 对象才可以直接查看内部对应的 sql 语句) orm 暂时做个了解,后面有详解

    QuerySet 对象你可以把它当成列表操作,索引也可以用索引取,但是不推荐这么做( QuerySet 只支持整数索引,不支持负数) 还支持切片操作(也不支持负数,切出来的结果还是一个 QuerySet 对象)

    QuerySet 封装的方法(个别)

    ​ ..... filter().first() 拿列表中的第一个对象

    ​ 空列表不会报错

    不推荐你使用索引取值,一旦没有任何数据,再索引取值会报错,但是如果用 .first() 虽然内部也是按索引取值,但是没有数据, 也不会报错,返回的是None

    models.User.objects.filter(username=username).first()

    少了 .first() 会报这个错

    all (拿到所有的)

    models.User.objects.all() 直接拿到 User 表模型类的所有数据,结果是列表套对象

    增加记录

    新增对象的两种方式

    create 方法

    models.User.objects.create(username=username, password=password)

    create方法能够新增数据并且有一个返回值
    返回值就是新增的数据对象本身

    实例化对象调用 .save()

    ...省略一堆代码 user_obj = models.User(username=username, password=password) user_obj.save() ...省略一堆代码

    删除记录

    models.User.objects.filter(条件).delete()

    html中利用 a 标签的 href 把参数发过去(加一个删除功能)

    models.User.objects.filter(条件).delete()

    更新记录

    无论是什么请求,request.GET 都能拿到 url 里携带的参数

    总体思路

    先传过来id 获取记录 重定向到页面让用户修改 获取用户提交过来的新信息,更新数据,重定向到列表页

    .filter(条件).update(username=username, password=password) 批量更新

    models.User.objects.filter(id=edit_id).update(username=username,password=password)

    .filter 拿到的是一个列表,所以 .filter 的操作 都是批量操作(如果 .filter 结果列表中有多个数据,那么会一次性全部修改,就类似于 for循环一个个修改)

    直接 对象.改属性 .save保存

    edit_obj.username = username edit_obj.password = password edit_obj.save()

    不推荐!--> 会从头到尾将所有的字段修改一遍(遍历身上的属性),效率极低

    用户信息增删改查

    先通过 orm 展示所有的数据到前端 all() 拿所有数据 模板语法 for 循环 添加新增按钮,能够实现用户的新增操作 利用 a 标签的 href 直接触发后端的逻辑 添加编辑、删除按钮 编辑 删除 利用 get 请求携带参数的特点,在url的后面跟上对应数据的id值 request.GET.get() 如果是编辑 重新渲染一个页面,将编辑对象传递到前端,让用户修改 如果是删除 直接利用 filter(条件).delete() 重定向定位不同的页面

    与ORM相关的代码实现

    app01/views.py

    from django.shortcuts import render, HttpResponse, redirect from app01 import models # Create your views here. def login(request): # 视图函数针对不同的请求方式 应该有不同的处理逻辑 # if request.method == 'GET': # print('收到了') # print(request.method) # 能够获取前端请求方式 并且是全大写的字符串 # print(type(request.method)) # return render(request,'login.html') # elif request.method == 'POST': # # 获取用户输入 做相应的逻辑判断 # return HttpResponse("拿到了 老弟") if request.method == 'POST': print(request.POST) # 获取前端post请求提交过来的数据 就把它当成一个大字典即可 # <QueryDict: {'username': ['jason', 'zekai'], 'password': ['123']}> username = request.POST.get('username') # 默认取列表最后一个元素 # password = request.POST['password'] # 不推荐 使用 password = request.POST.get('password') # hobby = request.POST.getlist('hobby') # print(username,password,hobby) # print(type(username),type(password),type(hobby)) # 利用orm从数据库获取数据 校验 # 1.查询数据 # 1.1 get() # user_obj = models.User.objects.get(username=username) # select * from user where username='jason' # """ # get方法 能够直接拿到数据对象本身 但是 当查询条件不存在的时候 会直接报错 所有不推荐使用 # """ # print(user_obj) # print(user_obj.username) # print(user_obj.password) # 1.2 filter() # res = models.User.objects.filter(username=username,password=password) """ filter查询出来的结果是一个"列表 列表内放的才是一个个的数据对象本身" 当查询条件不存在的时候 不会报错 只会返回一个空列表 filter括号内 支持写多个参数 并且参数与参数之间是and的关系 """ # print(res.query) # 只有querySet对象才可以直接点query查看年内部对应的sql语句 # 1.filter拿到的结果就是一个querySet对象(你现在只需要知道filter拿到的结果就能够点query查看sql语句) """ SELECT `app01_user`.`id`, `app01_user`.`username`, `app01_user`.`password` FROM `app01_user` WHERE (`app01_user`.`username` = jason AND `app01_user`.`password` = 123) """ # print(res) # user_obj = res[0:2] """ querySet对象 你可以吧它当做列表操作 取值也可以通过索引取(querySet只支持正数索引 不支持负数) 还支持切片操作(切出来的结果还是一个querySet对象) 但是不推荐你这么做 """ user_obj = models.User.objects.filter(username=username).first() # 拿列表中第一个数据对象 """ 不推荐你使用索引取值 原因在于一旦没有任何数据 再索引取值会报错 但是如果用first虽然内部也是按照索引取值 但是没有数据 也不会报错 返回的是None """ # print(user_obj,user_obj.username,user_obj.password) if user_obj: if user_obj.password == password: return redirect('http://www.xiaohuar.com') return HttpResponse('用户不存在 ') print(request.GET) # 如果没有get请求携带的数据 就是一个空字典 print(request.GET.get('username')) print(request.GET.getlist('hobby')) return render(request, 'login.html') """ http://127.0.0.1:8000/static/bootstrap-3.3.7-dist/css/bootstrap.min.css """ def reg(request): if request.method == 'POST': username = request.POST.get("username") password = request.POST.get('password') # orm插入数据 # 1.create() # res = models.User.objects.create(username=username,password=password) # insert into user(username,password) values(username,password) # """ # create方法能够新增数据 并且有一个返回值 # 返回值就是新增的数据对象本身 # """ # print(res) # print(res.username) # print(res.password) # 2.利用对象 user_obj = models.User(username=username, password=password) user_obj.save() return render(request, 'reg.html') def user_list(request): # 将user表中的数据全部查出 data = models.User.objects.all() # select * from user """ 拿到的也是一个querySet对象 """ print(data.query) return render(request, 'userlist.html', {'user_list': data}) def del_user(request): # 根据用户想要删除的数据的id值 取数据库中删除数据 # 获取到id值 delete_id = request.GET.get('id') # 拿着id去数据库中删除 models.User.objects.filter(id=delete_id).delete() # delete from user where id = delete_id; return redirect('/userlist/') def update_user(request): # 编辑 是基于已经存在了的数据 进行一个修改 # 逻辑:获取用户想要修改的数据的主键值 然后去数据库修改数据 edit_id = request.GET.get('id') # 给用户将数据查出来 展示到页面上 让用户自己修改 edit_obj = models.User.objects.filter(id=edit_id).first() # 将编辑对象传递给前端页面 if request.method == 'POST': # 不要关系思维 post请求中也是获取get请求携带的参数 username = request.POST.get('username') password = request.POST.get('password') # 更新数据 # 方式1: # models.User.objects.filter(id=edit_id).update(username=username,password=password) # update user set username = username,password = password where id = edit_id """ filter拿到是一个列表 filter操作其实都是批量操作 如果filter结果列表中有多个数据 那么会一次性全部修改 类似于for循环一个个修改 """ # 方式二(不推荐使用) edit_obj.username = username edit_obj.password = password edit_obj.save() """ 第二种方式会从头到尾将所有的字段全部修改一遍 效率极低 """ return redirect('/userlist/') return render(request, 'update_user.html', {"edit_obj": edit_obj}) def test_request_way(request): print(request.method, type(request.method)) # GET <class 'str'> return HttpResponse('alallala')

    7|0代码书写位置--个人小总结(待补充)


    --> 暨 django 目录结构再解读

    为了防止后期搞混,不知道代码往哪写,所以最好还是把,每个文件写在哪的搞清楚(app 里面还是项目同名文件夹下?)

    7|1app文件下的


    views.py 视图函数/类 一般都是分应用(某个方面)来对应功能(视图函数)的 models.py 数据库模型类,一般还会给模型类加上app的前缀(django设计的是可以分开开发,最后合并,故这里这样做能保证数据表名不重复(那app名字一样呢...))

    7|2项目同名文件下的


    urls.py 路由配置 settings.py django暴露给用户可以配置的配置信息,这里包含了 app 注册、templates 路径配置、static 静态资源路径配置等

    7|3app 和 项目同名目录 都可以放的


    单独拎出来可能记得更深点吧

    __init__.py 前面指定数据库软件的 import pymysql pymysql.install_as_MySQLdb()

    7|4项目根目录的


    static 静态资源文件夹,要记得改配置(settings.py、html引入的时候用static文件路径动态解析) templates 模版文件夹,要记得配置(settings.py) 大多通过 manage.py 执行 django 的命令 --> 这个文件专门用来读取命令行命令,并作出处理
  • 相关阅读:
    RHEL7挂载ISO做本地yum
    服务器虚拟化架构突出优势
    国内公共DNS
    世界上最小的发行版之一Tiny Core
    VMware v12.1.1 专业版以及永久密钥
    Webbench网站压力测试
    Web.xml配置详解之context-param
    SpringMvc自动代理
    SpringMvc aop before
    SpringMvc 面向切面1
  • 原文地址:https://www.cnblogs.com/wkq0220/p/11531398.html
Copyright © 2011-2022 走看看