Django框架学习

一、Ubuntu安装
二、安装mkvirtualenv(解决mkvirtualenv: command not found报错)
  • 1、首先在终端输入以下命令:
    • sudo pip install virtualenv
    • sudo pip install virtualenvwrapper
    • windows下直接安装即可pip install virtualenvwrapper-win
  • 2、然后切换到家目录下,编辑家目录下的 .bashrc 文件
    • cd ~/
    • vim .bashrc
  • 3、接着在.bashrc 文件末尾添加如下两行;然后按esc键,输入:wq保存并退出 .bashrc 文件
    • export WORKON_HOME=~/.environments
    • source /usr/local/bin/virtualenvwrapper.sh
      在这里插入图片描述
  • 4、最后在终端输入如下命令,加载.bashrc文件
    • source ~/.bashrc
  • 5、其他命令扩展了解
# 虚拟环境
mkvirtualenv  # 创建虚拟环境
rmvirtualenv  # 删除虚拟环境
workon  # 进入虚拟环境、查看所有虚拟环境
deactivate  # 退出虚拟环境
三、创建django虚拟化环境
  • 1、首先初始化环境(其中django-env只是环境名称可替换,我这里的python3指的是python3解释器)
    • mkvirtualenv django-env -p python3
  • 2、然后激活虚拟环境
    • workon django-env
  • 3、接着安装django(可指定版本号),(pip install django可能会报错pip._vendor.urllib3.exceptions.ReadTimeoutError),可改为如下命令安装
    • pip install django==1.11.11 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
  • 4、最后输出所有在本地已安装的包,可看到django已安装成功
    • pip freeze
      在这里插入图片描述
  • 5、windows下安装django
    • pip install virtualenvwrapper-win
    • mkvirtualenv MyDjango
    • workon MyDjango
    • pip install django==2.2.4 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
    • django-admin startproject mysite
    • pycharm下配置django的run和debug,且Project_Interpreter也要改为C:\Users\Shirmay\Envs\MyDjango\Scripts
      在这里插入图片描述
      在这里插入图片描述
四、django框架
1、创建django项目的大致流程
  • 首先创建一个项目工程”mysite“:django-admin startproject mysite
    在这里插入图片描述

  • 其次创建一个APP即一个功能"app01":cd mysitepython manage.py startapp app01
    在这里插入图片描述

  • 然后、修改settings.py(配置层)的INSTALLED_APPS列表添加'app01',用于框架可找到app01这个APP,否则找不到
    在这里插入图片描述

  • 接着、修改settings.py(配置层)网页展示为中文,中国时间:LANGUAGE_CODE = 'zh-hans'TIME_ZONE = 'Asia/Shanghai'

  • 接着、创建一个用于放html文件的文件夹"templates":cd mysitemkdir templates

  • 接着、修改setting.py(配置层),配置templates指向路径,'DIRS': [os.path.join(BASE_DIR, 'templates')],
    在这里插入图片描述

  • 代码开始、编写views.py,新建方法;并在对应的urls.py(路由层)添加路由指向views的方法

  • 代码过程、编写models.py,真正创建数据库表并执行建立表,执行命令python manage.py makemigrationspython manage.py migrate

  • 启动项目工程:python manage.py runserver 127.0.0.1:9090 , 查看效果:http://localhost:9090/

  • 服务器上线后DEBUG = False # 上线之后改成False; ALLOWED_HOSTS
    在这里插入图片描述

