django整理未整理完

创建虚拟环境

  • 创建隔离的Python运行环境

virtualenv

  • Windows下:
    1. 安装:pip install virtualenv
    2. 创建独立的Python运行环境
      virtualenv spider
      创建新的Python环境放到当前目录下的spider目录中
    3. 进入虚拟环境
      env\spider\activate
  • Linux下:
    1. 安装:pip install virtualenv
    2. 创建独立的Python运行环境
      virtualenv -p /usr/bin/python3.6 env #指定Python版本
      virtualenv env #默认Python2.7
      创建新的Python环境放到当前目录下的env目录中
    3. 进入虚拟环境
      cd env
      source ./bin/activate
    4. 退出虚拟环境:deactivate
    5. 删除虚拟环境:rmvirtualenv env

用Python3自带的

  • 安装python3-env
    sudo apt-get install python3-venv
  • 创建虚拟环境test
    python3.5 -m venv test
  • 进入虚拟环境
cd test
source ./bin/activate
  • 退出虚拟环境
    deactivate

安装django

  • pip install django
  • 查看当前环境下的第三方库:pip list

云服务器部署

  • 我用的是华为云服务器ESC,云服务器需要配置端口
  • 首先登录,到下图位置,在更多里选择更改安全组
    在这里插入图片描述
  • 选择新建安全组
    在这里插入图片描述
  • 选择配置规则
    在这里插入图片描述
  • 我添加的是8000的端口,我下面的django项目用8000的端口
    在这里插入图片描述
  • 访问云服务器要用云服务器的公网加端口

项目创建

  • 新建项目的命令:django-admin startproject projectname
  • pycharm环境配置见https://blog.csdn.net/xiaogeldx/article/details/87315081
  • 先在命令行创建项目,然后再设置pycharm代码同步
    在这里插入图片描述

开发服务器

  1. 将settings.py文件中的ALLOWED_HOSTS = 改为ALLOWED_HOSTS = ["*"]
  2. Linux虚拟机网络连接方式是nat端口转发时,需要设置http服务8000端口的转发

开启服务器

  • 方式一(不常用):
    命令行模式:
    在项目的根目录下执行命令
    python manage.py runserver 0.0.0.0:8000 #0.0.0.0可以简写为0
  • 方式二(常用):
    1. 选择编辑器右上角的Edit Configuration的按钮
    2. 点击添加Django server
    3. 改Host为0.0.0.0,表示的是允许连接服务器的IP #方便调试,使用什么ip都能访问到
    4. 点击Environment Variables项后面的…
    5. 将DJANGO_SETTINGS_MODULE添加到Name,将项目名.settings添加到Value
    6. 在apply按钮上有可能fix有红灯标志,点进去,把Enable Django Support勾选上,Django project root行点文件夹标志,选上根目录,Settings行点文件夹标志,选上根目录下的settings.py文件
      在这里插入图片描述

访问服务器

  1. 当用其中的一种方式开启了服务后,打开浏览器
  2. 在地址栏输入IP地址和服务的端口号
  3. 可以看到服务正在运行的页面
    在这里插入图片描述
  • 需要注意的点:
    • IP:
      • 在终端用命令ifconfig查看IP,注意网络连接方式
      • 虚拟机的端口转发时使用的是127.0.0.1回环地址
    • port
      • 远程连接ssh服务的端口号是22
      • http服务端口号8000/8080
      • MySQL服务的端口号3306

新建app

  • 在项目根目录下创建命令:python manage.py startapp app_name

  • 在app下新建urls.py

  • 在settings.py中的INSTALLED_APPS加入app,我的代码如下:(我新建了students和teachers两个app)

      INSTALLED_APPS = [
          'students',
          'teachers',
          'django.contrib.admin',
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.messages',
          'django.contrib.staticfiles',
      ]
    

新建views

  • 在app下新建views.py,简单代码如下:

      from django.shortcuts import render
      from django.http import HttpResponse	#导包
      def index(request):
          return HttpResponse('hi girl')
    

设置urls

  • app下新建urls.py文件,代码如下:

      from django.urls import path, re_path
      from students import views		#导包
      app_name = 'students'
      urlpatterns = [
          path('index/', views.index , name='index'),
      ]
    
  • 项目的urls.py文件代码:

      from django.contrib import admin
      from django.urls import path, re_path, include	#导包
      urlpatterns = [
          path('admin/', admin.site.urls),
          path('students/', include('students.urls'))		#students/前面不要加/
      ]
    

模板路径配置

  1. 在主目录下(和manage.py同等级,也叫项目根目录)创建一个templates目录用来存放所有的HTML的模板文件
  2. templates目录里面在新建各个以app名字命名的目录来存放各个app中模板文件
    在这里插入图片描述

渲染

	return render(request, 'students/index.html')   

在这里插入图片描述

调用渲染

  • 在index.html文件中
    • {{变量名}}
  • 在viwes.py文件中:
    • return HttpResponse(request, ‘students/index.html’, context{‘变量名’: 变量})
  • 语法:命名由字母和数字以及下划线组成,不能有空格和标点符号,不能以下划线,数字开头,不能以Python,django关键字命名
  • 变量的值可以是任何数据类型(字典,模型,方法,函数,列表…)
  • 变量的解析规则
    • 当模板引擎遇到模板变量,会计算变量,将其替换为结果
    • 解析结果相当于print的值
    • 模板变量中有点(.)的时候,按以下顺序查找
      • 字典键值查找
      • 属性或方法查找
      • 数字索引查找
    • 如果结果是可调用的,则调用它时不带参数,调用的结果成为模板的值(解析结果)
      如果渲染失败,返回空

