[学习笔记]python的web开发全家桶2

初识网站

  • 默认编写的静态的效果
  • 动态:需要用到Web框架的功能。
    在这里插入图片描述
    对于目前的我们来看,什么可以做数据存储:
  • txt文件
  • excel文件
  • 专业的软件:数据库管理系统
    MySQL/Oracle/SQLServer/DB2/Access...
    在这里插入图片描述

7 MysQL

7.1 安装MySQL

MySQL,本质上就是一个软件。

  • 8.x
  • 5.x

7.2 启动MySQL

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

7.3 MySQL指令

7.3.1 数据库管理(文件夹)

在这里插入图片描述

7.3.2 数据表的管理(文件)


char,速度快。varchar,节省空间。

7.4 案例:员工管理

在这里插入图片描述

7.4.2 Python操作MySQL

创建连接,创建游标cursor,用游标execute执行sql语句,然后断开连接。

import pymysql

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


# 2.发送指令
cursor.execute("insert into admin(username, password, mobile) values('张三', 'qwe123', '155555')")
conn.commit()

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

动态执行sql,千万不要用字符串格式化去做sql拼接,会有安全隐患SQL注入

sql = "insert into admin(username, password, mobile) values(%s, %s, %s)"
cursor.execute(sql, ["李四", "qwe123", "1999999"])

sql = "insert into admin(username, password, mobile) values(%(n1)s, %(n2)s, %(n3)s)"
cursor.execute(sql, {
    
    "n1": "王五",  "n2": "qwe123", "n3": "1999999"})
conn.commit()
  • 查询数据
    fetchall获取所有数据
    fetchone获取符合条件的第一条数据
import pymysql

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

# 2.发送指令
sql = "select * from admin where id > 2 "
cursor.execute(sql)
datalist = cursor.fetchall()
for row_dict in datalist:
    print(row_dict)

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

在这里插入图片描述

8.案例:Flask+MySQL

在这里插入图片描述

from flask import Flask, render_template, request
import pymysql

app = Flask(__name__)

@app.route("/add/user", methods=["GET", "POST"])
def add_user():
    if request.method == "GET":
        return render_template("add_user.html")

    username = request.form.get("user")
    password = request.form.get("pwd")
    mobile = request.form.get("mobile")

    # 1.连接MySQL
    conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", password="xxxx", charset="utf8", db="unicom")
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 2.执行SQL
    sql = "insert into admin(username, password, mobile) values(%s, %s, %s)"
    cursor.execute(sql, [username, password, mobile])
    conn.commit()
    # 3.关闭连接
    cursor.close()
    conn.close()

    return "添加成功"


@app.route("/show/user")
def show_user():
    # 1.连接MySQL
    conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", password="xxxx", charset="utf8", db="unicom")
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 2.执行SQL
    sql = "select * from admin"
    cursor.execute(sql)
    data_list = cursor.fetchall()
    # 3.关闭连接
    cursor.close()
    conn.close()

    print(data_list)
    return render_template("show_user.html", data_list=data_list)


if __name__ == '__main__':
    app.run()

9 初始Django

9.1 安装django

安装完会有django-amin.exe和django模块。
在这里插入图片描述

9.2 创建项目

9.2.1 在终端

在这里插入图片描述

9.2.2 Pycharm


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

9.3 APP

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

9.4 快速上手

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

9.4.1 再写一个页面

在这里插入图片描述

9.4.2 templates模板

在这里插入图片描述

9.4.3 静态文件

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

9.5 模板语法

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>模板语法的学习</h1>
<div>{
   
   { n1 }}</div>
<div>{
   
   { n2 }}</div>

<div>{
   
   { n2.0 }}</div>
<div>{
   
   { n2.1 }}</div>
<div>{
   
   { n2.2 }}</div>

<div>
    {% for item in n2 %}
        <span>{
   
   { item }}</span>
    {% endfor %}
</div>
<hr/>
<div>{
   
   { n3 }}</div>

<div>{
   
   { n3.name }}</div>
<div>{
   
   { n3.salary }}</div>
<div>{
   
   { n3.role }}</div>

<div>
    {% for k, v in n3.items %}
        <li>{
   
   { k }} = {
   
   { v }}</li>
    {% endfor %}
</div>
<hr>
{
   
   { n4.1 }}
{
   
   { n4.1.name }}
{% for item in n4 %}
    <div>{
   
   { item.name }}{
   
   { item.salary }}</div>
{% endfor %}

<hr>
{% if n1 == "韩超" %}
    <h1>哒哒哒</h1>
{% else %}
    <h1>嘟嘟嘟</h1>
{% endif %}

{% if n1 == "韩超" %}
    <h1>哒哒哒</h1>
{% elif n1 == "xxx" %}
    <h1>bibibi</h1>
{% else %}
    <h1>嘟嘟嘟</h1>
{% endif %}
</body>
</html>