2、django必会三板斧
  • 首先在urls.py文件添加自己的路由如下图,并导入相关的应用层app
    在这里插入图片描述

  • 然后在app01的views.py里面编写功能:

    • HttpResponse:返回字符串类型的数据
    • render:返回html文件的
    • redirect:重定向路由
      • return redirect(‘https://baidu.com’) # 重定向到指定的网址
      • return redirect(‘/home/’) # 或者重定向到指定的路由
    # views.py
    from django.shortcuts import render, HttpResponse, redirect
    
    
    def home(request):
        return HttpResponse('HOME')
    
    
    def index(request):
        """
        :param request: 请求相关的所有数据对象
        :return:
        """
        user_dict = {'username': 'jason', 'age': 18}
        # return HttpResponse("你好啊")
        # return render(request, 'myfirst.html', {'data': user_dict, 'date':123})   # 自动去templates文件夹帮你查找文件,指定要传递的
        # locals会将所在的名称空间中所有的名字(如key: data,date)全部传递给html页面
        return render(request, 'myfirst.html', locals())  # 自动去tempaltes文件夹下帮你查找html文件;
        # return redirect('https://baidu.com')   # 重定向
        # return redirect('/home/')  
    
3、django静态文件配置(登录功能)
  • (1)我们将html文件默认都放在templates文件夹下,我们将网站所使用的静态文件默认都放在static文件夹下

    • 什么是静态文件:前端已经写好了的, 能够直接调用使用的文件:网站写好的js文件、网站写好的css文件、网站用到的图片文件、第三方前端框架、拿来就可以直接使用的
    • 在浏览器中输入url能够看到对应的资源,是因为后端提前开设了该资源的接口;如果访问不到资源,说明后端没有开设该资源的接口
  • (2)django默认是不会自动帮你创建static文件夹,需要你自己手动创建,一般情况下我们在static文件夹内还会做进一步划分处理,比如再新建js、img、css等文件夹。下载Bootstrap 源码并解压里面的dist文件夹粘贴到static文件夹下,下载jquery.js文件
    在这里插入图片描述

  • (3)如果要使得html文件能够找到静态文件,还需要在settings.py写相关静态配置如下。指定静态文件的令牌为'/static/'时,html文件内导入的link,script等路径开头要与令牌一致,否则无法找到该资源

    #settings.py
    
    # STATIC_URL = '/oooo/'   # 类似于访问静态文件的令牌
    STATIC_URL = '/static/'   # 类似于访问静态文件的令牌,并不是指的路径
    """
    注意:如果你想要访问静态文件,,且令牌如果指定是 '/static/',你就必须以/static/开头,如:
    1、/static/bootstrap-3.3.7-dist/js/bootstrap.min.js;前面这个/static/指定是令牌,而非路径,也就是html里面要引用时填写的
    2、一旦令牌对了,就取列表STATICFILES_DIRS里的文件夹路径从上往下依次查找/bootstrap-3.3.7-dist/js/bootstrap.min.js; 如果都没有找到才会报错
    """
    #静态文件配置
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'static'),
        os.path.join(BASE_DIR, 'static1'),
        os.path.join(BASE_DIR, 'static2'),
    ]
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    <!--    <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>-->
        {% 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>
    </head>
    <body>
    <h1 class="text-center">登陆</h1>
    </body>
    </html>
    

    在这里插入图片描述

  • (4)settings.py随意更换静态文件的令牌如为'/oooo/'时,html文件内导入的link,script等路径开头要与令牌一致,否则无法找到该资源,那html导入的令牌开头可以写成动态的通用模式,如下图{% 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>
    # 静态文件动态令牌解析
        {% load static %}
        <script src="{% static 'bootstrap-3.3.7-dist/js/jquery-3.5.1.min.js' %}"></script>
        <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
        <link rel="stylesheet" href= "{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    
    • http://127.0.0.1:8000/oooo/bootstrap-3.3.7-dist/css/bootstrap.min.css
    • http://127.0.0.1:8000/oooo/a.txt

    在这里插入图片描述

  • (5)问题注意:当你在写django项目的时候 可能会出现后端代码修改了但是前端页面没有变化的情况:

    • ①你在同一个端口开了好几个django项目,一直在跑的其实是第一个django项目;
    • ②浏览器缓存的问题:settings>network>disable cache勾选上
  • (6)form表单默认是get请求数据,通过method可以指定post请求哦

    • http://127.0.0.1:8000/login?username=jason&password=123
    • form表单的action参数:不写:默认朝当前所在的url提交数据;全写:指名道姓;只写后缀:/login/
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    <!--    <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>-->
        {% load static %}
        <script src="{% static 'bootstrap-3.3.7-dist/js/jquery-3.5.1.min.js' %}"></script>
        <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
        <link rel="stylesheet" href= "{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    </head>
    <body>
    <h1 class="text-center">登陆</h1>
    <div class="container">
        <div class="row" >
            <div class="col-md-8 col-mod-offset-2">
                <form action="" method="post">
                    <p>username:<input type="text" name="username" class="form-control"></p>
                    <p>password:<input type="password" name="password" class="form-control"></p>
                    <input type="submit" class="btn btn-success btn-block">
                </form>
            </div>
    
        </div>
    
    </div>
    </body>
    </html>
    

    在这里插入图片描述

    def login(request):
        # 返回一个登陆界面
        """
        get请求和post请求应该有不同的处理机制
        :param request: 请求相关的数据对象, 里面有很多简易的方法
        :return:
        """
        print(request.method)
        if request.method == "POST":
            # 获取前端用户提交的post请求数据(不包含文件)
            username = request.POST.get('username')  # get只会获取列表最后一个元素
            username = request.POST.getList('username')  # get只会获取列表
            return HttpResponse("收到了")
        username = request.GET.get('username')  # get只会获取列表最后一个元素
        username = request.GET.getList('username')  # get只会获取列表
        return render(request, 'login.html')
    
4、pycharm连接数据库mysql
  • (1) pycharm连接mysql,专业版pycharm右侧有Database或者左下方Database或者配置里面Plugins插件搜索安装; 可以充当很多款数据库软件的客户端
    在这里插入图片描述

  • (2) Ubuntu安装mysql过程

    • dpkg -l | grep mysql:查看有无安装mysql
    • apt install mysql-server:安装mysql
    • mysql -u root -p:登录mysql,默认无密码,直接敲回车
    • show databases;:查看当前数据库
    • create database my_db1; :新建数据库my_db1
    • mysql_secure_installation:数据库初始化操作,并设置密码
    • grant all on *.* to root@'%' identified by '123456' with grant option;:注意换成你的mysql密码,我这里是123456
    • flush privileges; :刷新权限
    • systemctl restart mysql:重启mysql
  • (3) 选择mysql数据库,然后先选择Download;
    在这里插入图片描述

  • (4)输入user,password,database,并测试连接;也可以将如下Host里的localhost改成你的ip地址10.0.2.15,通过命令ifconfig -a查询,可得ip(inet 10.0.2.15 );
    在这里插入图片描述

  • (5)pychram直接操作mysql里已建好的表,其中可以新增和删除记录,操作完点击绿色小点即可同步到数据库
    在这里插入图片描述
    在这里插入图片描述

5、django连接数据库mysql
  • (1)修改settings.py,将原有的DATABASES配置注释掉,改为如下格式
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'my_db1',   # 数据库的名字
            'USER': 'root',
            'PASSWORD': '123456',
            'Host': 'localhost',
            'PORT': 3306,
            'CHARSET': 'utf8'
        }
    }
    
  • (2)django默认用的是mysqldb模块链接MySQL,但是该模块的兼容性不好,需要手动改为用pymysql链接;在应用名下的__init__文件中书写如下代码
    import pymysql
    pymysql.install_as_MySQLdb()
    
    在这里插入图片描述