案例

  • views.py文件

      from django.shortcuts import render, redirect, reverse
      from django.http import HttpResponse
      from django.template.loader import get_template
      from datetime import datetime
      class Test:
          def __init__(self, name, age):
              self.name = name
              self.age = age
          def student(self):
              return 'my girl'
      s = Test('xiaoge', 18)
      def index(request):
          lt = [1, 2, 3]
          now = datetime.now()
          dt = {'name': 'xiaoge', 'age': 19, 'items':'abc'}
          tp = (1, 2, 3)
          str = 'hi girl'
          return render(request, 'students/index.html',
                        context={
                            'now': now,
                            'lt': lt,
                            'cs': s,
                            'name': s.name,
                            'fc': s.student,
                            'dt': dt,
                            'tp': tp,
                            'str':str,
                                 })
    

模板过滤器

  • 对变量进行过滤,在真正渲染出来之前,过滤器会根据功能处理好变量,然后得出结果后再替换掉原来的变量展示出来

  • 语法:{{value|方法}}

  • 使用参数:过滤器可以使用参数,在过滤器名称后面使用‘:’,再在引号中加上参数

    • {{value|方法:‘参数’}}
  • 常用模板过滤器
    - add 将参数与值相加 首先尝试转换成整数相加,失败,则尝试所有可能,字符串,列表等。{{ value|add:“2” }}
    - capfirst 首字母大写,如果第一个字母不是字母则不起作用。{{ value|capfirst }}
    - date 日期格式化 {{ value|date:“D d M Y” }}
    - time 时间格式化 {{ value|time:“H:i:s” }} 格式化格式见官方文档:https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#date
    - default 如果变量解析失败,使用给定的默认值。{{ value|default:“nothing” }}(注意如果value是空字符串或者None,输出将会是’nothing’)
    - first 返回列表的第一个元素 {{ value|first }}
    - last 返回列表的最有一个元素 {{ value|last }}
    - slice 返回一个列表的切片 {{ some_list|slice:“2” }}
    - join 连接字符串列表 与str.join(list)一样 {{ value|join:" // " }}
    - length 返回字符串或列表的长度
    - length_is 判断字符串或列表长度是否指定的值,相等返回True {{ value|length_is:“4” }}
    - lower 字符串中的字母都变小写{{ value|lower }}
    - upper 字符串中的字母都变大写{{ value|upper }}
    - safe 关闭变量的自动转义,使html标签生效{{ value|safe }}
    - title 标题化,首字母大写 {{ value|title }}
    - floatformat 浮点数格式化 不指定小数位参数,默认保留一个为小数

      			 value	           Template	                  Output
      			34.23234  	{{ value|floatformat }}            34.2
      			34.23234 	{{ value|floatformat:3 }}         34.232
    

案例

  • index.html文件:

      <p>现在时间{{ now|date:'Y-m-d H:i:s' }}</p> #模板过滤器
      <p>列表第一个值+3:{{ lt.0|add:3 }}</p>
      <p>列表第一个值+3.5:{{ lt.0|add:3.5 }}</p>
      <p>列表第一个值+'3':{{ lt.0|add:'3' }}</p>
      <p>首字母大写:{{ fc|capfirst}}</p>
      <p>字母都大写:{{ fc|upper}}</p>
      <p>字母标题化:{{ fc|title}}</p>
      <p>浮点数:{{ 3.1413223|floatformat}}</p>
      <p>浮点数:{{ 3.1413223|floatformat:'3'}}</p>
      <p>插入/:{{ fc|join:'/'}}</p>
      <p>字符串长度:{{ fc|length}}</p>
      <p>字符串长度:{{ fc|length_is:'7'}}</p>
      <p>列表第一个值+'3.5':{{ lt.0|add:'3.5' }}</p>
      <p>函数加字符串{{ fc|add:'haha' }}</p>
      <p>字典的值gender是否存在{{ dt.gender|default:'nothing' }}
      <p>列表第一个值:{{ lt|first }}</p>
      <p>列表最后一个值:{{ lt|last }}</p>
      <p>列表切片:{{ lt|slice:'2' }}</p> #取前两个
      <p>列表倒序:{{ lt|slice:'::-1' }}</p>		
    

在这里插入图片描述

静态文件

  • 路径设置
    • 在settings.py文件中添加STATICFILES_DIRS = [os.path.join(BASE_DIR, ‘static’)]
  • 新建文件
    • 在项目根目录下新建static文件夹,在static下新建app名的文件夹,在app文件夹下新建css等需要的文件夹,在css文件夹下新建cover.css文件(名自己起)
      在这里插入图片描述
  • 静态文件的引入
    在settings.py中有STATIC_URL = ‘/static/’ #这里的static对应link中href的static,不建议改
    • 模板标签

    • 在开头加载static,在head标签中加入link

        {% load static %}   #加载static
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
            #在link的href中加载路径,格式为{% static 'app名/css路径' %}
            <link rel="stylesheet" href="{% static 'students/css/index.css' %}">
        </head>
      
  • F12查看网页,会发现选中的部分和硬编码一样
    在这里插入图片描述

模板标签

在这里插入图片描述
在这里插入图片描述
效果图:
在这里插入图片描述