案例:伪联通新闻中心

爬虫如果报错:Expecting value: line 1 column 1 (char 0)可以参考视频

def news(request):
    import requests
    # 请求头添加浏览器信息
    headers = {
    
    
        'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
    }
    url = "http://www.chinaunicom.com.cn/api/article/NewsByIndex/2/2023/06/news"
    res = requests.get(url, headers=headers)

    data_list = res.json()
    print(data_list)

    return render(request, "news.html", {
    
    "news_list": data_list})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>联通新闻中心</h1>
<ul>
    {% for item in news_list %}
        <li>{
   
   { item.news_title }} 时间: {
   
   { item.post_time }} </li>
    {% endfor %}
</ul>
</body>
</html>

9.6 请求和响应

from django.shortcuts import render, HttpResponse, redirect


def index(request):
    return HttpResponse("欢迎使用")


def user_list(request):
    return render(request, "user_list.html")


def user_add(request):
    return render(request, "user_add.html")


def tpl(request):
    name = "韩超发方法"
    roles = ["管理员", "CEO", "保安"]
    user_info = {
    
    "name": "张三", "salary": 10000, "role": "CTO"}
    data_list = [
        {
    
    "name": "张三", "salary": 10000, "role": "CTO"},
        {
    
    "name": "李四", "salary": 10000, "role": "CTO"},
        {
    
    "name": "王五", "salary": 10000, "role": "CTO"},
    ]
    return render(request, "tpl.html", {
    
    "n1": name, "n2": roles, "n3": user_info, "n4": data_list})


def news(request):
    import requests
    # 请求头添加浏览器信息
    headers = {
    
    
        'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
    }
    url = "http://www.chinaunicom.com.cn/api/article/NewsByIndex/2/2023/06/news"
    res = requests.get(url, headers=headers)

    data_list = res.json()
    print(data_list)

    return render(request, "news.html", {
    
    "news_list": data_list})

def something(request):
    # request是一个对象,封装了用户通过发送过来的所有请求相关数据

    # 1.获取请求方式 GET/POST
    print(request.method)

    # 2.在URL上传递值 /something/?n1=123&n2=999
    print(request.GET)

    # 3.在请求体中提交数据
    print(request.POST)

    # 4.【响应】HttpResponse("返回内容"),将字符串内容返回给请求者
    # return HttpResponse("返回内容")

    # 5.【响应】读取HTML内容+渲染(替换)-> 字符串,返回给用户浏览器。
    # return render(request, 'something.html', {"title": "来了"})

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

关于重定向:web框架返回重定向的网站给浏览器,然后浏览器自己去请求那个网站。

案例:用户登录

def login(request):
    if request.method == "GET":
        return render(request, "login.html")
    # 如果是POST请求,获取用户提交的数据
    print(request.POST)
    username = request.POST.get("user")
    password = request.POST.get("pwd")

    if username == "root" and password == "123":
        # return HttpResponse("登陆成功")
        return redirect("https://www.baidu.com/")
    
    # return HttpResponse("登陆失败")
    return render(request, 'login.html', {
    
    "error_msg": "用户名或密码错误"})

9.7 数据库操作

Django开发操作数据库更简单,内部提供了ORM框架。
在这里插入图片描述

9.7.1 安装第三方模块

pip install mysqlclient

9.7.2 ORM

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

DATABASES = {
    
    
    'default': {
    
    
    'ENGINE': 'django.db.backends.mysql',
    'NAME':'dbname',
    'USER': 'root',
    'PASSWORD': 'xxx',
    'HOST': '',
    'PORT': '',
    }
}

9.7.3 django操作表

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

# 生成数据库同步脚本
python manage.py makemigrations
# 迁移处理表
python manage.py migrate

注意:在表中
在这里插入图片描述

9.7.4 表中的数据

from app01.models import Department, UserInfo
def orm(request):
    # 测试ORM操作表中的数据
    ### 1.新建
    # Department.objects.create(title="销售部")
    # Department.objects.create(title="IT部")
    # Department.objects.create(title="运营部")
    # UserInfo.objects.create(name="张三", password="123", age=19)
    # UserInfo.objects.create(name="李四", password="666", age=29)

    ### 2.删除
    # UserInfo.objects.filter(id=3).delete()
    # Department.objects.all().delete()

    ### 3.获取数据
    # data_list = [对象-行, 对象-行, 对象-行] QuerySet类型

    # data_list = UserInfo.objects.all()
    # for obj in data_list:
    #     print(obj.id, obj.name, obj.password, obj.age)

    # data_list = UserInfo.objects.filter(id=4)
    # print(data_list)

    # row_obj = UserInfo.objects.filter(id=4).first()
    # print(row_obj.id, row_obj.name, row_obj.password, row_obj.age)

    ### 4.更新数据
    # UserInfo.objects.all().update(password=999)
    UserInfo.objects.filter(id=4).update(age=999)

    return HttpResponse("成功")

