Django开发

Django开发(一)

主题:员工管理系统

1.新建项目

Django开发_第1张图片

Django开发_第2张图片

2.创建app

python manage.py startapp app01

Django开发_第3张图片

注册app:

Django开发_第4张图片

3.设计表结构(django)

Django开发_第5张图片

Django开发_第6张图片

from django.db import models


class Department(models.Model):
    """ 部门表 """
    title = models.CharField(verbose_name='标题', max_length=32)


class UserInfo(models.Model):
    """ 员工表 """
    name = models.CharField(verbose_name="姓名", max_length=16)
    password = models.CharField(verbose_name="密码", max_length=64)
    age = models.IntegerField(verbose_name="年龄")
    account = models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)
    create_time = models.DateTimeField(verbose_name="入职时间")

    # 无约束
    # depart_id = models.BigIntegerField(verbose_name="部门ID")
    # 1.有约束
    #   - to,与那张表关联
    #   - to_field,表中的那一列关联
    # 2.django自动
    #   - 写的depart
    #   - 生成数据列 depart_id
    # 3.部门表被删除
    # ### 3.1 级联删除
    depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
    # ### 3.2 置空
    # depart = models.ForeignKey(to="Department", to_field="id", null=True, blank=True, on_delete=models.SET_NULL)

    # 在django中做的约束
    gender_choices = (
        (1, "男"),
        (2, "女"),
    )
    gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)

4.在MySQL中生成表

  • 工具连接MySQL生成数据库。

    create database gx_day16 DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
    
  • 修改配置文件,连接MySQL

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'gx_day16',  # 数据库名字
            'USER': 'root',
            'PASSWORD': 'root123',
            'HOST': '127.0.0.1',  # 那台机器安装了MySQL
            'PORT': 3306,
        }
    }
    

    Django开发_第7张图片

  • django命令生成数据库表

    python manage.py makemigrations
    python manage.py migrate
    

使用pycharm自带的tools工具,run manage.py Task Django开发_第8张图片

表结构创建成功:

Django开发_第9张图片

5.静态文件管理

static目录

Django开发_第10张图片

6.部门管理

体验,最原始方法来做。

Django中提供Form和ModelForm组件(方便)

Django开发_第11张图片

7.模板的继承

  • 部门列表
  • 添加部门
  • 编辑部门

定义母模版:layout.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <link rel="stylesheet" href="{% static 'plugin...min.css' %}">
    {% block css %}{% endblock %}
head>
<body>
    <h1>标题h1>
    <div>
        {% block content %}{% endblock %}
    div>
    <h1>底部h1>
    
    <script src="{% static 'js/jquery-3.6.0.min.js' %}">script>
    {% block js %}{% endblock %}
body>
html>

继承母版:

{% extends 'layout.html' %}

{% block css %}
	<link rel="stylesheet" href="{% static 'pluxxx.css' %}">
	<style>
		...
	style>
{% endblock %}


{% block content %}
    <h1>首页h1>
{% endblock %}


{% block js %}
	<script src="{% static 'js/jqxxxin.js' %}">script>
{% endblock %}

8.用户管理

insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("韩超","666",23,100.68,"2020-01-11",2,1);

insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("刘东","123",23,100.68,"2010-11-11",1,4);

insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("朱虎飞","999",33,9900.68,"2021-05-11",1,1);
+-------------+---------------+------+-----+---------+----------------+
| Field       | Type          | Null | Key | Default | Extra          |
+-------------+---------------+------+-----+---------+----------------+
| id          | bigint(20)    | NO   | PRI | NULL    | auto_increment |
| name        | varchar(16)   | NO   |     | NULL    |                |
| password    | varchar(64)   | NO   |     | NULL    |                |
| age         | int(11)       | NO   |     | NULL    |                |
| account     | decimal(10,2) | NO   |     | NULL    |                |
| create_time | datetime(6)   | NO   |     | NULL    |                |
| gender      | smallint(6)   | NO   |     | NULL    |                |
| depart_id   | bigint(20)    | NO   | MUL | NULL    |                |
+-------------+---------------+------+-----+---------+----------------+

Django开发_第12张图片

新建用户:

  • 原始方式理思路:不会采用(本质)【麻烦】

    - 用户提交数据没有校验。
    - 错误,页面上应该有错误提示。
    - 页面上,没一个字段都需要我们重新写一遍。     [OK]
    - 关联的数据,手动去获取并展示循环展示在页面。  [OK]
    
  • Django组件

    • Form组件(小简便)
    • ModelForm组件(最简便)

8.1 初识Form

1. views.py
class MyForm(Form):
    user = forms.CharField(widget=forms.Input)
    pwd = form.CharFiled(widget=forms.Input)
    email = form.CharFiled(widget=forms.Input)
    account = form.CharFiled(widget=forms.Input)
    create_time = form.CharFiled(widget=forms.Input)
    depart = form.CharFiled(widget=forms.Input)
    gender = form.CharFiled(widget=forms.Input)


def user_add(request):
    if request.method == "GET":
        form = MyForm()
        return render(request, 'user_add.html',{"form":form})
2.user_add.html
<form method="post">
    {% for field in form%}
    	{{ field }}
    {% endfor %}
    
form>
<form method="post">
    {{ form.user }}
    {{ form.pwd }}
    {{ form.email }}
    
form>

8.3 ModelForm(推荐)

0. models.py
class UserInfo(models.Model):
    """ 员工表 """
    name = models.CharField(verbose_name="姓名", max_length=16)
    password = models.CharField(verbose_name="密码", max_length=64)
    age = models.IntegerField(verbose_name="年龄")
    account = models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)
    create_time = models.DateTimeField(verbose_name="入职时间")
    depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
    gender_choices = (
        (1, "男"),
        (2, "女"),
    )
    gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
1. views.py
class MyForm(ModelForm):
    xx = form.CharField*("...")
    class Meta:
        model = UserInfo
        fields = ["name","password","age","xx"]


