5.Django初识

Django

官方文档:https://docs.djangoproject.com/zh-hans/5.0/ref/request-response/#django.http.HttpRequest

安装python

# 安装依赖
yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel gcc

wget https://www.python.org/ftp/python/3.8.15/Python-3.8.15.tgz
tar xf Python-3.8.15.tar.xz
cd Python-3.8.15
./configure --prefix=/usr/local/python3
make && make install

# 删除旧软链接
rm -rf /usr/bin/python3
rm -rf /usr/bin/pip3

# 新添加软链接
ln -s /usr/local/python3/bin/python3.8 /usr/bin/python3
ln -s /usr/local/python3/bin/pip3.8 /usr/bin/pip3

# 修改yum运行环境
vi /usr/bin/yum
vi /usr/libexec/urlgrabber-ext-down
按i进入编辑模式,在第一行
#!/usr/bin/python把修改为#!/usr/bin/python2.7

pip加速

cd ~
mkdir .pip
vi .pip/pip.conf
# 增加如下内容
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = pypi.tuna.tsinghua.edu.cn

安装Django

pip3 install django

# 新版跟老版不太一样,需要自己设置软链接
ln -s /usr/local/python3/bin/django-admin /usr/bin/django-admin

# 创建web项目: django-admin startproject 项目名称
django-admin startproject myweb

# Django项目目录
web
├── db.sqlite3
├── manage.py           # 项目的管理,包括: 启动项目,创建app, 数据管理
└── web
    ├── asgi.py         # 接收网络请求
    ├── __init__.py
    ├── settings.py     # 项目配置(模板配置,数据库配置,注册app)
    ├── urls.py         # url和函数的对应关系
    └── wsgi.py         # 接收网络请求

# 添加新的app
cd myweb;django-admin startapp blog
cd myweb;python manage.py startapp blog
# app目录
blog/
├── admin.py    # 映射models中的数据到Django自带的admin后台
├── apps.py     # 在新的Django版本中新增,用于应用程序的配置
├── __init__.py
├── migrations    # 用于记录models中数据的变更记录
│   └── __init__.py
├── models.py   # 创建应用程序数据表模型(对应数据库的相关操作)
├── tests.py    # 创建Django测试
└── views.py    # 控制向前端显示那些数据

# app注册
vi myweb/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog.apps.BlogConfig',   # 或直接appname  blog
]

快速上手

  • 编辑myweb/blog 下的views.py 视图函数
    from django.shortcuts import render
    from django.http import HttpResponse
    def index_app(req):
      return HttpResponse('welcome to Django blog!')
  • 编辑myweb/web 下的urls.py 来指定访问路由

    from django.contrib import admin
    from django.urls import path
    from blog.views import index_app
    
    urlpatterns = [
      path('admin/', admin.site.urls),
      path('index_app/', views.index_app),
    ]
  • 命令行启动Django应用

    cd myweb/
    python manage.py runserver
    python3 manage.py runserver 0.0.0.0:8888
    
    # windows
    cd myweb/
    python manage.py runserver
    python.exe manage.py runserver 0.0.0.0:8888
    
    # 报错 You have 18 unapplied migration(s)
    python.exe manage.py migrate

templates模板

为了使用HTML,这里开始引入templates模板

注意: 可以在app下创建templates目录,也可以在主目录下创建templates目录

如果 setting.py 配置TEMPLATES DIRS: [os.path.join(BASE_DIR, 'templates')] 会从项目根目录templates寻找html

如果没有配置DIRS,则根据app的注册顺序,在每个app下的templates目录中寻找

图片、js、css 静态文件需放在app目录下的static目录,可以修改setting.py里STATIC_URL配置

Django html 静态文件引入:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>user_list</title>
    {% load static %}
    <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}" />
  </head>
  <body>
    <h1>用户列表 new</h1>

    <img src="{% static 'img/haha.png' %}" style="height: 200px;" alt="" />

    <script src="{% static 'js/jquery-3.7.1.min.js' %}"></script>
    <script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
  </body>
</html>

单一变量

def tpl(request):
    name = "poker"
    return render(request, "tpl.html", {"name":name})
<body>
    <h1>templates模板语法</h1>
    <li>姓名: {{ name }}</li>
</body>

列表

def tpl(request):
    name = "tpl模板语法学习"
    my_list = ['好好', '学习', '天天', '向上']
    return render(request, "tpl.html", {"name":name, "roles_list":roles_list})