案例:用户管理

在这里插入图片描述
重定向到别人的网站需要写全url。重定向到自己的网站不需要。

10 Django开发

主题:员工管理系统

10.1 新建项目

去掉setting中的"DIRS"中的内容。去掉templates文件夹。

10.2 创建app

在这里插入图片描述
创建app
注册app

10.3 设计表结构(django)

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

10.4 在MySQL中生成表

在这里插入图片描述

10.5 静态文件管理

在这里插入图片描述

10.6 部门管理

在这里插入图片描述

10.6.1 部门列表

预期效果:
在这里插入图片描述
代码详见视频

10.7 模板的继承

在这里插入图片描述

10.8 用户管理

在这里插入图片描述
模板语法中不允许加括号,他读到你需要加括号的地方会自动帮你加。
模板语法和python语法稍微有点区别。
在这里插入图片描述
在这里插入图片描述

10.8.1 初识Form

views.py
在这里插入图片描述

10.8.3 ModelForm

models.py

from django.db import models

# Create your models here.
class Department(models.Model):
    """部门表"""
    title = models.CharField(verbose_name="", max_length=32)

    def __str__(self):
        return self.title


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)

views.py

from django import forms


class UserModelForm(forms.ModelForm):
    class Meta:
        model = models.UserInfo
        # fields = ["name", "password", "age", "account", "create_time"]
        fields = "__all__"

def user_model_form_add(request):
    form = UserModelForm()
    return render(request, "user_model_form_add.html", {
    
    "form": form})

modelform内部去取Department表时,是先通过models.Department.objects.all()取到queryset,然后遍历其中的对象,并打印。
但是这样打印的结果是Department对象。
所以需要重写Department的

  • 如何添加样式
    在这里插入图片描述
class UserModelForm(forms.ModelForm):
    class Meta:
        model = models.UserInfo
        # fields = ["name", "password", "age", "account", "create_time"]
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs = {
    
    "class": "form-control", "placeholder": field.label}

def user_model_form_add(request):
    if request.method == "GET":
        form = UserModelForm()
        return render(request, "user_model_form_add.html", {
    
    "form": form})

    form = UserModelForm(data=request.POST)
    if form.is_valid():
        # 数据合法,保存到数据库
        # {'name': '123', 'password': '123', 'age': 123, 'account': Decimal('0'), 'create_time': datetime.datetime(2011, 11, 11, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'depart': <Department: 营销部>, 'gender': 1}
        form.save()
        return redirect('/user/list/')
        print(form.cleaned_data)
    # 校验失败(在页面上显示错误信息)
    return render(request, "user_model_form_add.html", {
    
    "form": form})

将setting中的LANGUAGE_CODE改成”zh-hans“,则提示信息会成为中文。

10.8.4 编辑用户

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

10.8.5 删除

10.9 靓号管理

10.9.1 表结构

在这里插入图片描述

class PrettyNumber(models.Model):
    """靓号表"""
    mobile = models.CharField(verbose_name="手机号", max_length=11)
    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)

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

10.9.2 靓号列表

在这里插入图片描述

10.9.3 新建靓号

在这里插入图片描述

10.9.3.1 验证

方式一:正则表达式

from django.core.validators import RegexValidator
class PrettyModelForm(forms.ModelForm):

    mobile = forms.CharField(
        label="手机号",
        validators=[RegexValidator(r'^1\d{10}', '手机号格式错误')]
    )
    class Meta:
        model = models.PrettyNumber
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs = {
    
    "class": "form-control", "placeholder": field.label}

方式二:钩子方法

from django.core.exceptions import ValidationError
class PrettyModelForm(forms.ModelForm):
    class Meta:
        model = models.PrettyNumber
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs = {
    
    "class": "form-control", "placeholder": field.label}

    def clean_mobile(self):
        txt_mobile = self.cleaned_data['mobile']
        if len(txt_mobile) != 11:
            raise ValidationError("格式错误")
        return txt_mobile

10.9.4 编辑靓号