def user_add(request):
    if request.method == "GET":
        form = MyForm()
        return render(request, 'user_add.html',{"form":form})
2.user_add.html
<form method="post">
    {% for field in form%}
    	{{ field }}
    {% endfor %}
    
form>
<form method="post">
    {{ form.user }}
    {{ form.pwd }}
    {{ form.email }}
    
form>

Django开发(二)

  • 部门管理

  • 用户管理

    • 用户列表

    • 新建用户

      - ModelForm,针对数据库中的某个表。
      - Form。
      

8.4 编辑用户

  • 点击编辑,跳转到编辑页面(将编辑行的ID携带过去)。

  • 编辑页面(默认数据,根据ID获取并设置到页面中)

  • 提交:

    • 错误提示

    • 数据校验

    • 在数据库更新

      models.UserInfo.filter(id=4).update(...)
      

8.5 删除

见代码。

9.靓号管理

9.1 表结构

Django开发_第13张图片

根据表结构的需求,在models.py中创建类(由类生成数据库中的表)。

class PrettyNum(models.Model):
    """ 靓号表 """
    mobile = models.CharField(verbose_name="手机号", max_length=11)
    # 想要允许为空 null=True, blank=True
    price = models.IntegerField(verbose_name="价格", default=0)

    level_choices = (
        (1, "1级"),
        (2, "2级"),
        (3, "3级"),
        (4, "4级"),
    )
    level = models.SmallIntegerField(verbose_name="级别", choices=level_choices, default=1)

    status_choices = (
        (1, "已占用"),
        (2, "未使用")
    )
    status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=2)

自己在数据模拟创建一些数据:

insert into app01_prettynum(mobile,price,level,status)values("111111111",19,1,1);
mysql> select * from app01_prettynum;
+----+-----------+-------+-------+--------+
| id | mobile    | price | level | status |
+----+-----------+-------+-------+--------+
|  1 | 111111111 |    19 |     1 |      1 |
|  2 | 111111111 |    19 |     1 |      1 |
|  3 | 111111111 |    19 |     1 |      1 |
|  4 | 111111111 |    19 |     1 |      1 |
+----+-----------+-------+-------+--------+
4 rows in set (0.01 sec)

9.2 靓号列表

  • URL

  • 函数

    • 获取所有的靓号

    • 结合html+render将靓号罗列出来

      id	号码	价格	级别(中文)	状态(中文)
      

9.3 新建靓号

  • 列表点击跳转:/pretty/add/

  • URL

  • ModelForm类

    from django import forms
    
    class PrettyModelForm(forms.ModelForm):
    	...
    
  • 函数

    • 实例化类的对象
    • 通过render将对象传入到HTML中。
    • 模板的循环展示所有的字段。
  • 点击提交

    • 数据校验
    • 保存到数据库
    • 跳转回靓号列表
      Django开发_第14张图片

9.4 编辑靓号

  • 列表页面:/pretty/数字/edit/
  • URL
  • 函数
    • 根据ID获取当前编辑的对象
    • ModelForm配合,默认显示数据。
    • 提交修改。

Django开发_第15张图片

不允许手机号重复。

  • 添加:【正则表达式】【手机号不能存在】

    # [obj,obj,obj]
    queryset = models.PrettyNum.objects.filter(mobile="1888888888")
    
    obj = models.PrettyNum.objects.filter(mobile="1888888888").first()
    
    # True/False
    exists = models.PrettyNum.objects.filter(mobile="1888888888").exists()
    
  • 编辑:【正则表达式】【手机号不能存在】

    排除自己以外,其他的数据是否手机号是否重复?
    
    # id!=2 and mobile='1888888888'
    models.PrettyNum.objects.filter(mobile="1888888888").exclude(id=2)
    

9.5 搜索手机号

models.PrettyNum.objects.filter(mobile="19999999991",id=12)

data_dict = {"mobile":"19999999991","id":123}
models.PrettyNum.objects.filter(**data_dict)
models.PrettyNum.objects.filter(id=12)       # 等于12
models.PrettyNum.objects.filter(id__gt=12)   # 大于12
models.PrettyNum.objects.filter(id__gte=12)  # 大于等于12
models.PrettyNum.objects.filter(id__lt=12)   # 小于12
models.PrettyNum.objects.filter(id__lte=12)  # 小于等于12

data_dict = {"id__lte":12}
models.PrettyNum.objects.filter(**data_dict)
models.PrettyNum.objects.filter(mobile="999")               # 等于
models.PrettyNum.objects.filter(mobile__startswith="1999")  # 筛选出以1999开头
models.PrettyNum.objects.filter(mobile__endswith="999")     # 筛选出以999结尾
models.PrettyNum.objects.filter(mobile__contains="999")     # 筛选出包含999

data_dict = {"mobile__contains":"999"}
models.PrettyNum.objects.filter(**data_dict)

9.6 分页

queryset = models.PrettyNum.objects.all()

queryset = models.PrettyNum.objects.filter(id=1)[0:10]


# 第1页
queryset = models.PrettyNum.objects.all()[0:10]

# 第2页
queryset = models.PrettyNum.objects.all()[10:20]

# 第3页
queryset = models.PrettyNum.objects.all()[20:30]
data = models.PrettyNum.objects.all().count()
data = models.PrettyNum.objects.filter(id=1).count()
  • 分页的逻辑和处理规则

  • 封装分页类

    • 从头到尾开发
    • 写项目用【pagination.py】公共组件。
  • 小Bug,搜索 + 分页情况下。

    分页时候,保留原来的搜索条件
    
    http://127.0.0.1:8000/pretty/list/?q=888
    http://127.0.0.1:8000/pretty/list/?page=1
    
    http://127.0.0.1:8000/pretty/list/?q=888&page=23
    

10.时间插件
