6、djang之ORM
  • ORM:对象关系映射;将类映射成表,对象映射成记录,对象属性映射成记录某个字段对应的值
  • (1)先去models.py文件中书写一个类
    from django.db import models
    
    # Create your models here.
    
    
    class User(models.Model):
        # id int primary_key auto_increment
        id = models.AutoField(primary_key=True, verbose_name="主键")
        # username varchar(32)
        username = models.CharField(max_length=32, verbose_name="用户名")
        """
        CharField必须要指定max_length参数,不写会报错
        verbose_name该参数是所有字段都有的,就是用来对字段的解释
        """
        # password int
        # password = models.IntegerField(verbose_name="密码")
        password = models.CharField(verbose_name="密码", max_length=64)
        # 新增字段
        age = models.IntegerField(verbose_name='年龄', default=0)
        # 注释掉即删除该字段
        # info = models.CharField(max_length=32, verbose_name='个人简介', null=True)
        # hobby = models.CharField(max_length=32, verbose_name='兴趣爱好', default='study')
    
    
    class Author(models.Model):
        # 由于一张表中必须要有一个主键字段,并且一般情况下都叫id字段,
        # 所以orm当你不定义主键id字段的时候,orm会自动帮你创建一个名为id的主键字段
        # username varchar(32)
        username = models.CharField(max_length=32)
        # password int
        password = models.IntegerField()
    
  • (2) teminal下执行数据库迁移命令,只要你修改了models.py中和数据库相关的代码,就必须重新执行下面的两条命令
    • python3 manage.py makemigrations :将操作记录记录到小本本上(migrations文件夹)
    • python3 manage.py migrate:将操作真正同步到数据库中
      在这里插入图片描述
      在这里插入图片描述
  • (3)字段的增删改查
    • 增加:指定字段默认值或者 default=是可以为空null=True
          # 新增字段
          age = models.IntegerField(verbose_name='年龄', default=0)
          info = models.CharField(max_length=32, verbose_name='个人简介', null=True)
          hobby = models.CharField(max_length=32, verbose_name='兴趣爱好', default='study')
      
    • 修改:直接修改代码,然后执行数据库的两条迁移命令
          # password = models.IntegerField(verbose_name="密码")
          password = models.CharField(verbose_name="密码", max_length=64)
      
    • 删除(不要轻易的操作):直接注释对应的字段然后执行数据库迁移命令即可,执行完两条迁移命令后字段对应的数据就没了
       # 注释掉即删除该字段
       # info = models.CharField(max_length=32, verbose_name='个人简介', null=True)
       # hobby = models.CharField(max_length=32, verbose_name='兴趣爱好', default='study')
      
  • (4)数据的增删改查
    • 查:返回列表,支持索引取值,切片操作,但不支持负数索引,filter可以传多个参数,默认是and关系
      # views.py
      user_obj = models.User.objects.filter(username=username).first()
      # select * from user where username='jason';
      # <QuerySet [<User: User object (1)>]> [数据对象1,数据对象2...]
      # user_obj = res[0]
      # print(user_obj)
      # print(user_obj.username)
      # print(user_obj.password)
      
    • 增:两种新增数据的方法
      # 第一种保存数据
      # 直接获取用户数据存入数据库
      res = models.User.objects.create(username=username, password=password)
      # 返回值就是当前被创键的对象本身
      print(res, res.username, res.password)
      # 第二种保存数据
      user_obj = models.User(username=username, password=password)
      user_obj.save()  # 保存数据
      
  • (5)数据的查改删功能实现
    1、查看展示功能:数据库中的数据全部展示到前端, 然后每一个数据两个按钮,一个编辑一个删除
    2、编辑功能:
    	点击编辑按钮后端发送编辑数据的请求
    	"如何告诉后端用户想要编辑哪条数据?"
    		将编辑按钮所在的那一行数据的主键值发送给后端
    		利用url问号后面携带参数的方式
    	后端查询出用户想要编辑的数据对象,展示到前端页面共用户查看和编辑
    	(1)首先获得用户想要编辑的数据的主键值
             <a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">编辑</a>
        (2)后端查询出对应的数据对象展示到前端
              利用input标签的value属性
        (3)提交post请求修改数据
              前期提交post请求csrf先注释掉
    3、删除功能:
    	跟编辑功能逻辑类似
    	删除数据内部其实并不是真正的删除,我们会给数据添加一个标识字段用来表示当前数据是否被删除了,如果数据被删了仅仅只是将字段修改一个状态,如is_delete(0, 1)
    
    # 查看功能
    def userlist(request):
        # 查询出用户表里面所有的数据
        # # 方式一
        # data = models.User.objects.filter()
        # print(data)
        # 方式二
        user_queryset = models.User.objects.all()
        # return render(request, 'userlist.html', {'user_queryset': user_queryset})
        return render(request, 'userlist.html', locals())
    
    # 编辑
    def edit_user(request):
        # 获取url问号后面的参数
        edit_id = request.GET.get('user_id')
        # 查询当前用户想要编辑的数据对象
        edit_obj = models.User.objects.filter(id=edit_id).first()
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            # 去数据库中修改对应的数据内容
            # # 修改数据方式1, 将filter查询出来的列表中的所有对象全部更新,批量操作更新,只修改被修改的字段
            # models.User.objects.filter(id=edit_id).update(username=username, password=password)
            # 修改数据方式2,字段特别多的时候,效率会非常的低(从头到尾将数据的所有字段全部更新一遍,无论该字段是否被修改)
            edit_obj.username = username
            edit_obj.password = password
            edit_obj.save()
            # 跳转到数据展示的页面
            return redirect('/userlist/')
        # 将数据对象展示到页面上
        return render(request, "edit_user.html", locals())
    
    # 删除
    def delete_user(request):
        # 获取用户想要删除的数据id值
        delete_id = request.GET.get('user_id')
        # 直接去数据库中找到对应的数据删除即可, 批量删除
        models.User.objects.filter(id=delete_id).delete()
        # 跳转到数据展示的页面
        return redirect('/userlist/')
    
  • (6)orm如何创建表关系
    • 表与表之间的关系,判断表关系的方法:换位思考(一对多,多对多,多对一)
      from django.db import models
      
      # Create your models here.
      
      
      # 创建表关系 先将基表创建出来 然后再添加外键字段
      class Book(models.Model):
          title = models.CharField(max_length=32)
          # 小数总共八位,小数点后面占两位
          price = models.DecimalField(max_digits=8, decimal_places=2)
          """
          图书和出版社一对多, 并且书是多的一方, 所以外键字段放在书表里面
          如果字段对应的是ForeignKey 那orm会自动在字段后面加_id
          """
          publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)  # 默认是与出版社的主键字段做外键关联
          """
          图书和作者是多对多的关系,外键字段在任意一方均可, 但是推荐你建在查询频率较高的一方
          authors是一个虚拟字段,主要用来告诉orm, 书籍表和作者表是多对多的关系, 让orm自动帮你创建第三张关系表
          """
          authors = models.ManyToManyField(to='Author')
      
      
      class Publish(models.Model):
          name = models.CharField(max_length=32)
          addr = models.CharField(max_length=32)
      
      
      class Author(models.Model):
          name = models.CharField(max_length=32)
          age = models.IntegerField()
          """
          作者与作者详情是一对一的关系,外键字段建在任意一方都可以, 但是推荐你建在查询频率较高的表中
          如果字段对应的是OneToOneField 那orm会自动在字段后面加_id
          """
          author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
      
      
      class AuthorDetail(models.Model):
          phone = models.BigIntegerField()
          addr = models.CharField(max_length=32)
      