class PrettyEditModelForm(forms.ModelForm):
    # mobile = forms.CharField(disabled=True, label="手机号")

    class Meta:
        model = models.PrettyNumber
        fields = ["mobile", "price", "level", "status"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs = {
    
    "class": "form-control", "placeholder": field.label}


def pretty_edit(request, nid):
    """编辑靓号"""
    row_object = models.PrettyNumber.objects.filter(id=nid).first()

    if request.method == "GET":
        form = PrettyEditModelForm(instance=row_object)
        return render(request, "pretty_edit.html", {
    
    "form": form})

    form = PrettyEditModelForm(data=request.POST, instance=row_object)
    if form.is_valid():
        form.save()
        return redirect("/pretty/list/")

    return render(request, "pretty_edit.html", {
    
    "form": form})

在这里插入图片描述
靓号删除

def pretty_delete(request, nid):
    models.PrettyNumber.objects.filter(id=nid).delete()
    return redirect("/pretty/list/")

10.9.5 搜索手机号

在这里插入图片描述

注释是中间双下划线

def pretty_list(request):
    data_dict = {
    
    }
    search_data = request.GET.get("q", "")
    if search_data:
        data_dict["mobile__contains"] = search_data

    # 排序,id表示asc,-id表示desc
    queryset = models.PrettyNumber.objects.filter(**data_dict).order_by("-level")
    return render(request, "pretty_list.html", {
    
    "queryset": queryset, "search_data": search_data})
<div style="margin-bottom: 10px" class="clearfix">
   <a class="btn btn-success" href="/pretty/add/">
        <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
        新建靓号
    </a>
    <div style="float: right; width: 300px">
        <form method="get">
            <div class="input-group">
                <input type="text" name="q" class="form-control" placeholder="Search for..." value="{
     
     { search_data }}">
                <span class="input-group-btn">
                <button class="btn btn-default" type="submit">
                <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
                </button>
                </span>
            </div>
        </form>
    </div>
</div>

10.9.6 分页

根据用户想要访问的页码,计算起止位置

 page = int(request.GET.get('page', 1))
    page_size = 10
    start = (page-1) * page_size
    end = page * page_size
    # 排序,id表示asc,-id表示desc
    queryset = models.PrettyNumber.objects.filter(**data_dict).order_by("-level")[start:end]

如果python后端写html的字符串想传入前端html,需要使用from django.utils.safestring import mark_safe
然后用make_safe包裹page_str_list字符串

def pretty_list(request):
    data_dict = {
    
    }
    search_data = request.GET.get("q", "")
    if search_data:
        data_dict["mobile__contains"] = search_data

    page = int(request.GET.get('page', 1))
    page_size = 10
    start = (page-1) * page_size
    end = page * page_size
    # 排序,id表示asc,-id表示desc
    total_count = models.PrettyNumber.objects.filter(**data_dict).order_by("-level").count()
    queryset = models.PrettyNumber.objects.filter(**data_dict).order_by("-level")[start:end]

    total_page_count, div = divmod(total_count, page_size)
    if div:
        total_page_count += 1


    # 计算出,显示当前页的前5页,后5页
    plus = 5
    if total_page_count <= 2 * plus:
        # 数据库中数据比较少
        start_page = 1
        end_page = total_page_count
    else:
        # 数据库数据比较多
        if page <= plus:
            start_page = 1
            end_page = 2 * plus + 1
        elif (page + plus) > total_page_count:
            start_page = total_page_count - 2 * plus
            end_page = total_page_count
        else:
            start_page = page - plus
            end_page = page + plus

    # 页码
    page_str_list = []

    page_str_list.append('<li><a href="?page={}">首页</a></li>'.format(1))

    # 上一页
    if page > 1:
        prev = '<li><a href="?page={}">上一页</a></li>'.format(page - 1)
    else:
        prev = '<li><a href="?page={}">上一页</a></li>'.format(1)

    page_str_list.append(prev)

    for i in range(start_page, end_page + 1):
        if i == page:
            ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
        else:
            ele = '<li><a href="?page={}">{}</a></li>'.format(i, i)
        page_str_list.append(ele)

    # 下一页
    if page < total_page_count:
        next = '<li><a href="?page={}">下一页</a></li>'.format(page + 1)
    else:
        next = '<li><a href="?page={}">下一页</a></li>'.format(total_page_count)
    page_str_list.append(next)

    # 尾页
    page_str_list.append('<li><a href="?page={}">尾页</a></li>'.format(total_page_count))

    page_string = mark_safe("".join(page_str_list))


    return render(request, "pretty_list.html", {
    
    "queryset": queryset, "search_data": search_data, 'page_string': page_string})
  • 封装分页类
"""
自定义的分页组件,以后如果想要使用这个分页组件,你需要做如下几件事:

在视图函数中:
    def pretty_list(request):
        # 1.根据情况筛选数据
        queryset = models.PrettyNumber.objects.all()

        # 2.实例化分页对象
        page_object = Pagination(request, queryset)

        context = {
            "queryset": page_object.page_queryset, # 分完页的数据
            'page_string': page_object.html()      # 生成的页码
        }
        return render(request, "pretty_list.html", context)

在HTML页面中:
        {% for obj in queryset %}
            {
    
    {obj.xx}}
        {% endfor %}

        <ul class="pagination">
            {
    
    { page_string }}
        </ul>

"""
from django.utils.safestring import mark_safe