<body>
    <h1>templates模板语法</h1>
    <h2 class="btn btn-lg">{{ name }}</h2>
    <div>
      <h3> 列表 my_list </h3>
      <li>{{ my_list }}</li>
      <li>{{ my_list.0 }}</li>
      <li>{{ my_list.1 }}</li>
      <li>{{ my_list.2 }}</li>
      <li>{{ my_list.3 }}</li>
    </div>
</body>
  • 循环(列表)
<body>
    <div>
      {% for item in my_list %}
        <span>{{ item }}</span>
      {% endfor %}
    </div>
</body>

字典

def tpl(req):
    name = "tpl模板语法学习"
    my_list = ['好好', '学习', '天天', '向上']
    my_dict = {"name": "tang", "age": 18}
    return render(req, "tpl.html", {"name": name, "my_list": my_list, "my_dict": my_dict})
<div>
  <h3> 字典 my_dict </h3>
  {{ my_dict.name }}
  {{ my_dict.age }}
  <h4>字典 for 循环</h4>
  {% for k in my_dict.keys %}
    <li>{{ k }}</li>
  {% endfor %}
  {% for v in my_dict.values %}
    <li>{{ v }}</li>
  {% endfor %}
  {% for k,v in my_dict.items %}
    <li>{{ k }}: {{ v }}</li>
  {% endfor %}
</div>

列表套字典

def tpl(req):
    name = "tpl模板语法学习"
    my_list = ['好好', '学习', '天天', '向上']
    my_dict = {"name": "tang", "age": 18}
    data_list = [
        {"name": "张三", "age": 25, "sex": "男"},
        {"name": "李四", "age": 18, "sex": "男"},
        {"name": "王五", "age": 22, "sex": "女"},
    ]
    return render(req, "tpl.html", {"name": name, "my_list": my_list, "my_dict": my_dict, "data_list": data_list})
  <div>
    <h3>列表套字典</h3>
    <div>
      {{ data_list.1.name }}
      {{ data_list.1.age }}
      {{ data_list.1.sex }}
      <h3>列表套字典for循环</h3>
      {% for item in data_list %}
          <div>{{ item.name }} {{ item.age }} {{ item.sex }}</div>
      {% endfor %}
    </div>
  </div>

条件判断

{%  if name == "poker" %}
    <h3>嘿嘿嘿</h3>
{% elif name == "toker" %}
    <h3>哈哈哈</h3>
{% else %}
    <h3>呵呵呵</h3>
{% endif %}

templates 模板语法案例

def news(req):
    import requests
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0"
    }
    r = requests.get(
        "http://ccdb.hemiola.com/characters/radicals/85", headers=headers)
    data_list = r.json()
    # print(data_list)
    # print(r.status_code)
    # print(r.headers['content-type'])
    # print(r.text)

    return render(req, 'news.html', {"data_list": data_list})
  <div class="container-fluid haha">
  <hr></hr>
    <h3>data_list</h3>
    <ul>
      {% for items in data_list %}
      <li>{{ items.string }}</li>
      {% endfor %}
    </ul>
  </div>

请求、响应、重定向

浏览器向某个网站发送请求,网站返回给浏览器一个新的URL,浏览器去访问这个新的URL地址

def something(req):
    # req 是一个对象,封闭了用户发送过来的所有请求相关数据
    # 获取用户请求方式
    print(req.method)
    # 获取URL上传递的值  /something/?n1=888&n2=999
    print(req.GET)    # <QueryDict: {'n1': ['888'], 'n2': ['999']}>
    # 通过请求体中提交数据
    print(req.POST)

    # [响应] 内容字符串内容返回给请求者
    # return HttpResponse("hahaha")

    # [响应] 读取HTML的内容 + 渲染(替换) --> 字符串,返回给用户浏览器
    # return render(req, 'something.html', {'title': "something"})

    # [响应] 让浏览器重定向到其他页面
    return redirect("https://baidu.com")

案例: 用户登录

def login(req):
    if req.method == "GET":
        return render(req, 'login.html')
    else:
        # 如果是POST请求,获取用户提交的数据
        print(req.POST)
        data_dict = req.POST
        user = data_dict["user"]
        password = data_dict["password"]
        print(user,password)
        if user == "tang" and password == "123":
            return HttpResponse("登录成功!")
        else:
            #return HttpResponse("登录失败")
            return render(req, "login.html", {"error_msg": "用户名或密码错误"})
<div class="container-fluid haha">
<hr></hr>
<h1>用户登录</h1>
<form method="post" action="/login/">
    <!-- Django访问token校验 -->
    {% csrf_token %}

    <input type="text" name="user", placeholder="用户名">
    <input type="password" name="password", placeholder="密码">
    <input type="submit" value="提交"> 
    <span style="color: red;">{{ error_msg }}</span>