11.ModelForm和BootStrap

  • ModelForm可以帮助我们生成HTML标签。

    class UserModelForm(forms.ModelForm):
        class Meta:
            model = models.UserInfo
            fields = ["name", "password",]
    
    form = UserModelForm()
    
    {{form.name}}      普通的input框
    {{form.password}}  普通的input框
    
  • 定义插件

    class UserModelForm(forms.ModelForm):
        class Meta:
            model = models.UserInfo
            fields = ["name", "password",]
            widgets = {
                "name": forms.TextInput(attrs={"class": "form-control"}),
                "password": forms.PasswordInput(attrs={"class": "form-control"}),
                "age": forms.TextInput(attrs={"class": "form-control"}),
            }
    
    class UserModelForm(forms.ModelForm):
        name = forms.CharField(
            min_length=3,
            label="用户名",
            widget=forms.TextInput(attrs={"class": "form-control"})
        )
    
        class Meta:
            model = models.UserInfo
            fields = ["name", "password", "age"]
    
    {{form.name}}      BootStrap的input框
    {{form.password}}  BootStrap的input框
    
  • 重新定义的init方法,批量设置

    class UserModelForm(forms.ModelForm):
        class Meta:
            model = models.UserInfo
            fields = ["name", "password", "age",]
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            
            # 循环ModelForm中的所有字段,给每个字段的插件设置
            for name, field in self.fields.items():
    			field.widget.attrs = {
                    "class": "form-control", 
                    "placeholder": field.label
                }
    
    class UserModelForm(forms.ModelForm):
        class Meta:
            model = models.UserInfo
            fields = ["name", "password", "age",]
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            
            # 循环ModelForm中的所有字段,给每个字段的插件设置
            for name, field in self.fields.items():
                # 字段中有属性,保留原来的属性,没有属性,才增加。
                if field.widget.attrs:
    				field.widget.attrs["class"] = "form-control"
    				field.widget.attrs["placeholder"] = field.label
                else:
                    field.widget.attrs = {
                        "class": "form-control", 
                        "placeholder": field.label
                    }
    
    class UserEditModelForm(forms.ModelForm):
        class Meta:
            model = models.UserInfo
            fields = ["name", "password", "age",]
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            
            # 循环ModelForm中的所有字段,给每个字段的插件设置
            for name, field in self.fields.items():
                # 字段中有属性,保留原来的属性,没有属性,才增加。
                if field.widget.attrs:
    				field.widget.attrs["class"] = "form-control"
    				field.widget.attrs["placeholder"] = field.label
                else:
                    field.widget.attrs = {
                        "class": "form-control", 
                        "placeholder": field.label
                    }
    
  • 自定义类

    class BootStrapModelForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            # 循环ModelForm中的所有字段,给每个字段的插件设置
            for name, field in self.fields.items():
                # 字段中有属性,保留原来的属性,没有属性,才增加。
                if field.widget.attrs:
    				field.widget.attrs["class"] = "form-control"
    				field.widget.attrs["placeholder"] = field.label
                else:
                    field.widget.attrs = {
                        "class": "form-control", 
                        "placeholder": field.label
                    }
    
    class UserEditModelForm(BootStrapModelForm):
        class Meta:
            model = models.UserInfo
            fields = ["name", "password", "age",]
    

操作

  • 提取公共的类

    Django开发_第16张图片

    Django开发_第17张图片

  • ModelForm拆分出来
    Django开发_第18张图片

  • 视图函数的归类

12. 管理员操作

Django开发_第19张图片

13. 用户登录

http无状态短连接:

Django开发_第20张图片

什么是cookie和session?

http://127.0.0.1:8000/admin/list/
https://127.0.0.1:8000/admin/list/

Django开发_第21张图片

13.1 登录

登录成功后:

  • cookie,随机字符串
  • session,用户信息

在其他需要登录才能访问的页面中,都需要加入:

def index(request):
    info = request.session.get("info")
    if not info:
        return redirect('/login/')
    
    ...

目标:在18个视图函数前面统一加入判断。(过于繁琐–> 使用中间件)

info = request.session.get("info")
if not info:
    return redirect('/login/')

13.2 中间件的体验

Django开发_第22张图片

  • 定义中间件

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class M1(MiddlewareMixin):
        """ 中间件1 """
    
        def process_request(self, request):
    
            # 如果方法中没有返回值(返回None),继续向后走
            # 如果有返回值 HttpResponse、render 、redirect
            print("M1.process_request")
            return HttpResponse("无权访问")
    
        def process_response(self, request, response):
            print("M1.process_response")
            return response
    
    
    class M2(MiddlewareMixin):
        """ 中间件2 """
    
        def process_request(self, request):
            print("M2.process_request")
    
        def process_response(self, request, response):
            print("M2.process_response")
            return response
    
  • 应用中间件 setings.py

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'app01.middleware.auth.M1',
        'app01.middleware.auth.M2',
    ]
    
  • 在中间件的process_request方法

    # 如果方法中没有返回值(返回None),继续向后走
    # 如果有返回值 HttpResponse、render 、redirect,则不再继续向后执行。
    

13.3 中间件实现登录校验

  • 编写中间件

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse, redirect
    
    
    class AuthMiddleware(MiddlewareMixin):
    
        def process_request(self, request):
            # 0.排除那些不需要登录就能访问的页面
            #   request.path_info 获取当前用户请求的URL /login/
            if request.path_info == "/login/":
                return
    
            # 1.读取当前访问的用户的session信息,如果能读到,说明已登陆过,就可以继续向后走。
            info_dict = request.session.get("info")
            print(info_dict)
            if info_dict:
                return
    
            # 2.没有登录过,重新回到登录页面
            return redirect('/login/')
    
  • 应用中间件

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'app01.middleware.auth.AuthMiddleware',
    ]
    

13.4 注销

def logout(request):
    """ 注销 """

    request.session.clear()

    return redirect('/login/')

13.5 当前用户

14.图片验证码

Django开发_第23张图片

14.1 生成图片

pip install pillow
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter


def check_code(width=120, height=30, char_length=5, font_file='Monaco.ttf', font_size=28):
    code = []
    img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')

    def rndChar():
        """
        生成随机字母
        :return:
        """
        return chr(random.randint(65, 90))

    def rndColor():
        """
        生成随机颜色
        :return:
        """
        return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))

    # 写文字
    font = ImageFont.truetype(font_file, font_size)
    for i in range(char_length):
        char = rndChar()
        code.append(char)
        h = random.randint(0, 4)
        draw.text([i * width / char_length, h], char, font=font, fill=rndColor())

    # 写干扰点
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())

    # 写干扰圆圈
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())

    # 画干扰线
    for i in range(5):
        x1 = random.randint(0, width)
        y1 = random.randint(0, height)
        x2 = random.randint(0, width)
        y2 = random.randint(0, height)

        draw.line((x1, y1, x2, y2), fill=rndColor())

    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
    return img, ''.join(code)


if __name__ == '__main__':
    img, code_str = check_code()
    print(code_str)

    with open('code.png', 'wb') as f:
        img.save(f, format='png')

15. Ajax请求

浏览器向网站发送请求时:URL 和 表单的形式提交。

  • GET
  • POST

特点:页面刷新。

除此之外,也可以基于Ajax向后台发送请求(偷偷的发送请求)。

  • 依赖jQuery

  • 编写ajax代码

    $.ajax({
        url:"发送的地址",
        type:"get",
        data:{
            n1:123,
            n2:456
        },
        success:function(res){
            console.log(res);
        }
    })
    

15.1 GET请求

$.ajax({
    url: '/task/ajax/',
    type: "get",
    data: {
        n1: 123,
        n2: 456
    },
    success: function (res) {
        console.log(res);
    }
})
from django.shortcuts import render, HttpResponse

def task_ajax(request):
    print(request.GET)
    return HttpResponse("成功了")

15.2 POST请求

$.ajax({
    url: '/task/ajax/',
    type: "get",
    data: {
        n1: 123,
        n2: 456
    },
    success: function (res) {
        console.log(res);
    }
})
from django.shortcuts import render, HttpResponse
from django.views.decorators.csrf import csrf_exempt


@csrf_exempt
def task_ajax(request):
    print(request.GET)
    print(request.POST)
    return HttpResponse("成功了")

15.3 关闭绑定事件

{% extends 'layout.html' %}


{% block content %}
    <div class="container">
        <h1>任务管理h1>

        <h3>示例1h3>
        <input id="btn1" type="button" class="btn btn-primary" value="点击"/>

    div>
{% endblock %}

{% block js %}
    <script type="text/javascript">
        $(function () {
            // 页面框架加载完成之后代码自动执行
            bindBtn1Event();

        })

        function bindBtn1Event() {
            $("#btn1").click(function () {
                $.ajax({
                    url: '/task/ajax/',
                    type: "post",
                    data: {
                        n1: 123,
                        n2: 456
                    },
                    success: function (res) {
                        console.log(res);
                    }
                })
            })
        }

    script>
{% endblock %}

15.4 ajax请求的返回值

一般都会返回JSON格式。

{% extends 'layout.html' %}


{% block content %}
    <div class="container">
        <h1>任务管理h1>

        <h3>示例1h3>
        <input id="btn1" type="button" class="btn btn-primary" value="点击"/>

    div>
{% endblock %}

{% block js %}
    <script type="text/javascript">
        $(function () {
            // 页面框架加载完成之后代码自动执行
            bindBtn1Event();

        })

        function bindBtn1Event() {
            $("#btn1").click(function () {
                $.ajax({
                    url: '/task/ajax/',
                    type: "post",
                    data: {
                        n1: 123,
                        n2: 456
                    },
                    dataType: "JSON",
                    success: function (res) {
                        console.log(res);
                        console.log(res.status);
                        console.log(res.data);
                    }
                })
            })
        }

    script>
{% endblock %}
import json
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt


def task_list(request):
    """ 任务列表 """
    return render(request, "task_list.html")


@csrf_exempt
def task_ajax(request):
    print(request.GET)
    print(request.POST)

    data_dict = {"status": True, 'data': [11, 22, 33, 44]}
    return HttpResponse(json.dumps(data_dict))

Django开发(三)

知识点的回顾:

  • 安装Django

    pip install django
    
  • 创建Django项目

    >>> django-admin startproject mysite
    

    注意:Pycharm可以创建。如果用Pycharm创建,记得settings.py中的DIR templates 删除。

  • 创建app & 注册

    >>>python manage.py startapp app01
    >>>python manage.py startapp app02
    >>>python manage.py startapp app03
    
    INSTALLED_APPS = [
        ...
        'app01.apps.App01Config'
    ]
    

    注意:否则app下的models.py写类时,无法在数据库中创建表。

  • 配置 静态文件路径 & 模板的路径(放在app目录下)。

  • 配置数据库相关操作(MySQL)

    • 第三方模块(django3版本)

      pip install mysqlclient
      
    • 自己先去MySQL创建一个数据库。

    • 配置数据库连接settings.py

      DATABASES = {
          'default': {
              'ENGINE': 'django.db.backends.mysql',
              'NAME': 'gx_day16',  # 数据库名字
              'USER': 'root',
              'PASSWORD': 'root123',
              'HOST': '127.0.0.1',  # 那台机器安装了MySQL
              'PORT': 3306,
          }
      }
      
    • 在app下的models.py中编写

      from django.db import models
      
      
      class Admin(models.Model):
          """ 管理员 """
          username = models.CharField(verbose_name="用户名", max_length=32)
          password = models.CharField(verbose_name="密码", max_length=64)
      
          def __str__(self):
              return self.username
      
          
      class Department(models.Model):
          """ 部门表 """
          title = models.CharField(verbose_name='标题', max_length=32)
      
          def __str__(self):
              return self.title
      
    • 执行两个命令:

      >>>python manange.py makemigrations
      >>>python manange.py migrate
      
  • 在 urls.py ,路由 ( URL 和 函数的对应关系)。

  • 在views.py,视图函数,编写业务逻辑。

  • templates目录,编写HTML模板(含有模板语法、继承、{% static 'xx'%}

  • ModelForm & Form组件,在我们开发增删改查功能。

    • 生成HTML标签(生成默认值)
    • 请求数据进行校验。
    • 保存到数据库(ModelForm)
    • 获取错误信息。
  • Cookie和Session,用户登录信息保存起来。

  • 中间件,基于中间件实现用户认证 ,基于:process_request

  • ORM操作

    models.User.objects.filter(id="xxx")
    models.User.objects.filter(id="xxx").order_by("-id")
    
  • 分页组件。

1.Ajax请求

2.订单

Django开发_第24张图片

class Order(models.Model):
    """ 订单 """
    oid = models.CharField(verbose_name="订单号", max_length=64)
    title = models.CharField(verbose_name="名称", max_length=32)
    price = models.IntegerField(verbose_name="价格")

    status_choices = (
        (1, "待支付"),
        (2, "已支付"),
    )
    status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=1)
    admin = models.ForeignKey(verbose_name="管理员", to="Admin", on_delete=models.CASCADE)