class Pagination(object):

    def __init__(self, request, queryset, page_size=10, page_param="page", plus=5):
        """
        :param request: 请求的对象
        :param queryset: 符合条件的数据(根据这个数据进行分页处理)
        :param page_size: 每页显示多少条数据
        :param page_param: 在URL中传递的获取分页的参数
        :param plus: 显示当前页的 前或后几页(页码)
        """
        page = request.GET.get(page_param, "1")
        if page.isdecimal():
            page = int(page)
        else:
            page = 1
        self.page = page
        self.page_size = page_size
        self.start = (page - 1) * page_size
        self.end = page * page_size

        self.page_queryset = queryset[self.start:self.end]

        # 排序,id表示asc,-id表示desc
        total_count = queryset.count()
        total_page_count, div = divmod(total_count, page_size)
        if div:
            total_page_count += 1
        self.total_page_count = total_page_count
        self.plus = plus

    def html(self):
        if self.total_page_count <= 2 * self.plus:
            # 数据库中数据比较少
            start_page = 1
            end_page = self.total_page_count
        else:
            # 数据库数据比较多
            if self.page <= self.plus:
                start_page = 1
                end_page = 2 * self.plus + 1
            elif (self.page + self.plus) > self.total_page_count:
                start_page = self.total_page_count - 2 * self.plus
                end_page = self.total_page_count
            else:
                start_page = self.page - self.plus
                end_page = self.page + self.plus

        # 页码
        page_str_list = []

        page_str_list.append('<li><a href="?page={}">首页</a></li>'.format(1))

        # 上一页
        if self.page > 1:
            prev = '<li><a href="?page={}">上一页</a></li>'.format(self.page - 1)
        else:
            prev = '<li><a href="?page={}">上一页</a></li>'.format(1)

        page_str_list.append(prev)

        for i in range(start_page, end_page + 1):
            if i == self.page:
                ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
            else:
                ele = '<li><a href="?page={}">{}</a></li>'.format(i, i)
            page_str_list.append(ele)

        # 下一页
        if self.page < self.total_page_count:
            next = '<li><a href="?page={}">下一页</a></li>'.format(self.page + 1)
        else:
            next = '<li><a href="?page={}">下一页</a></li>'.format(self.total_page_count)
        page_str_list.append(next)

        # 尾页
        page_str_list.append('<li><a href="?page={}">尾页</a></li>'.format(self.total_page_count))

        search_sting = """
            <li>
                <form style="float: left; margin-left: -1px" method="get">
                    <div class="input-group" style="width: 200px">
                        <input type="text" name="page" class="form-control" placeholder="页码">
                        <span class="input-group-btn">
                            <button class="btn btn-default" type="submit">跳转</button>
                        </span>
                    </div>
                </form>
            </li>
        """
        page_str_list.append(search_sting)

        page_string = mark_safe("".join(page_str_list))
        return page_string

使用request.GET的深拷贝的urlencode()获取之前的条件。

import copy
query_dict = copy.deepcopy(request.GET)
query_dict._mutable = True
self.query_dict = query_dict
self.page_param = page_param

10.9.7 时间插件

10.10 ModelForm和BootStrap

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

业务较多时,视图函数可以进行拆分

10.11 管理员操作

class Admin(models.Model):
    """管理员"""
    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=64)

导入时候:
模块的书写,一般是先写内置模块,再写第三方模块,最后是自定义模块
短的在上面

  • 密码一致性校验
    django-clean:参考资料:https://pythonjishu.com/django-clean/
class AdminModelForm(BootStrapModelForm):
    confirm_password = forms.CharField(
        label="确认密码",
        widget=forms.PasswordInput
    )

    class Meta:
        model = models.Admin
        fields = ["username", "password", "confirm_password"]
        widgets = {
    
    
            "password": forms.PasswordInput
        }

    def clean_confirm_password(self):
        print(self.cleaned_data)
        pwd = self.cleaned_data.get("password")
        confirm = self.cleaned_data.get("confirm_password")
        if confirm != pwd:
            raise ValidationError("密码不一致,请重新输入")
        # 返回什么,此字段以后保存到数据库就是什么
        return confirm

def admin_add(request):
    """ 添加管理员 """
    title = "新建管理员"
    if request.method == "GET":
        form = AdminModelForm()
        return render(request, 'change.html', {
    
    "form": form, "title": title})


    form = AdminModelForm(data=request.POST)
    if form.is_valid():

        form.save()
        return redirect('/admin/list')
    return render(request, "change.html", {
    
    'form': form, "title": title})

在插件中加入render_value=True,则报错之后会保留原来的值

  • 密码的md5加密
import hashlib