7、django请求生命周期流程图
  • 扩展:缓存数据库: 提前已经将你想要的数据准备好了, 你来直接拿就可以,提高效率和响应时间
    在这里插入图片描述
8、django框架各层介绍
(1)路由层:
  • url方法第一个参数是正则表达式,只要第一个参数正则表达式能够匹配到内容,那么就会立刻停止往下匹配,直接执行对应的视图函数
    python urlpatterns = [ url(r'test', views.test), url(r'testadd', views.testadd), # 首页 url(r'^$', views.home), # 尾页 url(r'', views.error), ]
  • 分组:就是给某一段正则表达式用小括号括起来,有名分组无名分组不能混用,同类的可以使用多次
  • 无名分组:就是将括号内正则表达式匹配到的内容当作位置参数传递给后面的视图函数
	url(r'^test/(\d+)/', views.test)    # 无名分组
	
	def test(request, xx):
		print(xx)
		return HttpResponse('test')
  • 有名分组:可以给正则表达式起一个别名,就是将括号内正则表达式匹配到的内容当作关键字参数传递给后面的视图函数
    url(r'^testadd/(?P<year>\d+)/', views.testadd)    # 有名分组
    
    def testadd(request, year):
    	print(year)
    	return HttpResponse('test')
    
  • 反向解析:先给路由与视图函数起一个别名;前端反向解析和后端反向解析
    url(r'^func/', views.func, name="ooo")   
    # 前端反向解析
    	<a href="% url 'ooo' %}"> 111</a>
    # 后端反向解析
    from django.shortcuts import render, HttpResponse, redirect, reverse
    reverse('ooo')
    
  • 无名分组反向解析:先给路由与视图函数起一个别名;前端反向解析和后端反向解析;多了一个位置参数这边是数字,一般情况下放的是数据的主键值,数据的编辑和删除
    url(r'^index/(\d+)/', views.index, name="xxx")   
    # 前端反向解析
    	<a href="% url 'xxx'  123 %}"> 111</a>
    # 后端反向解析
    from django.shortcuts import render, HttpResponse, redirect, reverse
    reverse('xxx', args=(1,))
    # 例子
    def edit(request, edit_id):
    	reverse('xxx', args=(edit_id,))
    
    {%for user_obj in user_queryset%}
        # <a href="/edit_user/?user_id={{ user_obj.id }}">编辑</a>
    	<a href="{% url 'xxx' user_obj.id %}">编辑</a>
    <%endfor%}
    
  • 有名分组反向解析:
	url(r'^index/(?P<year>\d+)/', views.index, name="xxx")   
	# 前端反向解析
		<a href="% url 'xxx'  123 %}"> 111</a>
	# 后端反向解析
	from django.shortcuts import render, HttpResponse, redirect, reverse
	reverse('xxx', args=(1,))
  • 路由分发:django的每一个应用都可以有自己的templates文件夹 urls.py static文件夹,正是基于这个特点,django能够非常好的做到分组开发(每个人只写自己的app),作为组长,只需要将手下书写的app全部拷贝到一个新的django项目中,然后在配置文件里面注册所有的app再利用路由分发的特点将所有的app整合起来。
    • 当一个django项目中的url特别多的时候,总路由urls.py代码非常冗余不好维护,这个时候也可以利用路由分发来减轻总路由的压力
    • 利用路由分发之后,总路由不再干路由与视图函数的直接对应关系,而是做一个分发处理,先识别当前url是属于哪个应用下的,直接分发给对应的应用去处理
    • 总路由url.py
      from django.conf.urls import url, include
      from django.contrib import admin
      
      urlpatterns = [
      	url(r'^admin/', admin.site.urls),
      	# 路由分发, 只要前缀是app01开头,全部交给app01处理      
      	url(r"^app01/", include("app01.urls")),  
      ]
      
    • 子路由:如app01下urls.py,然后浏览器输入http://127.0.0.1:8001/app01/register/
      from django.conf.urls import url
      from app01 import views
      
      urlpatterns = [
          url(r'^register', views.reg),
      ]
      