想要去数据库中获取数据时:对象/字典

# 对象,当前行的所有数据。
row_object = models.Order.objects.filter(id=uid).first()
row_object.id
row_object.title
# 字典,{"id":1,"title":"xx"}
row_dict = models.Order.objects.filter(id=uid).values("id","title").first()
# queryset = [obj,obj,obj,]
queryset = models.Order.objects.all()
# queryset = [ {'id':1,'title':"xx"},{'id':2,'title':"xx"}, ]
queryset = models.Order.objects.all().values("id","title")
# queryset = [ (1,"xx"),(2,"xxx"), ]
queryset = models.Order.objects.all().values_list("id","title")

小结

至此,基于Ajax + 对话框的形式实现的页面的增删改查。

  • 表单,实现增删改查。
  • Ajax,实现增删改查。

3.图表

  • highchart,国外。
  • echarts,国内。

更多参考文档:https://echarts.apache.org/handbook/zh/get-started

Django开发(四)

1.知识点复习

1.1 基础入门

  • 编码

    编码基础知识点:utf-8、unicode、gbk、ascii
    默认解释器编码:
    	- Python2:ascii( # -*- coding:utf-8 -*- )
    	- Python3:utf-8(重要)
    
  • 输入和输出

    print
    input,用户输入的永远是字符串类型。
    
    data = input("请输入序号:") # 1
    print(data) # "1"
    
  • 变量

    规范:字母、数字、下划线;数字不能开头;不能是py内置关键字。
    建议:
    	- 见名知意
        - 多个单词,用下划线连接。
        - 全局变量用大写( DATA_LIST、USER_INFO  );局部变量小写(user_age)。
        
    注意:
    	全局变量    GET_INFO
        局部变量    get_info
    	函数名      get_info
        类名        GetInfo
        文件名      get_info
        包名称      get_info
    
  • 异常处理【补充】

    data = input("请输入:")  # 你好
    res = int(data)
    print(res)
    
    # 这个代码是有风险,可能会报错。
    
    print("开始")
    try:
        data = input("请输入:")  # 123  / 你好
        res = int(data)
        print(res)
    except Exception as e:
        print("出错了")
    
    print("结束")
    
  • 循环中for/while内部都可以用 break、continue

  • 字符串格式化

    data = "我是{},姓名是{},年龄是{}".format("xx",123,999)
    
    data = "我是{0},姓名是{1},年龄是{2}".format("xx",123,999)
    
    data = "我是{0},姓名是{0},年龄是{2}".format("xx",123)
    
  • 运算符

    - 传统的运算符
    - 逻辑运算符
    	- 常见操作,最终的到的结果:True/False
    		if 1>10 and 9<8:
    			pass
    		else:
    			pass
    	- 非传统,最终的结果是:第一个或第二个值。
    		data = 值1 and 值2
    		v1 = 5 and 9  # 9
    		v2 = 0 and 10 # 0
    

1.2 数据类型

  • 字符串类型

    - 不可变类型;
    - 常见方法:strip/split/replace/join
    	v1 = "root"
    	data = v1.upper()
    	print(v1)   # root
    	print(data) # ROOT
    	
    - 公共:索引、切片、循环
    	v1 = "root"
    	v1[1] = "X"  # 报错,不可变
    
  • 列表类型

    - 可变类型
    - 常见方法:append/insert/pop/remove
    - 公共:索引、切片、循环
    	v1 = [11,22,33,44,55]
    	
    	v1[0]
    	v1[1:3]      - 前取后不取
    	v1[1:-1]
    - 列表的推导式
    	data = [ i for i in range(10)]
    	data = [ i for i in range(10) if i<5]
    
  • 字典类型

    - 可变类型
    - 字典的键是有要求:可哈希类型,目前不可哈希:list/dict/set。
    - 扩展:python3.6+字典有序。
    - 常见的功能:keys、values、items、get
    	data = {}
    	v1 = data.get("k1")
    
  • 关于元组

    v1 = (11,)
    v2 = (11)   # 11
    v3 = 11
    
  • 其他数据类型

    其他类型转布尔类型时,哪些为False: 空、0、None
    其他类型转自己类型时,自己的类名()
    	int("123")
    

1.3 函数

  • 定义

    def func():
        pass
    
    func()
    
  • 参数

    def func(v1,v2):
        pass
    
    def func(v1, v2=None):
        pass
    
    def func(*args,**kwargs):
        pass
    
  • 返回值

    - 没有返回值,默认返回None
        def func(v1,v2):
            print(999)
    - 一个返回值
        def func(v1,v2):
            return 123
        
        res = func(1,2)
        print(res) # 123
        
    - 多个返回值
        def func(v1,v2):
            return 123,999,123
        
        res = func(1,2)
        print(res) # (123,999,123)
        
        
    	def func(v1,v2):
            return 123,999,123
        
        d1,d2,c3 = func(1,2)
    
    v1,v2 = [11,22]
    v1,v2,v3 = (11,22,999)
    
  • lambda表达式(匿名函数)

    def func(arg):
        return arg + 100
    
    func = lambda arg:arg+100
    v1 = func(100)
    print(v1) # 200
    
  • 内置函数

    max/min/all/any/help/hex/oct/bin..
    
    open,文件操作。
        f = open("xx.log",mode='r')
        data = f.read()
        f.close()
    
  • 文件操作

    - 模式:r/w/a ; rb/wb/ab
    - 打开 & 关闭
    	with open("xx.log",mode='r') as f:
    		f.read()
    

1.4 模块

  • 分类

    - 自定义模块:自己写文件/文件夹
    - 内置模块:time/datetime/json/hashlib/random/re等
    - 第三方模块:openpyxl/requests/bs4/flask/django等
    
  • 自定义模块

    - sys.path,Python内部导入模块时,根据目录去寻找。
    - 一定不要让自己写的模块名和内置的模块名重复(***)
    - 导入模块:
    	import xxx
    	from xxx import xxx
    
  • 内置模块

    - 时间部分:time/datetime/字符串类型。
    - random:随机生成数字。
    - hashlib:加密(md5加密、md5加密+加盐) 防止被撞库。
    - json:
    	- JSON格式的字符串: 内部字符串双引号、内部[] 
    	- json.dumps
    	- json.loads
    - re和正则
    	- 正则:\d \w ; 贪婪匹配。
    	- re.search/re.match/      re.findall
    
  • 第三方模块

    - 安装第三方模块:pip、源码、wheel
    - 常见第三方模块:
    	- requests
    	- bs4
    	- openpyxl
    	- python-docx
    	- flask/django (flask简洁(轻量级);django功能强大)
    

1.5 面向对象

- 面向对象的三大特性:封装、继承、多态。
- 理解,读懂源码和代码。

1.6 MySQL数据库

- 数据库
- 表
- 数据行
更多知识:https://www.bilibili.com/video/BV15R4y1b7y9
show databases;
use 数据库;

show tables;
desc 表名;

select * from 表;
insert into 表(列,列,列)values(...)
update  表 set 列=值;
delete from 表 where 条件;

Python连接并操作MySQL:

  • pymysql 【自己原生写】

    pip install pymysql
    
  • mysqlclient 【django内部】

    pip install mysqlclient
    
  • MySQLdb (默认不支持python3)

    pip intall MySQLdb
    

当使用Python代码去操作MySQL时,一定要防止SQL注入的问题。

# SQL语句不要用字符串格式化去拼接。

import pymysql
# 1.连接MySQL
conn = pymysql.connect(host="127.0.0.1", port=3306, user='root', passwd="root123", charset='utf8', db='unicom')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

# 【错误】不要这么写
sql = "select * from admin where id > %s".format(2)
cursor.execute(sql)
# 【正确】这么写
cursor.execute("select * from admin where id > %s", [2, ])

# 获取符合条件的第一条数据,字典    None
res = cursor.fetchone()
print(res)  # {'id': 3, 'username': '集宁', 'password': 'qwe123', 'mobile': '1999999999'}

# 3.关闭连接
cursor.close()
conn.close()

1.7 前端开发

  • HTML

    - 块级和行内标签(div、span)
    	块级:div/h系列
    	行内:span/a (设置高度、宽度、边距无效)
    - Form表单
    	
    - 关于a标签 百度 超链接去跳转。 做锚点 第一章 第二章
    第一章 谢新雪
    第二章 单独的
  • CSS

    - 位置
    	- 标签 
    - style代码块 - 文件中 - 选择器 div { } #v1 { } .v2 { } div[xx='11'] { } - 样式 color;fonts-ize; background-color; padding; margin; float:left; ,脱离文档流。 clear:both; :after
  • JavaScript & jQuery

    - 本质上:找到标签;操作标签。
    
    - 找标签
    	$("#x1")
    	$(".x1")
    	$("div")
    	
    	$("input[type='text']")   找到 input 标签且 type='text'
    - 操作标签
    	$("#x1").text()            
    dd
    $("#x1").text("xxx")
    xxx
    $("#x1").val() $("#x1").val("xxx") $("#x1").attr("uu")
    dd
    $("#x1").attr("uu","999")
    dd
    $("#x1").empty()
    dd
    - 清空内容 $("#x1").remove()
    dd
    - 整个标签删除
  • BootStrap

    - 支持响应式布局,根据屏幕的宽度调整布局。
    - 栅格,12份。
    - 常见的样式:
    	- container  / container-fluid
    	- 面板
    	- 按钮
    	- 表单
    	- 表格
    	- 对话框
    
  • 第三方插件

    - 插件一般都包含:CSS、JavaScript,开发使用时候
    	- 引入css、js(依赖jQuery)
    	- 使用
    
  • 关于注释

    - Python语言
    	# 注释
        """ 注释 """
    - HTML
    	
        
    - CSS注释
    	/* 注释 */
        
    - JavaScript
    	// 注释
        /* 注释 */
    

1.8 Django

  • 安装

    pip install django
    
    python安装目录下:
    	- lib/site-packages/django源码包
    	- Scripts/django-admin.exe  文件
    
  • 创建Django项目

    >>>django-admin  startproject  项目名
    
  • 创建APP

    >>>cd 项目目录
    >>>python manange.py startapp app名称
    
  • 注册app

    - 不注册,models.py生成数据库表行为不执行。
    - 不注册,模板文件、静态文件,不回去app目录下找。
    
  • static目录,静态文件目录

  • templates目录,模板文件目录(HTML)

  • 表结构设计 app01/modes.py下执行

    from django.db import models
    
    class UserInfo(models.Model):
        v1 = models.CharField(max_length=32)
        ...
        ..
    
    >>>python manage.py makemigrations
    >>>python manage.py migrate
    
  • urls.py 中编写路由。

    from django.urls import path,re_path
    from app01 import admin
    
    
    urlpatterns = [
        path('admin/list/', admin.admin_list),
        path('admin//delete/', admin.admin_delete),
        re_path('admin/(?P\d+)/delete/', admin.admin_delete)
    ]
    
  • 视图函数

    def admin_list(request):
        k1 = request.POST.get("k1")
        
        ... 业务处理
        
        return 数据
    
    - 默认参数request,包含请求相关的所有数据。
    	request.method
        request.GET
        request.POST
        request.FILES,上传文件。
        request.path_info,获取当前请求的URL
        	http://127.0.0.1:8000/depart/add/  ->    /depart/add/
                    
    - 返回值
    	return HttpResponse("字符串")
    	return JSONResponse( {"status":123,"data":[456,55,66,22,]} )
    		return JSONResponse( [11,22,33,44] ,safe=False)
    	return render(request,"xxx.html",{})
    	return redirect("http://127.0.0.1:8000/depart/add/")
    			return redirect("/depart/add/")
    
  • 数据库的ORM操作

    # 增加
    models..objects.create(name="武沛齐",age=19)
    models..objects.create(**{"name":"武沛齐","age":19})
    
    obj = models.(name="武沛齐",age=19)
    obj.save()
    
    obj_list = [
        models.(name="武沛齐",age=19),
        models.(name="武沛齐",age=19),
        models.(name="武沛齐",age=19),
        models.(name="武沛齐",age=19),
        models.(name="武沛齐",age=19)
        。。。
    ]
    models..objects.bulk_create(obj_list,batch_size=10)
    
    # 查询
    queyrset = models..objects.filter(name="武沛齐",age=19)         # [obj,obj,]
    queyrset = models..objects.filter(**{"name":"武沛齐","age":19}) # []
    obj = models..objects.filter(name="武沛齐",age=19).first()      # obj / None
    
    queyrset = models..objects.filter(age=19)
    queyrset = models..objects.filter(age__gt=19)
    queyrset = models..objects.filter(age__gte=19)
    queyrset = models..objects.filter(age__lt=19)
    queyrset = models..objects.filter(age__lte=19)
    queyrset = models..objects.filter(age__gt=19, name="武沛齐")
    queyrset = models..objects.filter(name__contains="中国")
    queyrset = models..objects.exclude(id=9)  # id !=9
    
    queyrset = models..objects.filter(age=19).order_by("id")
    queyrset = models..objects.filter(age=19).order_by("-id")
    queyrset = models..objects.filter(age=19).order_by("-id","name")
    
    queyrset = models..objects.filter(age=19)[0:10]
    
    # 更新
    queyrset = models..objects.filter(id=2).update(age=19,name="武沛齐")
    queyrset = models..objects.filter(id=2).update(**{"name":"武沛齐","age":19})
    
    
    obj = models..objects.filter(id=2).first()
    obj.name = "武沛齐"
    obj.age = 19
    obj.save()
    
    # 删除
    models..objects.filter(id=2).delete()
    
    整理的所有ORM操作:
    	https://www.cnblogs.com/wupeiqi/articles/6216618.html
    
  • Form和ModelForm组件

    - 自动生成HTML标签
    - 对用户请求的数据进行校验
    	- 自动保存到数据库(ModelForm)
    - 错误信息
    
    from django import forms
    
    class UserForm(forms.Form):
        xx = forms.CharField(...)
        
        
    class UserModelForm(forms.ModelForm):
        class Meta:
            model = models.类
            fields = "__all__"    
    
    form = UserModelForm(data=request.POST,instance=对象)
    if form.is_valid():
        form.cleaned_data
    else:
        form.errors
    
  • 关于POST提交CSRF认证

    <form method='post'>
        {% csrf_token %}
        ...
    form>
    

    如果想要免除csrf认证。

    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def order_add(request):
        pass
    
  • Cookie和Session

    cookie,本质上保存在浏览器端的键值对。 
    session,保存服务器端(django是将session默认存储在数据库中)
    
    def order_add(request):
        request.session['xx'] = 123
        
    def logout(request):
    	request.session.clear()
    
  • 中间件

    - 类 process_request / process_response
    - 注册中间件类
        MIDDLEWARE = [
            'django.middleware.security.SecurityMiddleware',
            'django.contrib.sessions.middleware.SessionMiddleware',
            'django.middleware.common.CommonMiddleware',
            'django.middleware.csrf.CsrfViewMiddleware',
            'django.contrib.auth.middleware.AuthenticationMiddleware',
            'django.contrib.messages.middleware.MessageMiddleware',
            'django.middleware.clickjacking.XFrameOptionsMiddleware',
            'app01.middleware.auth.AuthMiddleware',
        ]
    - django请求到达之后,自动会执行相应的方法。
    
    - process_request
    	- 没有返回值或返回None,继续向后执行。
    	- 返回redirect/render/HttpResponse/JsonReponse,拦截请求不再继续向后之后。
    
  • 图片验证码

    pip install pillow
    
    - 创建图片并在图片上写文字
    - 字体文件
    - 自定义模块 check_code
    
  • 分页组件

    开发时候会用。
    

2.关于文件上传

2.1 基本操作

<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <input type="text" name="username">
    <input type="file" name="avatar">
    <input type="submit" value="提交">
form>
from django.shortcuts import render, HttpResponse


def upload_list(request):
    if request.method == "GET":
        return render(request, 'upload_list.html')

    # # 'username': ['big666']
    # print(request.POST)  # 请求体中数据
    # # {'avatar': []}>
    # print(request.FILES)  # 请求发过来的文件 {}

    file_object = request.FILES.get("avatar")
    # print(file_object.name)  # 文件名:[email protected]

    f = open(file_object.name, mode='wb')
    for chunk in file_object.chunks():
        f.write(chunk)
    f.close()
    return HttpResponse("...")

案例:批量上传数据

<form method="post" enctype="multipart/form-data" action="/depart/multi/">
    {% csrf_token %}
    <div class="form-group">
        <input type="file" name="exc">
    div>
    <input type="submit" value="上传" class="btn btn-info btn-sm">
form>
def depart_multi(request):
    """ 批量删除(Excel文件)"""
    from openpyxl import load_workbook

    # 1.获取用户上传的文件对象
    file_object = request.FILES.get("exc")

    # 2.对象传递给openpyxl,由openpyxl读取文件的内容
    wb = load_workbook(file_object)
    sheet = wb.worksheets[0]

    # 3.循环获取每一行数据
    for row in sheet.iter_rows(min_row=2):
        text = row[0].value
        exists = models.Department.objects.filter(title=text).exists()
        if not exists:
            models.Department.objects.create(title=text)

    return redirect('/depart/list/')

案例:混合数据(Form)

提交页面时:用户输入数据 + 文件(输入不能为空、报错)。

  • Form生成HTML标签:type=file
  • 表单的验证
  • form.cleaned_data 获取 数据 + 文件对象
{% extends 'layout.html' %}


{% block content %}

    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title"> {{ title }} h3>
            div>
            <div class="panel-body">
                <form method="post" enctype="multipart/form-data" novalidate >
                    {% csrf_token %}

                    {% for field in form %}
                        <div class="form-group">
                            <label>{{ field.label }}label>
                            {{ field }}
                            <span style="color: red;">{{ field.errors.0 }}span>
                        div>
                    {% endfor %}

                    <button type="submit" class="btn btn-primary">提 交button>
                form>
            div>
        div>
    div>

{% endblock %}

from django import forms
from app01.utils.bootstrap import BootStrapForm


class UpForm(BootStrapForm):
    bootstrap_exclude_fields = ['img']

    name = forms.CharField(label="姓名")
    age = forms.IntegerField(label="年龄")
    img = forms.FileField(label="头像")


def upload_form(request):
    title = "Form上传"
    if request.method == "GET":
        form = UpForm()
        return render(request, 'upload_form.html', {"form": form, "title": title})

    form = UpForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        # {'name': '武沛齐', 'age': 123, 'img': }
        # 1.读取图片内容,写入到文件夹中并获取文件的路径。
        image_object = form.cleaned_data.get("img")

        # file_path = "app01/static/img/{}".format(image_object.name)
        db_file_path = os.path.join("static", "img", image_object.name)

        file_path = os.path.join("app01", db_file_path)
        f = open(file_path, mode='wb')
        for chunk in image_object.chunks():
            f.write(chunk)
        f.close()

        # 2.将图片文件路径写入到数据库
        models.Boss.objects.create(
            name=form.cleaned_data['name'],
            age=form.cleaned_data['age'],
            img=db_file_path,
        )
        return HttpResponse("...")
    return render(request, 'upload_form.html', {"form": form, "title": title})

注意:就目前而言,所有的静态文件都只能放在static目录。

在django的开发过程中两个特殊的文件夹:

  • static,存放静态文件的路径,包括:CSS、JS、项目图片。
  • media,用户上传的数据的目录。

2.2 启用media

在urls.py中进行配置:

from django.urls import path, re_path
from django.views.static import serve
from django.conf import settings

urlpatterns = [
	re_path(r'^media/(?P.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
]

在settings.py中进行配置:

import os

MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"

在浏览器上访问这个地址:

Django开发_第25张图片

案例:混合数据(form)

from django import forms
from app01.utils.bootstrap import BootStrapForm


class UpForm(BootStrapForm):
    bootstrap_exclude_fields = ['img']

    name = forms.CharField(label="姓名")
    age = forms.IntegerField(label="年龄")
    img = forms.FileField(label="头像")


def upload_form(request):
    title = "Form上传"
    if request.method == "GET":
        form = UpForm()
        return render(request, 'upload_form.html', {"form": form, "title": title})

    form = UpForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        # {'name': '武沛齐', 'age': 123, 'img': }
        # 1.读取图片内容,写入到文件夹中并获取文件的路径。
        image_object = form.cleaned_data.get("img")

        # media_path = os.path.join(settings.MEDIA_ROOT, image_object.name)
        media_path = os.path.join("media", image_object.name)
        f = open(media_path, mode='wb')
        for chunk in image_object.chunks():
            f.write(chunk)
        f.close()

        # 2.将图片文件路径写入到数据库
        models.Boss.objects.create(
            name=form.cleaned_data['name'],
            age=form.cleaned_data['age'],
            img=media_path,
        )
        return HttpResponse("...")
    return render(request, 'upload_form.html', {"form": form, "title": title})

案例:混合数据(ModalForm)

models.py
class City(models.Model):
    """ 城市 """
    name = models.CharField(verbose_name="名称", max_length=32)
    count = models.IntegerField(verbose_name="人口")

    # 本质上数据库也是CharField,自动保存数据。
    img = models.FileField(verbose_name="Logo", max_length=128, upload_to='city/')
定义ModelForm
from app01.utils.bootstrap import BootStrapModelForm


class UpModelForm(BootStrapModelForm):
    bootstrap_exclude_fields = ['img']

    class Meta:
        model = models.City
        fields = "__all__"
视图
def upload_modal_form(request):
    """ 上传文件和数据(modelForm)"""
    title = "ModelForm上传文件"
    if request.method == "GET":
        form = UpModelForm()
        return render(request, 'upload_form.html', {"form": form, 'title': title})

    form = UpModelForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        # 对于文件:自动保存;
        # 字段 + 上传路径写入到数据库
        form.save()
        
        return HttpResponse("成功")
    return render(request, 'upload_form.html', {"form": form, 'title': title})

小结

  • 自己手动去写

    file_object = request.FILES.get("exc")
    ...
    
  • Form组件(表单验证)

    request.POST
    file_object = request.FILES.get("exc")
    
    具体文件操作还是手动自己做。
    
  • ModelForm(表单验证 + 自动保存数据库 + 自动保存文件)

    - Media文件夹
    - Models.py定义类文件要
    	img = models.FileField(verbose_name="Logo", max_length=128, upload_to='city/')
    

你可能感兴趣的:(django,数据库)