def md5(data_string):
    salt = 'xxxxxxxx'
    obj = hashlib.md5(salt.encode('utf-8'))
    obj.update(data_string.encdoe('utf-8'))
    return obj.hexdigest()

settings中有SECRET_KEY的值,用来做盐

class AdminModelForm(BootStrapModelForm):
    confirm_password = forms.CharField(
        label="确认密码",
        widget=forms.PasswordInput(render_value=True)
    )

    class Meta:
        model = models.Admin
        fields = ["username", "password", "confirm_password"]
        widgets = {
    
    
            "password": forms.PasswordInput(render_value=True)
        }

    def clean_password(self):
        pwd = self.cleaned_data.get("password")
        return md5(pwd)

    def clean_confirm_password(self):
        pwd = self.cleaned_data.get("password")
        confirm = md5(self.cleaned_data.get("confirm_password"))
        if confirm != pwd:
            raise ValidationError("密码不一致,请重新输入")
        # 返回什么,此字段以后保存到数据库就是什么
        return confirm

10.12 用户登录

10.12.1 用户认证-cookie和session

  • http协议的特点
    无状态&短链接
    在这里插入图片描述
  • 什么是cookie和session?
    在这里插入图片描述

Django默认将session放在数据库

from django.shortcuts import render, HttpResponse, redirect
from django import forms
from app01 import models
from app01.utils.encrypt import md5


class LoginForm(forms.Form):
    username = forms.CharField(
        label="用户名",
        widget=forms.TextInput,
        required=True
    )
    password = forms.CharField(
        label="密码",
        widget=forms.PasswordInput(render_value=True)
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        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
                }

    def clean_password(self):
        pwd = self.cleaned_data.get("password")
        return md5(pwd)


def login(request):
    if request.method == 'GET':
        form = LoginForm()
        return render(request, 'login.html', {
    
    'form': form})

    form = LoginForm(data=request.POST)
    if form.is_valid():
        print(form.cleaned_data)
        # 校验用户名和密码
        admin_object = models.Admin.objects.filter(**form.cleaned_data).first()
        if not admin_object:
            form.add_error("password", "用户名或密码错误")
            return render(request, 'login.html', {
    
    'form': form})
        # 用户名和密码正确
        # 网站要生成一个字符串;写到用户浏览器的cookie中,再写入到session中
        request.session["info"] = {
    
    'id': admin_object.id, 'name': admin_object.username}

        return redirect('/admin/list/')
    return render(request, 'login.html', {
    
    'form': form})

10.12.2 登录

没有登录的用户不应该通过网址能访问到管理员列表页面

在这里插入图片描述

10.12.3 中间件的体验

要穿过中间件,才能到视图函数,返回也要穿过中间件。
如果穿不过中间件,就直接返回。

在这里插入图片描述

  • 定义中间件
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class M1(MiddlewareMixin):
    """中间件1"""

    def process_request(self, request):
        print("M1.进来了")
        return HttpResponse("无权访问")


    def process_response(self, request, response):
        print("M1.走了")
        return response


class M2(MiddlewareMixin):
    """中间件1"""

    def process_request(self, request):
        print("M2.进来了")

    def process_response(self, request, response):
        print("M2.走了")
        return response
  • 应用中间件
    在settings.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方法

如果在process_request方法中没有返回值(返回None),则可以继续往后走
如果有返回值,一般返回值类似视图函数的返回值

10.12.4 中间件实现登录校验

  • 编写中间件
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirect

class AuthMiddleware(MiddlewareMixin):
    """中间件1"""

    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',
]

10.12.5 注销

def logout(request):
    """ 注销 """
    request.session.clear()

    return redirect('/login/')

10.13 图片验证码

在这里插入图片描述

10.13.1 利用python生成图片

pip install pillow

参考资料:
https://www.cnblogs.com/wupeiqi/articles/5812291.html

10.14 Ajax请求

在这里插入图片描述

10.14.1 GET请求

# html中
 $.ajax({
         url: "/task/ajax/",
         type: "get",
         data:{
             n1: 123,
             n2: 456
         },
         success: function(res){
             console.log(res);
         }
     })
def task_ajax(request):
    print(request.GET)
    return HttpResponse("成功了")

10.14.2 POST请求

发送post请求时,可以使用免除csrft oken

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

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

10.14.3 绑定事件

{% extends 'layout.html' %}

{% block content %}
    <div class="container">
        <h1>任务管理</h1>
        <h3>示例1</h3>
        <input id="btn1" type="button" class="btn btn-primary" value="点击" onclick="clickMe();"/>
    </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 %}

10.14.4 ajax请求的返回值

  • 前端
{% extends 'layout.html' %}

{% block content %}
    <div class="container">
        <h1>任务管理</h1>
        <h3>示例1</h3>
        <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 %}
  • 后端
    返回值一般是json字典,需要经过序列化
