Django-开放静态资源-获取请求携带的数据-pychram连接数据库-修改Django默认数据库-DjangoORM操作...

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

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

关于静态资源访问

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

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

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

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

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

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

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

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

常见的静态文件种类

  • css

  • js

  • iamge (图片)

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

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

如何配置来开启访问权限

默认的 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 放当前网站所有的 图片 文件

禁用浏览器缓存

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

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

django的自动重启机制(热启动)

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

静态文件接口动态解析

如果你的产品经理要让你上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代码

向服务器发送数据

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

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

?username=jason&password=123

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

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

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

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

代码区分请求方式

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 请求!')

获取请求带过来的数据

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

GET、POST

request.POST

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

取数据

request.POST.get('username')  # 虽然value是一一个列表但是默认只取列表最后一个元素
password = request.POST['password']  # --->强烈不建议你使用中括号的形式取值,不存在会直接报错

# 如果想直接把列表全部拿出来 -->  request.POST.getlist('hobby')  # 获取用户爱好、下拉框的选项

request.GET

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

取数据

request.GET.get('username')  # 虽然value是一一个列表但是默认只取列表最后一个元素
# 如果没有 get 请求携带的数据,就是一个空字典

password = request.GET['password']  #  --->强烈不建议你使用中括号的形式取值,不存在会直接报错

# 如果想直接把列表全部拿出来 -->  request.GET.getlist('hobby')  # 获取用户爱好、下拉框的选项

pycharm 图形化工具连接数据库

准备工作,安装插件

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

配置连接信息

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

不然 Test Connection 可能会报错

图形页面基本操作

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

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

不显示数据表?

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

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

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

在 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'
    }
}

... 其他配置信息

指定数据库“软件”?

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

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

import pymysql

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

django ORM

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

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

在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

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

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

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

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

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

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

简便写法

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

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 呢?)

表字段的增删改

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

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

增加表字段

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

1.给新增的字段设置默认值
    addr = models.CharField(max_length=32,default='China')  # default该字段默认值

2.给新增的字段设置成可以为空
    age = models.IntegerField(null=True)  # 该字段允许为空

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

删除表字段

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

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

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

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

改字段

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

数据的增删改查(ORM)

导入 models 里面的表

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

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

查记录

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

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

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')

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

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

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

app文件下的

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

项目同名文件下的

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

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

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

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

项目根目录的

static  静态资源文件夹,要记得改配置(settings.py、html引入的时候用static文件路径动态解析)

templates  模版文件夹,要记得配置(settings.py)

大多通过 manage.py 执行 django 的命令
    --> 这个文件专门用来读取命令行命令,并作出处理
我来评几句
登录后评论

已发表评论数()

相关站点

热门文章