(2)视图层
  • 三板斧:

    • HttpResponse:返回字符串类型
    • render:返回html页面,并且在返给浏览器之前还可以给html文件传值
    • redirect:重定向
  • JsonResponse,默认字典,列表需要设置safe等于False

    from django.http import JsonResponse
    
    
    def ab_json(request):
        user_dict = {"username": "jason这个", "password": '123', "hobby": "eee"}
        return JsonResponse(user_dict, json_dumps_params={"ensure_ascii": False})
        # ll = [1212, 34, 43443]
        # return JsonResponse(ll, safe=False)
        # # 先转成json格式字符串
        # json_str = json.dumps(user_dict, ensure_ascii=False)
        # # 将该字符串返回
        # return HttpResponse(json_str)
    
  • form表单完成文件上传及后端如何获取:

    • form表单上传文件类型的数据:首先method必须指定成post;enctype必须换成formdata
    def ab_file(request):
        if request.method == 'POST':
            # print(request.POST)  # 只能获取普通的键值对数据,文件不行
            print(request.FILES)
            file_obj = request.FILES.get('file')  # 文件对象
            print(file_obj.name)
            with open(file_obj.name, 'wb') as f:
                for line in file_obj.chunks():
                    f.write(line)
        return render(request, 'fileform.html')
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>上传文件</title>
        {% load static %}
        <script src="{% static 'bootstrap-3.3.7-dist/js/jquery-3.5.1.min.js' %}"></script>
        <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
        <link rel="stylesheet" href= "{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    </head>
    <body>
    <form action="" method="post" enctype="multipart/form-data">
        <p>username:<input type="text" name="username"></p>
        <p>file:<input type="file" name="file"></p>
        <input type="submit">
    </form>
    </body>
    </html>
    
  • FBV与CBV:视图函数可以是函数也可以是类

    • FBV:
      def home(request):
      	return HttpResponse('HOME')
      
    • CBV:
      	# url(r'^login/', views.MyLogin.as_view())   # 路由写法
      from django.views import View
      
      class MyLogin(View):
          def get(self, request):
              return render(request, 'form.html')
          
          def post(self, request):
              return HttpResponse('post方法')
      