import json
from django.shortcuts import render, redirect, HttpResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def task_ajax(request):
    print(request.POST)
    data_dict = {
    
    "status": True, "data": [11, 22, 33, 44]}
    json_string = json.dumps(data_dict)
    return HttpResponse(json_string)

django也提供了序列化方法:JsonResponse

{
    
    % extends 'layout.html' %}

{
    
    % block content %}
    <div class="container">
        <h1>Ajax学习</h1>

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

        <h3>示例2</h3>
        <input type="text" id="txtUser" placeholder="用户名"/>
        <input type="text" id="txtAge" placeholder="年龄"/>
        <input id="btn2" type="button" class="btn btn-primary" value="点击2"/>

        <h3>示例3</h3>
        <form id="form3">
            <input type="text" name="user" placeholder="用户名"/>
            <input type="text" name="age" placeholder="年龄"/>
            <input type="text" name="email" placeholder="邮箱"/>
            <input type="text" name="more" placeholder="介绍"/>
        </form>
        <input id="btn3" type="button" class="btn btn-primary" value="点击3"/>
    </div>
{
    
    % endblock %}



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

        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);
                    }
                })
            })
        }

        function bindBtn2Event() {
    
    
            $("#btn2").click(function () {
    
    
                $.ajax({
    
    
                    url: "/task/ajax/",
                    type: "post",
                    data: {
    
    
                        name: $("#txtUser").val(),
                        age: $("#txtAge").val()
                    },
                    dataType: "JSON",
                    success: function (res) {
    
    
                        console.log(res);
                        console.log(res.status);
                        console.log(res.data);
                    }
                })
            })
        }

        function bindBtn3Event() {
    
    
            $("#btn3").click(function () {
    
    
                $.ajax({
    
    
                    url: "/task/ajax/",
                    type: "post",
                    data: $("#form3").serialize(),
                    dataType: "JSON",
                    success: function (res) {
    
    
                        console.log(res);
                        console.log(res.status);
                        console.log(res.data);
                    }
                })
            })
        }
    </script>
{
    
    % endblock %}

10.14.5 案例

{% extends 'layout.html' %}

{% block content %}
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">表单</div>
            <div class="panel-body">
                <form id="formAdd" novalidate>
                    <div class="clearfix">
                        {% for field in form %}
                            <div class="col-xs-6">
                                <div class="form-group" style="position: relative; margin-bottom: 20px;">
                                    <label>{
   
   { field.label }}</label>
                                    {
   
   { field }}
                                    <span class="error-msg" style="color:red;position: absolute;"></span>
                                </div>
                            </div>
                        {% endfor %}
                    </div>
                    <div class="col-xs-12">
                        <button id="btnAdd" type="button" class="btn btn-primary">提 交</button>
                    </div>
                </form>
            </div>
        </div>

        <hr/>
        <h1>Ajax学习</h1>

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

        <h3>示例2</h3>
        <input type="text" id="txtUser" placeholder="用户名"/>
        <input type="text" id="txtAge" placeholder="年龄"/>
        <input id="btn2" type="button" class="btn btn-primary" value="点击2"/>

        <h3>示例3</h3>
        <form id="form3">
            <input type="text" name="user" placeholder="用户名"/>
            <input type="text" name="age" placeholder="年龄"/>
            <input type="text" name="email" placeholder="邮箱"/>
            <input type="text" name="more" placeholder="介绍"/>
        </form>
        <input id="btn3" type="button" class="btn btn-primary" value="点击3"/>
    </div>
{% endblock %}



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

        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);
                    }
                })
            })
        }

        function bindBtn2Event() {
      
      
            $("#btn2").click(function () {
      
      
                $.ajax({
      
      
                    url: "/task/ajax/",
                    type: "post",
                    data: {
      
      
                        name: $("#txtUser").val(),
                        age: $("#txtAge").val()
                    },
                    dataType: "JSON",
                    success: function (res) {
      
      
                        console.log(res);
                        console.log(res.status);
                        console.log(res.data);
                    }
                })
            })
        }

        function bindBtn3Event() {
      
      
            $("#btn3").click(function () {
      
      
                $.ajax({
      
      
                    url: "/task/ajax/",
                    type: "post",
                    data: $("#form3").serialize(),
                    dataType: "JSON",
                    success: function (res) {
      
      
                        console.log(res);
                        console.log(res.status);
                        console.log(res.data);
                    }
                })
            })
        }

        function bindBtnAddEvent() {
      
      
            $("#btnAdd").click(function () {
      
      
                $(".error-msg").empty();

                $.ajax({
      
      
                    url: "/task/add/",
                    type: "post",
                    data: $("#formAdd").serialize(),
                    dataType: "JSON",
                    success: function (res) {
      
      
                        if (res.status) {
      
      
                            alert("添加成功");
                        } else {
      
      
                            {
      
      #console.log(res.error);#}
                            $.each(res.error, function(name, data){
      
      
                                // console.log(name, data);
                                $("#id_" + name).next().text(data[0])
                            })
                        }
                    }
                })
            })
        }
    </script>
{% endblock %}

10.15 Django开发-内容回顾

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

10.16 订单

表结构
在这里插入图片描述

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)