标签语法

  • 由{% 和 %}来定义的,例如:{% tag %} {% endtag %}

常用标签

  • 标签内的语法和Python语法大致一样
    在这里插入图片描述

案例

  • index.html文件中的demo

      <table class="table">
          <tr>
              <th>序号</th>
              <th>姓名</th>
              <th>年龄</th>
              <th>性别</th>
          </tr>
      {#  如果students为空,则渲染empty下的内容#}
          {% for stu in students %}   
              <tr {% if stu.age < 17 %}style="color:blue;"
                  {% elif stu.age > 16 and stu.age < 22 %}style="color:red;"
                  {% else %}style="color:green;"
                  {% endif %}>
      {#        forloop.counter获取当前for循环的迭代次数,以1开始#}
      {# 硬编码跳转  <td><a href="/students/detail/{{ stu.id }}/">{{ forloop.counter }}</a></td>#}
                  <td><a href="{% url 'students:detail' stu.id %}">{{ forloop.counter }}</a></td>
      {#        forloop.counter0获取当前for循环的迭代次数,以0开始#}
      {#            <td>{{ forloop.counter0 }}</td>#}
      {#        forloop.revcounter获取当前for循环的迭代次数,从大到小#}
      {#            <td>{{ forloop.revcounter }}</td>#}
      {#        forloop.revcounter0获取当前for循环的迭代次数,从大到小,最小为0#}
      {#            <td>{{ forloop.counter0 }}</td>#}
                  <td>{{ stu.name }}</td>
                  <td>{{ stu.age }}</td>
                  <td>{{ stu.gender }}</td>
              </tr>
      {#  如果students为空,则渲染empty下的内容#}
      {#          {% empty %}#}
      {#          要渲染的内容#}
          {% endfor %}
      </table>
    
  • views.py文件中的demo:

      def index(request):
          students = [
          {'id':10, 'name': '小哥', 'age': 15, 'gender': '男'},
          {'id':33,'name': 'yang', 'age': 15, 'gender': '女'},
          {'id':53,'name': 'wen', 'age': 25, 'gender': '女'},
          {'id':12,'name': 'long', 'age': 18, 'gender': '男'},
          {'id':76,'name': 'na', 'age': 16, 'gender': '女'},
          {'id':38,'name': 'yi', 'age': 19, 'gender': '女'},
          {'id':48,'name': 'xin', 'age': 17, 'gender': '男'},
          ]
          return render(request, 'students/index.html', context={
              'students': students,
          })
      def detail(request, pk): #pk一般是个id,是整数primary key
          return HttpResponse('学生id为%s的详情页' % pk)
    
  • urls.py文件中的demo:

      	urlpatterns = [
      	    path('index/', views.index, name='index'),  #index前不要加/,django自动添加,index后面要加/
      	    path('login/', views.login),
      	    path('detail/<int:pk>/', views.detail, name='detail'), #捕获的值传递给views.py里的detail(request,pk)的pk
      	]
    

模板的继承与引用

引用

  • 将渲染好的模板放到想要放的模板中

  • 用include标签将ad.html引用到index.html中

  • index.html中加入下面代码:

      <div style="position:fixed; bottom:0px;">
          {% include 'students/ad.html' %}
      </div>
    
  • ad.html文件中代码:

      <h1 id="h1">你看不见我,你看不见我</h1>
          <script>
              var h = document.getElementById('h1')
              var color = 'blue'
              function change_color() {
                  if(color=='blue'){
                      color = 'red';
                  }else{
                      color = 'blue';
                  }
                  h.style.color = color;
                  setTimeout('change_color()',400)
              }
              change_color()
          </script>
    
  • 模板继承使用extends标签实现,通过使用block来给子模板开放接口

    • extends必须是模板中的第一个出现的标签
    • 子模板中的所有内容,必须出现在父模板定义好的block中,否则django将不会渲染
    • 如果出现重复代码,就应该考虑使用模板
    • 尽可能多的定义block,方便子模板实现更细的需求
    • 如果在某个block中,要使用父模板的内容,使用block.super获取
    • block相当于字符串中的占位符,当继承时就可以在block中间写继承模板自己的demo
      • block用法:形如{% block content %} <h1>我是base</h1> {% endblock %},
        content起定位作用
    • block可以插入多个

不加block案例

在这里插入图片描述
在这里插入图片描述

  • 效果图:
    在这里插入图片描述

案例

  • base.html文件demo:

      <!DOCTYPE html>
      <html lang="zh-CN">
        <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <meta name="description" content="">
          <meta name="author" content="">
          <title>{% block title %}base{% endblock %}</title>
          <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
            <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
            <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
              {% block link %}{% endblock %}
        </head>
        <body>
        {% block content %}
        {% endblock %}
      {% block domready %}
      {% endblock %}
        </body>
      </html>
    
  • index.html文件的demo:

      {% extends 'students/base.html' %}
      {% block title %}学生表{% endblock %}
      {% load static %}
      {% block link %}<link href="{% static 'students/css/index.css' %}" rel="stylesheet">{% endblock %}
      {% block content %}
          <div class="blog-masthead">
            <div class="container">
              <nav class="blog-nav">
                <a class="blog-nav-item active" href="#">Home</a>
                <a class="blog-nav-item" href="#">New features</a>
                <a class="blog-nav-item" href="#">Press</a>
                <a class="blog-nav-item" href="#">New hires</a>
                <a class="blog-nav-item" href="#">About</a>
              </nav>
            </div>
          </div>
          <div class="container">
            <div class="blog-header">
              {#  从这里开始替换#}
              <table class="table">
                  <tr>
                      <th>序号</th>
                      <th>姓名</th>
                      <th>年龄</th>
                      <th>性别</th>
                  </tr>
              {#  如果students为空,则渲染empty下的内容#}
                  {% for stu in students %}
                      <tr {% if stu.age < 17 %}style="color:blue;"
                          {% elif stu.age > 16 and stu.age < 22 %}style="color:red;"
                          {% else %}style="color:green;"
                          {% endif %}>
              {#        forloop.counter获取当前for循环的迭代次数,以1开始#}
              {# 硬编码跳转  <td><a href="/students/detail/{{ stu.id }}/">{{ forloop.counter }}</a></td>#}
                          <td><a href="{% url 'students:detail' stu.id %}">{{ forloop.counter }}</a></td>
              {#        forloop.counter0获取当前for循环的迭代次数,以0开始#}
              {#            <td>{{ forloop.counter0 }}</td>#}
              {#        forloop.revcounter获取当前for循环的迭代次数,从大到小#}
              {#            <td>{{ forloop.revcounter }}</td>#}
              {#        forloop.revcounter0获取当前for循环的迭代次数,从大到小,最小为0#}
              {#            <td>{{ forloop.counter0 }}</td>#}
                          <td>{{ stu.name }}</td>
                          <td>{{ stu.age }}</td>
                          <td>{{ stu.gender }}</td>
                      </tr>
              {#  如果students为空,则渲染empty下的内容#}
              {#          {% empty %}#}
              {#          要渲染的内容#}
                  {% endfor %}
              </table>
            </div>
          </div><!-- /.blog-sidebar -->
          <div style="position:fixed; bottom:0px;">
          {#  将渲染好的模板放到想要放的模板#}
              {% include 'students/ad.html' %}
          </div>
      {% endblock %}
      {% block domready %}
          <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
          <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
          <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
      {% endblock %}
    
  • 效果图:
    在这里插入图片描述
    base模块用尽可能多的block,根据实际业务,宁多勿缺

关于自定义

  • 代码布局(自定义的代码放在那里)
    • 某个app特有的
      • app目录下创建templatetags(Python的包)(名字固定的)文件夹
      • 把普通文件夹变成Python的包:在文件夹中加__init__.py
      • 在templatetags文件夹下创建Python模块(py文件)
    • 定义复用
      • 创建一个新的app,将他们定义在新的app中,在INSTALL_APPS注册,然后就可以应用
    • app特有的和复用的只是代码布局(代码所在文件夹)不同,没有什么区别
  • templates用于存放模板的目录
  • templatetags用于存放自定义标签及过滤器的目录
    templatetags这个目录名字是固定的,而里面的模块名是自定义的

自定义模板过滤器

  • 模板过滤器本质是函数
  • 有一个或两个参数,返回字符串
    • 第一个参数是传递进来的模板变量
    • 第二个参数是普通的参数,也可以是默认,也可以不要
  • 定义非常简单,就是写一个函数,一个带有一个或两个参数的Python参数:
    • (输入的)变量的值不一定是字符串形式
    • 参数的值可以有一个初始值,或者完全不要这个参数

注册自定义过滤器

  • 注册自定义过滤器有两种方法:
    • 通过django.template.Library的实例的filter方法
      django.template.Library.filter()
      • Library.filter()方法需要两个参数:
        • name 过滤器的名称(一个字符串对象),可以不写,默认使用方法名作为过滤器的名称
        • filter_func(定义的过滤器的函数),一个Python函数(不要把函数名写成字符串)
    • 也可以把register.filter()用做装饰器
      • 可以传name参数,也可以不传
  • 没有声明name参数,Django将使用函数名作为过滤器的名字

使用自定义过滤器

  • 在模板中使用自定义的过滤器
  • 需要使用{% load 模块名 %}标签将我们的自定义的模块加载进来
  • {% load 模块名 %}声明将会载入给定模块名中的标签/过滤器

案例

  • views.py中的index代码:

      def index(request):
          students = [
          {'id':10, 'name': '小哥', 'age': 15, 'gender': 1},
          {'id':33,'name': 'yang', 'age': 15, 'gender': 0},
          {'id':53,'name': 'wen', 'age': 25, 'gender': 0},
          {'id':12,'name': 'long', 'age': 18, 'gender': 1},
          {'id':76,'name': 'na', 'age': 16, 'gender': 0},
          {'id':38,'name': 'yi', 'age': 19, 'gender': 0},
          {'id':48,'name': 'xin', 'age': 17, 'gender': 1},
          ]
          return render(request, 'students/index.html', context={
              'students': students,
          })
    
  • index.html的demo:

      {% extends 'students/base.html' %}
      {% block title %}学生表{% endblock %}
      {% load static %}
      {% load customer_filters %}
      {% block link %}<link href="{% static 'students/css/index.css' %}" rel="stylesheet">{% endblock %}
      {% block content %}
          <div class="blog-masthead">
            <div class="container">
              <nav class="blog-nav">
                <a class="blog-nav-item active" href="#">Home</a>
                <a class="blog-nav-item" href="#">New features</a>
                <a class="blog-nav-item" href="#">Press</a>
                <a class="blog-nav-item" href="#">New hires</a>
                <a class="blog-nav-item" href="#">About</a>
              </nav>
            </div>
          </div>
          <div class="container">
            <div class="blog-header">
              {#  从这里开始替换#}
              <table class="table">
                  <tr>
                      <th>序号</th>
                      <th>姓名</th>
                      <th>年龄</th>
                      <th>性别</th>
                  </tr>
              {#  如果students为空,则渲染empty下的内容#}
                  {% for stu in students %}
                      <tr {% if stu.age < 17 %}style="color:blue;"
                          {% elif stu.age > 16 and stu.age < 22 %}style="color:red;"
                          {% else %}style="color:green;"
                          {% endif %}>
              {#        forloop.counter获取当前for循环的迭代次数,以1开始#}
              {# 硬编码跳转  <td><a href="/students/detail/{{ stu.id }}/">{{ forloop.counter }}</a></td>#}
                          <td><a href="{% url 'students:detail' stu.id %}">{{ forloop.counter }}</a></td>
              {#        forloop.counter0获取当前for循环的迭代次数,以0开始#}
              {#            <td>{{ forloop.counter0 }}</td>#}
              {#        forloop.revcounter获取当前for循环的迭代次数,从大到小#}
              {#            <td>{{ forloop.revcounter }}</td>#}
              {#        forloop.revcounter0获取当前for循环的迭代次数,从大到小,最小为0#}
              {#            <td>{{ forloop.counter0 }}</td>#}
                          <td>{{ stu.name }}</td>
                          <td>{{ stu.age }}</td>
                {#to_male对应customer_filter.py的@register.filter的name名对应#}
                          <td>{{ stu.gender|to_male:'en' }}</td>	
                      </tr>
              {#  如果students为空,则渲染empty下的内容#}
              {#          {% empty %}#}
              {#          要渲染的内容#}
                  {% endfor %}
              </table>
            </div>
          </div><!-- /.blog-sidebar -->
          <div style="position:fixed; bottom:0px;">
          {#  将渲染好的模板放到想要放的模板#}
              {% include 'students/ad.html' %}
          </div>
      {% endblock %}
      {% block domready %}
          <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
          <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
          <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
      {% endblock %}
    
  • customer_filter.py的demo:

      from django.template import Library
      register = Library()	#register名称固定,不可改
      # @register.filter()	#和下一行的区别是下一行可以定义name名
      #自定义过滤器的第二种方法
      @register.filter(name='to_male')	#'to_male'对应{{ stu.gender }}的to_male
      def to_male(value, arg='zh'):    #默认是中文
          map = {
              'zh': ('女', '男'),
              'en': ('female', 'male')
          }
          # if value == 0:
          #     if arg == 'zh':
          #         return '女'
          #     return 'female'
          # if value == 1:
          #     if arg == 'zh':
          #         return '男'
          #     return 'male'
          return map[arg][value] 	#等同于上几行注释掉的demo
      #下面三行注释掉的是一样的效果,是注册自定义过滤器的第一种方法
      # register.filter('to_male', to_male)
      # register.filter(to_male)
      # register.filter(name='to_male', filter_func=to_male)
    

    效果图:
    在这里插入图片描述

自定义模板标签

简单标签

	django.template.Labrary.simple_tag()
  • 新建Python模块
    • 在templatetags中创建py文件,customer_tags.py
  • 注册
    • 调用函数
    • 装饰器
  • 引用上下文变量(views中render传递到模板中的那个context)
    • 只需要在simple_tag中,设置参数take_context=True
    • 自定义的标签函数的第一个参数一定是context
  • 使用自定义模板标签
    • 需要使用{% load 模块名 %}标签将我们的自定义的模块加载进来

demo

  • views.py的代码:

      format_str = '%Y-%m-%d %H:%M:%S'
          return render(request, 'students/index.html', context={
              'students': students,
              'format_str': format_str,
          })
    
  • index.html的代码:

      {% load customer_tags %}	#在开头
      <h1>当前时间:{% current %}</h1>		#在正文部分
    
  • customer_tags的代码:

      from django.template import Library
      from datetime import datetime
      register = Library()
      @register.simple_tag(name='current', takes_context=True)    #注册,装饰器
      def current_time(context):  #context必须是第一个参数,并且名字固定,不能改
          return datetime.now().strftime(context['format_str'])
      # register.simple_tag(current_time, name='current') #注册,调用函数
    

包含标签

	django.template.Library.inclusion_tag()
  • 通过渲染另外一个模板来展示数据,类似url中的include

定义

  • 在customer_tags模板中定义一个函数,接受调用时传递的模板变量

      @register.inclusion_tag('students/show_list_as_ul.html')    #参数是想要传的模板路径
      def show_list_as_ul(value, style):
          return {'ls': value, 'style': style}
      # registerinclusion_tag('students/show_list_as_ul.html')(show_list_as_ul)
    
  • 定义一个模板

  • tag()方法有两个参数:

    • 模板标记的名称是字符串,如果省略,将使用编译函数的名称
    • 编译的函数是一个Python函数(不要把函数名写成字符串)
    • 和简单标签注册一样,也可以将其用做装饰器
    • 也可以拿到context,和简单标签用法一样
  • 包含标签的功能是可以通过渲染另外一个模板来显示一些数据

  • 很多地方都可能会用到下面这几行代码,除了choices(模板变量)这几个变量不一样之外,其他的都是格式都一样时,那么我们就可以把这部分代码封装在一个包含标签中

      <ul>
          {% for i in choices %}
          <li>{{ i }}</li>
          {% endfor %}
      </ul>
    

案例

  • show_list_as_ul.html的代码:

      {% if style == 'button' %}
          <div class="list-group">
          {% for l in ls %}
               <button type="button" class="list-group-item">{{ l }}</button>
          {% endfor %}
          </div>
      {% elif style == 'link' %}
          <div class="list-group">
          {% for l in ls %}
              <a href="#" class="list-group-item active">{{ l }}</a>
          {% endfor %}
          </div>
      {% else %}
          <ul class="list-group">
          {% for l in ls %}
              <li class="list-group-item">{{ l }}</li>
          {% endfor %}
          </ul>
      {% endif %}
    
  • index.html的部分代码:

      {#                    <td>{% show_list_as_ul stu.course 'link' %}</td>#}
      {#                    等同于上行代码#}
      {#                    <td>{% show_list_as_ul stu.course style='link' %}</td>#}
      {#                    <td>{% show_list_as_ul stu.course 'button' %}</td>#}
                          <td>{% show_list_as_ul stu.course '' %}</td>
    
  • customer_tags.py的部分代码:

      @register.inclusion_tag('students/show_list_as_ul.html')    #参数是想要传的模板路径
      def show_list_as_ul(value, style):
          return {'ls': value, 'style': style}
      # register.inclusion_tag('students/show_list_as_ul.html')(show_list_as_ul)
    

模型的创建与映射

django模型映射关系

  • 模型类必须都写在app下的models.py文件中
  • 模型如果需要映射到数据库,所在的app必须被安装
  • 一个数据表对应一个模型类,表中的字段对应模型中的类属性,一个实例对应数据表中的一条数据

django连接MySQL的配置流程

  • 安装pymysql:pip install pymysql

  • 创建数据库用户(有数据库权限的用户)

  • 创建数据库(我的是django_test)

  • 修改配置(settings.py)

      DATABASES = {
          'default': {
              'ENGINE': 'django.db.backends.mysql',
              'NAME': 'django_test',
              'USER':'xiaoge',
              'PASSWORD':'*****',
              'HOST':'127.0.0.1',
              'PORT':'****'
          }
      }
    
  • 修改项目文件夹(和settings.py文件所在的目录)下的__init__.py添加代码:

      import pymysql
      pymysql.install_as_MySQLdb()
    
  • 设置时区(settings.py)

      TIME_ZONE = 'Asia/Shanghai'	#北京时间
    

创建模型

  • 创建一个student的模型,代表学生

  • 每一个模型都是django.db.models.Model的子类

  • 类变量表示模型中的数据库字段

  • 每一个字段由一个字段类的实例表示

  • 数据表的名称就是模型的名称

  • 在students中的models.py文件中创建模型

      from django.db import models
      class Student(models.Model):     #继承
      	#可以不写主键,模型会创建
      	# id = models.IntegerField(primary_key=True,auto_created=True)  
          name = models.CharField(max_length=20)	#字符串
          age = models.SmallIntegerField(default=0)   #整数,默认为0,表示没填
          sex = models.SmallIntegerField(default=1)   #整数,默认为1(男)
          qq = models.CharField(max_length=20,default='') #字符串,默认不填
          phone = models.CharField(max_length=20,default='')  #字符串,默认不填
          c_time = models.DateTimeField(verbose_name='创建时间',auto_now_add=True)   #创建时间,自动记录当前时间
              def __str__(self):
     				return '%s-%s' % (self.name,self.age)
    

激活模型

  • 在项目中注册app

    • 在settings.py的INSTALLED_APPS中注册
  • 运行数据库迁移命令(在项目根目录下)

      python manage.py makemigrations students#如果不加students,settings.py的INSTALLED_APPS中所有的app都会迁移
    

在这里插入图片描述
- 告诉django我们做了哪些数据库的修改
数据库迁移文件见下图的0001_initial.py,再修改就会多个0002
在这里插入图片描述
- python manage.py sqlmigrate students 0001可以从迁移的地方获取sql语句,效果见下图
在这里插入图片描述
- 表名:appname_模型name(小写的),如students_student
- django会自动创建主键,一般取名为id

  • 此时数据库中还没有表,需要运行migrate命令使迁移生效

      python manage.py migrate students
    

在这里插入图片描述
在这里插入图片描述
- 要修改数据库,都要修改模型,然后运行数据库迁移命令,再运行使迁移生效命令

数据的增删改查

  • django shell调试工具

      python manage.py shell
    
  • 导入模型

      from students.models import Student 
    

具体方法见 https://blog.csdn.net/xiaogeldx/article/details/87899499
https://blog.csdn.net/xiaogeldx/article/details/87927345

表关系

在这里插入图片描述
在这里插入图片描述

一对一(OneToOne)

  • 通过本表的主键外键关联另一张表的主键

  • 创建张学生详情表(在students的models.py文件中)

      	from django.db import models
      	class Student(models.Model):
      	    name = models.CharField(max_length=20)
      	    age = models.SmallIntegerField(default=0)
      	    gender = models.SmallIntegerField(default=1)
      	    qq = models.CharField(max_length=20,default='')
      	    phone = models.CharField(max_length=20,default='')
      	    c_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
      	    def __str__(self):
      	        return '%s-%s' % (self.name, self.age)
      	class StudentDetail(models.Model):	#学生对学生详情,一对一
      	    num = models.CharField(max_length=20, default='')
      	    college = models.CharField(max_length=20,default='')
      	    #Student最好用字符串 
      	    student = models.OneToOneField('Student', on_delete=models.CASCADE)    
      	    #外键和一对一关系的时候需要加on_delete选项,此参数为了避免两个表里的数据不一致问题,不然会报错	#一般使用CASCADE表示级联删除
    

    图中的student_id就是外键关联
    在这里插入图片描述

一对多(OneToMany)

		from django.db import models
		class Student(models.Model):
		    name = models.CharField(max_length=20)
		    age = models.SmallIntegerField(default=0)
		    gender = models.SmallIntegerField(default=1)
		    grade = models.ForeignKey('Grade', on_delete=models.SET_NULL, null=True)    #删除某个学生后,班级对应的位置会显示为NULL
		    qq = models.CharField(max_length=20,default='')
		    phone = models.CharField(max_length=20,default='')
		    c_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
		    def __str__(self):
		        return '%s-%s' % (self.name, self.age)
		class StudentDetail(models.Model):  	#学生对学生详情,一对一
		    num = models.CharField(max_length=20, default='')
		    college = models.CharField(max_length=20,default='')
		    #Student最好用字符串  
		    student = models.OneToOneField('Student', on_delete=models.CASCADE)   
		class Grade(models.Model):  #学生对班级,一对多
		    num = models.CharField(max_length=20)
		    name = models.CharField(max_length=20)

在这里插入图片描述

多对多(ManyToMany)

		class Course(models.Model):
		   	name = models.CharField('课程名称', max_length=20)  #参数第一位就是verbose_name,“verbose_name=”可省略
		    students = models.ManyToManyField('Student', through='Enroll')    #Student表和Course表可以不通过Enrol就能相互访问l#如果只有外键和id两个字段时会自动创建第三张表关联
		class Enroll(models.Model): #报名表,有多个字段
		    student = models.ForeignKey('Student', on_delete=models.CASCADE)
		    course = models.ForeignKey('Course', on_delete=models.CASCADE)
		    pay = models.FloatField('缴费金额', default=0)
		    c_time = models.DateTimeField('报名时间', auto_now_add=True)

在这里插入图片描述
在这里插入图片描述

关联表的数据操作

详细操作见 https://blog.csdn.net/xiaogeldx/article/details/88084034

form标签中的GET和POST请求

  • 在HTML中,form表单的作用是收集标签中的内容,<form>…</form>中间可以由访问者添加类似与文本,选择,或者一些控制模块等等,然后这些内容将会被送到服务端
  • 一个表单必须指定两样东西:
    • form的method参数用于表单的提交方式,默认使用POST
    • action用于设置表单的提交URL,如果不写或者保持空字符串,将使用当前的URL
      在这里插入图片描述
      在这里插入图片描述

GET

  • get方式提交的参数会在url中显示
  • 可以通过request.GET.get的方法来获取提交的参数
    在这里插入图片描述
  • 得到类字典,可以通过字典的方式取值
    在这里插入图片描述
    在这里插入图片描述
  • 一键多值时用get只能拿到一个值,要用getlist,post也这样
  • request对象的属性GET,POST都是QueryDict类型的对象,与Python字典不同,QueryDict类型的对象用来处理同一个键带多个值的情况
    • get根据键获取值,只能获取键的一个值,如果一个键同时拥有多个值,获取最后一个
    • getlist根据键获取值,将键的值以列表返回,可以获取一个键的多个值
      在这里插入图片描述
      在这里插入图片描述

request中GET对象的属性

  • QueryDict类型的对象
  • 包含get请求方式的所有参数
  • 与url请求地址中的参数对应,位于?后面
  • 参数的格式是键值对,如key1=value1
  • 多个参数之间,使用&连接,如key1=value1&key2=value2
    在这里插入图片描述

POST

  • 登录一般用post请求,get太不安全

  • post的提交方式不会在url中显示参数

  • 可以通过request.POST.get方式来获取提交的数据
    在这里插入图片描述
    调用csrf_token这个模板标签,可以解决post的403
    在这里插入图片描述
    在这里插入图片描述

  • values的值每次都不一样
    在这里插入图片描述

  • views.py的部分代码:

      def login(request):
          if request.method == 'POST':
              username = request.POST.get('username','')  #‘’是default的#username对应login.html中的用户名的name‘username’,password也是如此
              password = request.POST.get('password','')
              if username == 'xiaoge' and password == '123456':
                  return redirect(reverse('students:index'))
          return render(request,'students/login.html')
    

request中POST的属性

  • QueryDict类型的对象
  • 包含post请求方式的所有参数
  • 与form表单中的控件对应
  • 表单中控件要有name属性,则name属性的值为键,value属性的值为值,构成键值对提交
  • 对于checkbox控件,name属性一样为一组,当控件被选中后会被提交,存在一键多值的情况

GET和POST请求方式总结

  • GET:GET如其名,是从服务器获取数据,不会更改服务器的状态和数据,在URL中携带参数发送给服务器
  • POST则是将一定量的数据发送给服务器,一般会更改服务器的数据
  • POST方法的参数不能在URL当中看到,它是通过body参数传递给服务器的,所以相对GET方法直接能在URL当中看到传递的参数,显得更加那全一些,当然也不能简单的判定POST方法比GET方法更安全,要使网站保持安全,需要做更多的安全处理

文件上传

  • django在处理文件上传的时候,文件数据被保存在了request.FILES,FILES中的每个键为<input type=“file” name="" />中的name

  • 设置文件的存储路径

    • 在项目根目录下创建upload文件夹

    • 图片上传后会被保存到upload文件夹中

    • 在settings.py文件中添加绝对路径

        UPLOAD_ROOT = os.path.join(BASE_DIR, 'upload')  #添加绝对路径
      
  • upload.py文件代码:

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
      <h1>上传文件</h1>
      <!--FILES只有在请求的方法为POST且提交的<form>带有enctype='multipart/form-data'的情况下才会包含数据,否则,FILES将为一个空的类似于字典的对象-->
      <form action="" method="post" enctype="multipart/form-data">
          <!--这里的name类似于login.html中的,相当于key-->
          <p>请选择你要上传的文件:<input type="file" name="file" multiple></p>
          <p><input type="submit" value="上传"></p>
          <!--csrf_token标签要写在form标签内,不然不起作用-->
          {% csrf_token %}    
      </form>
      </body>
      </html>
    
  • views.py部分代码:

      from django.shortcuts import render,redirect,reverse
      from django.http import HttpResponse
      from django.template.loader import get_template
      from datetime import datetime
      import os
      from django_test.settings import UPLOAD_ROOT
      def upload(request):
          if request.method == 'POST':
              # pass
              files = request.FILES.getlist('file',None)
              for file in files:
                  day_dir = datetime.now().strftime('%Y%m%d')
                  pre_dir = os.path.join(UPLOAD_ROOT,day_dir)
                  if not os.path.exists(pre_dir): #确认pre_dir文件夹存在
                      os.mkdir(pre_dir)
                  filename = os.path.join(pre_dir,file.name)
                  with open(filename,'wb') as f:
                      for line in file.chunks():  #以流的方式读取
                          f.write(line)
              return HttpResponse('上传成功!')
          return render(request, 'students/upload.html')
    

HttpResponse对象

属性

  • content:表示返回的内容,字符串类型
  • charset:表示response采用的编码字符集,字符串类型
  • status_code:响应的HTTP响应状态码
  • content-type:指定输出的MIME类型

方法

  • init:使用页内容实例化HttpResponse对象

  • write(content):以文件的方式写

  • flush():以文件的方式输出缓存区

  • set_cookie(key,value="",max_age=None,expires=None):设置Cookie

  • key,value都是字符串类型

  • max_age是一个整数,表示在指定秒数后过期

  • expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期,注意datetime和timedelta值只有在使用PickleSerializer时才可序列化

  • max_age与expires二选一

  • 如果不指定过期时间,则关闭浏览器就失效

  • delete_cookie(key):删除指定的key的Cookie,如果key不存在则什么也不发生

  • 用shell试验

      (django) xiaoge@zhangqiling:~/PycharmProjects/django/django_test$ python manage.py shell
      Python 3.6.7 (default, Oct 22 2018, 11:32:17) 
      Type 'copyright', 'credits' or 'license' for more information
      IPython 7.3.0 -- An enhanced Interactive Python. Type '?' for help.
      In [1]: from django.http import HttpResponse                                                                                           
      In [2]: response = HttpResponse()                                                                                                      
      In [3]: response = HttpResponse('上传成功')                                                                                            
      In [4]: response.content                                                                                                               
      Out[4]: b'\xe4\xb8\x8a\xe4\xbc\xa0\xe6\x88\x90\xe5\x8a\x9f'
      In [5]: response.content.decode('utf-8')                                                                                               
      Out[5]: '上传成功'
      In [6]: response.charset                                                                                                               
      Out[6]: 'utf-8'
      In [7]: response                                                                                                                       
      Out[7]: <HttpResponse status_code=200, "text/html; charset=utf-8">
      In [8]: response.write('我是')     #可以当做文件句柄,追加                                                                                                    
      In [9]: response.write('一个')                                                                                                         
      In [10]: response.write('!')                                                                                                          
      In [11]: response                                                                                                                      
      Out[11]: <HttpResponse status_code=200, "text/html; charset=utf-8">
      In [12]: response.content.decode('utf-8')                                                                                              
      Out[12]: '上传成功我是一个!'
    
  • views.py文件的部分代码

      from django.http import HttpResponse,JsonResponse
      from students.models import Student
      def students_api(request):
          gender = request.GET.get('gender')  #得到的gender是字符串格式
          gender = int(gender)    #将字符串格式转为整数
          students = Student.objects.values('name','age','gender','phone').filter(gender=gender)
          students = list(students)
          res = {'data':students}
          return JsonResponse(res)
    

在这里插入图片描述

  • 拿到接口后不论是不是js系统都可以进行数据共享
    在这里插入图片描述

HttpResponse的子类

  • 返回数据的响应函数有:
    • HttpResponse() 返回简单的字符串对象
    • render() 渲染模板
    • redirect() 重定向
    • JsonResponse() 返回json数据

JsonResponse

  • 帮助用户创建JSON编码的响应
  • 参数data是字典对象
  • JsonResponse的默认ContentType为application/json

HTTP协议

  • HTTP(超文本传输协议)是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型,HTTP是一个无状态的协议
    在这里插入图片描述

  • views.py部分代码

      from django.http import HttpResponse,JsonResponse
      def students_api(request):
          gender = request.GET.get('gender')  #得到的gender是字符串格式
          gender = int(gender)    #将字符串格式转为整数
          students = Student.objects.values('name','age','gender','phone').filter(gender=gender)
          students = list(students)
          res = {'data':students}
          return JsonResponse(res)
    

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值