(3)模板层
  • 模板语法传值:
    • {{}} :变量相关
    • {%%}:逻辑相关
    • django模板语法的取值,是固定的格式,只能采用”句点符“(既可以点键,也可以点索引,还可以两者混用)
    • 过滤器:类似于是模板语法内置的方法:{{数据|过滤器:参数}}
    • 标签:for循环,if判断, with命名
    # 前端代码不一定非要在前端页面书写,也可以先在后端写好,然后传递给前端页面
    from django.utils.safestring import mark_safe
    	res = mark_safe('<h1>信息</h1>')
    
    <h1>模版语法取值格式</h1>
    <p>{{user_dict}}</p>
    <p>{{user_dict.username}}</p>
    <p>{{user_dict.username.0.info}}</p>
    
    <h1>模版语法过滤器</h1>
    <p>统计长度{{s|length}}</p>
    <p>默认值,第一个参数布尔值是True就展示第一个参数的值否则展示冒号后面的值{{b|default:'啥也不是'}}</p>
    <p>文件大小{{file_size|filesizeformat}}</p>
    <p>日期格式化{{current_time|date:'Y-m-d H:i:s'}}</p>
    <p>切片操作支持步长{{l|slice:'0:4:2'}}</p>
    <p>切取字符(包含三个点){{infor|truncatechars:9}}</p>
    <p>切取单词(不包含三个点, 按空格切){{infor|truncatewords:9}}</p>
    <p>移除特定的字符{{msg|cut:' '}}</p>
    <p>拼接操作{{msg|join: ','}}</p>
    <p>拼接操作(加法){{n|add: 10}}</p>
    <p>转义{{hhh|safe}}</p>
    
    <h1>模版语法变量种类</h1>
    <p>{{func}}</p>
    <p>{{ Myclass }}</p>
    <p>传类名的时候也会自动加括号调用(实例化) {{Myclass}}</p>
    <p>{{ obj }}</p>
    <p>{{ obj.get_self }}</p>
    
    <h1>标签</h1>
    {% for foo in f %}
        <p>{{ forloop }}</p>   {#  {'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 3, 'revcounter0': 2, 'first': True, 'last': False} #}
    	<p>{{ foo }}</p>
    {% endfor %}
    
    {% if b %}
        <p>baby</p>
    <% elif s %>
        <p>ddfee</p>
    <% else %>
        <p>ddf</p>
    {% endif %}
    
    {% with d.hobby.0.info as nb %}
        <p>{{ nb }}</p>
    {% endwith %}
    
  • 模板继承:
    • 1、你自己先选好一个你要想要继承的模板页面{% extends ‘home.html’ %};
    • 2、继承了之后子页面和模板页面长得是一模一样的,你需要在模板页面上提前划定可以被修改的区域{% block content %}模板内容{% endblock %};
    • 3、子页面就可以声明你想要修改哪块划定了的区域{% block content %}子模板内容{% endblock %}
    • 4、一般情况下,模板页面上至少有三块可以被修改的区域,css区域、html区域、js区域;
    • 5、一般情况下:模板的页面上划定的区域越多,那么该模板的扩展性就越高,但如果太多,还不如自己写
    {% extends 'home.html' %}
    {% block content %}
    	<h1>注册页面</h1>
    	<p></p>
    {% endblock %}
    
(4)模型层(ORM)和数据库打交道的
  • 单表查询(增删改查)
    • 测试脚本:在test.py文件按如下方式模拟写
    • 查看内部sql语句的方式:queryset对象才能够点击query查看内部的sql语句
    from django.test import TestCase
    
    # Create your tests here.
    import os
    
    
    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
        import django
        django.setup()
        from app01 import models
        # 增
        res = models.User.objects.create(name='jason', age=18, register_time='2002-12-12')
        import datetime
        ctime = datetime.datetime.now()
        user_obj = models.User(name='egon', age=84, register_time=ctime)
        # 删
        res2 = models.User.objects.filter(pk=2).delete()
        """pk会自动查找当前表的主键字段,指代的就是当前表的主键字段"""
        user_obj2 = models.User.objects.filter(pk=1).first()
        user_obj2.delete()
        # 修改
        models.User.objects.filter(pk=4).update(name="egonDSB")
        user_obj3 = models.User.objects.filter(pk=4)
        user_obj3.name = 'eogil'
        user_obj3.save()
        # 必知必会13条
        """
        1、all() 查询所有数据
        2、filter()  带有过滤条件的查询
        3、get() 直接拿数据对象,条件不存在直接报错
        4、first() 拿queryset里面第一个元素
        5、last()
        6、values() 可以指定获取的数据字段, 列表套字典res =models.User.objects.values('name', 'age')
        7、values_list() 列表套元组 res =models.User.objects.values_list('name', 'age')
        8、distinct() 去重一定是一模一样的数据,如果带有主键那么肯定不一样,在往后的查询中一定不要忽略主键res =models.User.objects.values('name', 'age').distinct()
        9、order_by() 默认升序 res=models.User.objects.order_by('age')
        10、reverse() 反转的前提是,数据已经排序了 res=models.User.objects.order_by('age').reverse()
        11、count() 统计当前数据的个数 res=models.User.objects.count()
        12、exclude() 排除在外 res = models.User.objects.exclude(name='jason')
        13、exists() 是否存在 res = models.User.objects.filter(pk=4).exists()
        """
    
  • 常见的十几种查询方法
  • 神奇的双下划线查询
  • 多表操作(外键字段的增删改查)
  • 跨表查询(重点):子查询、联表查询
五、web框架知识
1、web框架图

在这里插入图片描述

  • 后端是前端与数据库之间的连接桥梁
  • HTTP协议
1、网络协议
	HTTP协议:数据传输是明文,
	HTTPS协议:数据传输是密文, 
	websocket协议:数据传输是密文
2、四大特性
	a. 基于请求响应
	b.基于TCP、IP作用于应用层上的协议
	c.无状态
	d.短/无链接
3、数据格式
	a.请求首行
	b.请求头
	c.请求体
4、响应状态码
	1**
	2**  200
	3**  302
	4**  403  404
	5**  500
2、通过socket简易的web框架
  • 不足之处:http格式数据需要自己处理,只能拿到用户输入的路由,其它数据获取繁琐,没法解决并发的问题
    # noinspection PyInterpreter
    """
    这个是请求相关的所有信息
    b'GET / HTTP/1.1\r\n
    Host: 127.0.0.1:8081\r\n
    Connection: keep-alive\r\n
    Upgrade-Insecure-Requests: 1\r\n
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n
    Sec-Fetch-Site: none\r\n
    Sec-Fetch-Mode: navigate\r\n
    Sec-Fetch-User: ?1\r\n
    Sec-Fetch-Dest: document\r\n
    Accept-Encoding: gzip, deflate, br\r\n
    Accept-Language: zh-CN,zh;q=0.9\r\n
    \r\n'
    
    """
    import socket
    
    
    print("http://127.0.0.1:8081/")
    server = socket.socket()   # TCP  三次握手
    server.bind(('127.0.0.1',  8081))   # IP协议, 一台网协议  arp协议
    server.listen(5)
    
    while True:
        conn, addr = server.accept()
        data = conn.recv(1024)
        conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
        current_path = data.decode('utf-8').split(' ')[1]
        if current_path == '/index':
            # conn.send(b'index hhhhh')
            with open(r"myth.html", 'rb') as f:
                conn.send(f.read())
        else:
            conn.send(b'hello web')
        conn.close()
    
3、通过wsgiref实现的稍微封装的web框架
  • web服务网关接口,请求的时候帮你自动拆分http格式数据并封装成非常方便处理的数据格式;响应走的时候帮你将数据打包成符合http格式
  • 帮助封装了socket代码
  • 帮助处理了http格式的数据(大字典)
    from wsgiref.simple_server import make_server
    # from views import *    # 所有的index,error,等函数功能,再创一个html文件夹
    # from urls import urls      # url与函数对应的关系
    
    
    def error(env):
        return "404 err"
    
    
    def index(env):
        return "inedex"
    
    import datetime
    def get_time(env):
    	current_time = datetime.datetime.now().strftime('%Y-%m-%d %X')
    	# 如何将后端获取的数据"传递"给html文件?
        with open(r"mytime.html", "r", encoding="utf-8") as f:
            data = f.read()
        # 在后端将html页面处理好之后再返回给前端
    	data = data.replace("dadaadad", current_time)
    	return data
    
    from jinja2 import Template
    def get_dict(env):
        user_dic = {'username': 'jason', 'age': 18, 'hoby': 'read'}
        with open(r"get_dict.html", "r", encoding="utf-8") as f:
            data = f.read()
        tmp = Template(data)
        res = tmp.render(user=user_dic)
        # 给get_dict.html传递了一个值 页面上通过变量名user就能够拿到user_dict
        return res
    
    import pymysql
    def get_user(env):
        # 去数据库中获取数据 传递给html页面, 借助于jinja2模板语法 发给浏览器
        conn = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',
            password='admin123',
            db='daystu',
            charset='utf8',
            autocommit=True
        )
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        sql = 'select * from userinfo'
        affect_rows = cursor.execute(sql)
        data_list = cursor.fetchall()   # [{}, {}, {}]
        print(data_list)
        with open(r"get_data.html", "r", encoding="utf-8") as f:
            data = f.read()
        tmp = Template(data)
        res = tmp.render(user_list=data_list)
        return res
    
    urls = [
        ('/index', index),
        ('/get_dict', get_dict),
        ('/get_user', get_user)
    ]
    
    
    def run(env, response):
        """
    
        :param env: 请求相关的所有数据
        :param response:  响应相关的所有数据
        :return: 返回给浏览器的数据
        """
        print("http://127.0.0.1:8080/")
        print(env)   # wsgiref模块帮你处理号htpp格式的数据,装成了字典
        current_path = env.get('PATH_INFO')
        response('200 OK', [])
        # if current_path == '/index':
        #     return [b'index']
        # elif current_path == '/login':
        #     return [b'login']
        # return [b'404 err']
        func = None
        for url in urls:
            if current_path == url[0]:
                func = url[1]
                break
        if func:
            res = func(env)
        else:
            res = error(env)
        return [res.encode('utf-8')]
    
    
    if __name__ == '__main__':
        # 会实时监听127.0.0.1地址, 只要有客户端来了,都会交给run函数处理(加括号触发run函数的运行)
        server = make_server('127.0.0.1', 8080, run)
        server.serve_forever()   # 启动服务端
    