通过form.instance.oid=...将一些不是用户输入的值添加

import random
from datetime import datetime
from django.shortcuts import render, redirect, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
from app01.utils.bootstrap import BootStrapModelForm
from app01 import models


class OrderModelForm(BootStrapModelForm):
    class Meta:
        model = models.Order
        # fields = "__all__"
        exclude = ["oid"]


def order_list(request):
    form = OrderModelForm
    return render(request, 'order_list.html', {
    
    'form': form})


@csrf_exempt
def order_add(request):
    form = OrderModelForm(data=request.POST)
    if form.is_valid():
        # title=? price=? status=? admin_id?
        # print(form.cleaned_data)
        form.instance.oid = datetime.now().strftime("%Y%m%d%H%M%S") + str(random.randint(1000, 9999))
        form.save()
        return JsonResponse({
    
    "status": True})

    return JsonResponse({
    
    "status": False, 'error': form.errors})

$("#formAdd")是jQuery对象,$("#formAdd")[0]是DOM对象,后者有reset()方法。

在这里插入图片描述

10.17 图表

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

10.18 文件上传

10.18.1 基本操作

{% extends 'layout.html' %}

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


def upload_list(request):
    if request.method == "GET":
        return render(request, 'upload_list.html')
    # print(request.POST) # 请求体传递过来的数据
    # print(request.FILES) # 发过来的文件
    file_object = request.FILES.get("avatar")
    # print(file_object.name)
    f = open(file_object.name, mode='wb')
    for chunk in file_object.chunks():
        f.write(chunk)
    f.close()

    return HttpResponse("...")

10.18.2 案例:批量上传数据

 <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):
    """批量上传"""
    # 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/")

10.18.3 案例:混合数据(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.shortcuts import render, HttpResponse
import os
from app01 import models


def upload_list(request):
    if request.method == "GET":
        return render(request, 'upload_list.html')
    # print(request.POST) # 请求体传递过来的数据
    # print(request.FILES) # 发过来的文件
    file_object = request.FILES.get("avatar")
    # print(file_object.name)
    f = open(file_object.name, mode='wb')
    for chunk in file_object.chunks():
        f.write(chunk)
    f.close()

    return HttpResponse("...")


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', {
    
    "title": title, "form": form})

    form = UpForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        print(form.cleaned_data)
        # 读取到内容, 自己处理每个字段的内容
        # 1.读取图片内容,写入到文件夹中,并获取文件的路径
        image_object = form.cleaned_data.get('img')
        db_file_path = os.path.join("static", "img", image_object.name)
        file_path = os.path.join("app01", "static", "img", image_object.name)
        f = open(file_path, mode='wb')
        for chunk in image_object.chunks():
            f.write(chunk)
        f.close()
        # 将图片的文件路径写入到数据库
        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', {
    
    "title": title, "form": form})

10.19.4 启用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<path>.*)', serve, {
    
    'document_root': settings.MEDIA_ROOT}, name='media'),
}

在settings.py中进行配置:

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

10.19.5 案例:混合数据(form)

import os
from django.shortcuts import render, HttpResponse
from django.conf import settings
from app01 import models


def upload_list(request):
    if request.method == "GET":
        return render(request, 'upload_list.html')
    # print(request.POST) # 请求体传递过来的数据
    # print(request.FILES) # 发过来的文件
    file_object = request.FILES.get("avatar")
    # print(file_object.name)
    f = open(file_object.name, mode='wb')
    for chunk in file_object.chunks():
        f.write(chunk)
    f.close()

    return HttpResponse("...")


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', {
    
    "title": title, "form": form})

    form = UpForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        print(form.cleaned_data)
        # 读取到内容, 自己处理每个字段的内容
        # 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()
        # 将图片的文件路径写入到数据库
        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', {
    
    "title": title, "form": form})

案例:混合数据(ModalForm)

在models.py中

class City(models.Model):
    name = models.CharField(verbose_name="名称", max_length=32)
    age = models.IntegerField(verbose_name="人口")
    # 本质上数据也是CharField,帮你自动保存数据,支持upload_to
    img = models.FileField(verbose_name="Logo", max_length=128, upload_to='city/')

定义ModelForm

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

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zhangyifeng_1995/article/details/131379611
今日推荐