</form>
</div>

数据库操作

Django开发操作数据库更简单,内部提供了ORM框架

  • ORM可以帮助我们做两件事:

    • 创建/修改/删除数据库中的表(不用写sql语句,但无法创建数据库)
    • 操作表中的数据(不用写sql语句)
  • 环境:

    • yum -y install mysql-devel
    • yum -y install python-devel
    • pip3 install mysqlclient
  • 修改setting.py 配置数据连接参数
  DATABASES = {
      'default':{
          'ENGINE':'django.db.backends.mysql',
          'NAME':'py_sql',
          'USER':'xxxx',
          'PASSWORD':'xxxx',
          'HOST':'home.vimll.com',
          'PORT':xxxx,
      }
  }
  • 创建表 修改models.py 增加所创建表相关数据
  class UserInfo(models.Model):
      name = models.CharField(max_length=32)
      password = models.CharField(max_length=64)
      age = models.IntegerField()
      info = models.CharField(max_length=64, default="0")
      # test = models.IntegerField(default=0)     # 注释后 运行命名后删除该字段
      # data = models.IntegerField(null=True,blank=True)

  """上述类会自动生成sql语句
  create table blog_UserInfo(     # 默认会在表名前面加上app name
      id bigint auto_increment primary key,
      name varchar(20),
      password varchar(20),
      age int
  )
  """
  class UserInfo(models.Model):
      class Meta:
        db_table = 'UserInfo'      # 则表名不加app name 表名为:UserInfo
  • 创建库表(进入工程目录):库表名makemigrations

    • python manage.py makemigrations
  • 执行库表建立(进入工程目录):

    • python manage.py migrate
  • 修改表的话,如果原表中存有数据,此时如果增加一个新的列,需要设定一个默认值

    • 手动设定 age = models.IntegerField(default=2)
    • 允许为空 data = models.IntegerField(null=True, blank=True)
  • 使用已存在的库表,反向生成models.py

    • python manage.py inspectdb [表名] # 不写表名默认生成所有表

Django models 参数

建表字段参数
1、models.AutoField  自增列 = int(11)
  如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
2、models.CharField  字符串字段
  必须 max_length 参数
3、models.BooleanField  布尔类型=tinyint(1)
  不能为空,Blank=True
4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar
  继承CharField,所以必须 max_lenght 参数
5、models.DateField  日期类型 date
  对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
6、models.DateTimeField  日期类型 datetime
  同DateField的参数
7、models.Decimal  十进制小数类型 = decimal
  必须指定整数位max_digits和小数位decimal_places
8、models.EmailField  字符串类型(正则表达式邮箱) =varchar
  对字符串进行正则表达式
9、models.FloatField  浮点类型 = double
10、models.IntegerField  整形
11、models.BigIntegerField  长整形
  integer_field_ranges = {
    ‘SmallIntegerField‘: (-32768, 32767),
    ‘IntegerField‘: (-2147483648, 2147483647),
    ‘BigIntegerField‘: (-9223372036854775808, 9223372036854775807),
    ‘PositiveSmallIntegerField‘: (0, 32767),
    ‘PositiveIntegerField‘: (0, 2147483647),
  }
12、models.IPAddressField  字符串类型(ip4正则表达式)
13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)
  参数protocol可以是:both、ipv4、ipv6
  验证时,会根据设置报错
14、models.NullBooleanField  允许为空的布尔类型
15、models.PositiveIntegerFiel  正Integer
16、models.PositiveSmallIntegerField  正smallInteger
17、models.SlugField  减号、下划线、字母、数字
18、models.SmallIntegerField  数字
  数据库中的字段有:tinyint、smallint、int、bigint
19、models.TextField  字符串=longtext
20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]]
21、models.URLField  字符串,地址正则表达式
22、models.BinaryField  二进制
23、models.ImageField   图片
24、models.FilePathField 文件

字段传参
1、null=True
  数据库中字段是否可以为空
2、blank=True
  django的 Admin 中添加数据时是否可允许空值
3、primary_key = False
  主键,对AutoField设置主键后,就会代替原来的自增 id 列
4、auto_now 和 auto_now_add
  auto_now   自动创建---无论添加或修改,都是当前操作的时间
  auto_now_add  自动创建---永远是创建时的时间
5、choices
GENDER_CHOICE = (
        (u‘M‘, u‘Male‘),
        (u‘F‘, u‘Female‘),
    )
gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
6、max_length
7、default  默认值
8、verbose_name  Admin中字段的显示名称
9、name|db_column  数据库中的字段名称
10、unique=True  不允许重复
11、db_index = True  数据库索引
12、editable=True  在Admin里是否可编辑
13、error_messages=None  错误提示
14、auto_created=False  自动创建
15、help_text  在Admin中提示帮助信息
16、validators=[]
17、upload-to

Django操作表数据

  • 添加数据

    def orm(req):
      # 测试ORM操作表中的数据
      # 表新建数据
      UserInfo.objects.create(name="tang", password="123", age=18, info="haha")
      UserInfo.objects.create(name="tang2", password="1234", age=18, info="haha2")
      UserInfo.objects.create(name="tang3", password="1235", age=18, info="haha3")
    
      return HttpResponse("哈哈哈")
  • 删除数据
    # 删除数据
    # UserInfo.objects.all().delete()   # 清空表
    UserInfo.objects.filter(id=3).delete()
  • 获取数据

    # 获取数据
    data_list = UserInfo.objects.all()  
    # print(data_list)   # <QuerySet [<UserInfo: UserInfo object (1)>, <UserInfo: UserInfo object (2)>]>
    for obj in data_list:
      print(obj.id, obj.name, obj.password, obj.age, obj.info)
    
    # 获取一条数据
    row_obj = UserInfo.objects.filter(id=2).first()  # 拿到一行数据
    # print(row_obj)   # UserInfo object (2)
    print(row_obj.id, row_obj.name, row_obj.password, row_obj.age, row_obj.info)
  • 更新数据
    # 更新数据
    UserInfo.objects.all().update(info="哈哈")   # 更新所有行数据
    # 更新所筛选的数据
    UserInfo.objects.filter(id=2).update(info="哈哈哈",password="123456")

案例-用户管理

用户列表

# urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index_app/', index_app),
    path('user_list/', user_list),
    path('user_add/', user_add),
    path('', tpl),
    path('news/', news),
    path('something/', something),
    path('login/', login),
    path('orm/', orm),

    # 案例 用户列表
    path('info_list/', info_list),
]

# views.py
def info_list(req):
    info_list = UserInfo.objects.all()
    return render(req,'info_list.html',{"info_list": info_list})
<!-- info_list.html -->
    <h3>info_list用户列表</h3>
    <table border="1">
      <thead>
        <tr>
          <th>ID</th>
          <th>姓名</th>
          <th>密码</th>
          <th>年龄</th>
          <th>备注</th>
        </tr>
      </thead>
      <tbody>
        {% for items in info_list %}
        <tr>
          <td>{{ items.id }}</td>
          <td>{{ items.name }}</td>
          <td>{{ items.password }}</td>
          <td>{{ items.age }}</td>
          <td>{{ items.info }}</td>
        </tr>
        {% endfor %}
      </tbody>
    </table>

添加用户

def info_add(req):
    if req.method == "GET":
        return render(req, 'info_add.html')
    else:
        # 如果是POST请求,获取用户提交的数据
        # print(req.POST)
        data_dict = req.POST
        name = data_dict["name"]
        password = data_dict["password"]
        age = data_dict["age"]
        info = data_dict["info"]
        print(name, password, age, info)

        UserInfo.objects.create(name=name, password=password, age=age, info=info)

        # return redirect("http://127.0.0.1:8000/info_list/")
        return redirect("/info_list/")
    <h1>info_add添加用户</h1>
    <form method="post" action="/info_add/">

        {% csrf_token %}

        <input type="text" name="name", placeholder="用户名">
        <input type="password" name="password", placeholder="密码">
        <input type="number" name="age", placeholder="年龄">
        <input type="text" name="info", placeholder="备注">
        <input type="submit" value="提交"> 
        <span style="color: red;">{{ error_msg }}</span>
    </form>

删除用户

def info_del(req):
    nid = req.GET.get("nid")
    print(nid)
    UserInfo.objects.filter(id=nid).delete()
    return redirect("/info_list/")
    <table border="1" style="margin-top: 20px;">
      <thead>
        <tr>
          <th>ID</th>
          <th>姓名</th>
          <th>密码</th>
          <th>年龄</th>
          <th>备注</th>
          <th>用户操作</th>
        </tr>
      </thead>
      <tbody>
        {% for items in info_list %}
        <tr>
          <td>{{ items.id }}</td>
          <td>{{ items.name }}</td>
          <td>{{ items.password }}</td>
          <td>{{ items.age }}</td>
          <td>{{ items.info }}</td>
          <td><a href="/info_del/?nid={{ items.id }}">删除</a></td>
        </tr>
        {% endfor %}
      </tbody>
    </table>