4、实现web框架开发的基本了解
  • 功能分类
    根据功能不同拆分成不同的py文件,拆分完成后,后续想要添加功能,只需要在urls.py和views.py中书写对应的代码即可
    urls.py  路由与视图函数的对应关系
    views.py   视图函数(后端业务逻辑,函数功能),也可以是类
    templates文件夹   专门用来存储html文件
    
  • 动静态网页概念
    1、静态网页
    	页面上的数据集直接写死,万年不变
    2、动态网页
    	数据实时获取的 (后端获取实时时间展现在html, 数据从数据库中实时获取的展示在html页面上)
    
  • 实现后端数据与html数据交互,模板语法,实现后端数据与html数据交互,(在后端起作用), jinja2语法
    pip 3 install jinja2
    {{ user }}
    {{ user.get('username')}}
    {{ user['username']}}
    
    {% for user_dict in user_list %}
    	<tr>
    		<td>{{user_dict.username}}</td>
    		<td>{{user_dict.hobby}}</td>
    	</tr>
    {% endfor %}
    
    from jinja2 import Template
    def get_dict(env):
        user_dic = {'username': 'jason', 'age': 18, 'hoby': 'read'}
        with open(r"get_dict.html", "r", encoding="utf-8") as f:
            data = f.read()
        tmp = Template(data)
        res = tmp.render(user_list=user_dic)
        # 给get_dict.html传递了一个值,页面上通过变量名user就能够拿到user_dict
        return res
    
  • 三大主流框架区别
    wsgiref模块
    	1、请求来的时候解析http格式的数据 封装成大字典
    	2、响应走的时候给数据打包成符合http格式 再返回给浏览器
    python三大主流web框架
     	1、django:大而全,自带功能特别多;时而过于笨重
     	2、flask:小而精,自带的功能特别特别的少,第三方模块特别多;比较依赖于第三方的开发者
     	3、tornado:异步非阻塞,支持高并发,甚至可以开发游戏服务器
    
    框架的三个部分:
    	A:socket部分
    	B:路由于视图函数对应关系(路由匹配)
    	C:模板语法
    	
    	django: A用的是别人的wsgiref模块,B用的是自己的,C用的是自己的,没有jinja2好用
    	flask:A用的是别人的werkzeug(内部是wsgiref模块),B用的是自己的,C用的别人的jinja2
    	tornado:A、B、C都是自己写的
    
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值