首页 > 技术文章 > 初识Django

sec0reluo 2022-02-22 18:27 原文

image-20210111135812562

image-20210111142428322

Django介绍

Django是一个开放源代码的Web应用框架,由python写成。它源自一个在线新闻Web站点,于2005年以开源的形式被释放出来。它采用了MTV的框架模式,即模型M,模板T和 视图V。

Django框架再近年来发展迅速,应用也越来越广泛

image-20210111151102553

D讲哦是一个基于MVC架构构造的框架,但是在Django中,控制器接收用户输入的部分由框架自行处理。所以Django更关注的是模型(Model)、模板(Template)和视图(Views),称为MTV模式。

MVC 模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

MVC 以一种插件式的、松耦合的方式连接在一起。

  • 模型(M)- 编写程序应有的功能,负责业务对象与数据库的映射(ORM)。
  • 视图(V)- 图形界面,负责与用户的交互(页面)。
  • 控制器(C)- 负责转发请求,对请求进行处理。

简易图:

img

用户操作流程图:

img

MTV 模型

Django 的 MTV 模式本质上和 MVC 是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django 的 MTV 分别是指:

  • M 表示模型(Model):编写程序应有的功能,负责业务对象与数据库的映射(ORM)。
  • T 表示模板 (Template):负责如何把页面(html)展示给用户。
  • V 表示视图(View):负责业务逻辑,并在适当时候调用 Model和 Template。

除了以上三层之外,还需要一个 URL 分发器,它的作用是将一个个 URL 的页面请求分发给不同的 View 处理,View 再调用相应的 Model 和 Template,MTV 的响应模式如下所示:

简易图:

img

用户操作流程图:

img

解析:

用户通过浏览器向我们的服务器发起一个请求(request),这个请求会去访问视图函数:

  • a.如果不涉及到数据调用,那么这个时候视图函数直接返回一个模板也就是一个网页给用户。
  • b.如果涉及到数据调用,那么视图函数调用模型,模型去数据库查找数据,然后逐级返回。

视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。

Django项目的创建

安装Django之后,在cmd中使用命令命令 django-admin startproject ttsx 来创建一个名为ttsx的项目。

目录说明:

  • ttsx:** 项目的容器。
  • manage.py: 一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
  • __init__.py: 一个空文件,告诉 Python 该目录是一个 Python 包。
  • /asgi.py: 一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
  • /settings.py: 该 Django 项目的设置/配置。
  • /urls.py: 该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"。
  • /wsgi.py: 一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目。

创建应用

  • 和商品展示有关的应用,叫goods应用。
  • 和购物车相关的应用,叫做cart应用

一个应用中包含了该子业务所有的操作。创建这两个应用的命令如下:

python manage.py startapp goods
python manage.py startapp cart

应用是一个Web应用程序,它完成具体的事项 —— 比如一个博客系统、一个存储公共档案的数据库或者一个简单的投票应用。 项目是一个特定网站中相关配置和应用的集合。一个项目可以包含多个应用。一个应用可以运用到多个项目中。

一个应用就创建成功了,目录如下,来解释下每个文件:

polls/
    __init__.py   # 说明这是个python包
    admin.py   # 管理后台的文件,本次项目中没有用到
    migrations/   # 迁移文件夹,存放一些迁移文件。数据库每次改动都会在这个目录下生成一条记录 
        __init__.py   # 说明这是个python包
    models.py   # models文件,主要编写一些数据库的表结构,字段等。数据库相关操作写入该文件中【模型文件】
    tests.py   # 测试用的文件
    views.py   # 试图函数的文件,大多数我们是在这个文件进行页面逻辑的编写【视图文件】,用来处理逻辑部分

数据库配置

Django ORM

Django 模型使用自带的 ORM。

对象关系映射(Object Relational Mapping,简称 ORM )用于实现面向对象编程语言里不同类型系统的数据之间的转换。

ORM 在业务逻辑层和数据库层之间充当了桥梁的作用。

ORM 是通过使用描述对象和数据库之间的映射的元数据,将程序中的对象自动持久化到数据库中。

img

使用 ORM 的好处:

  • 提高开发效率。
  • 不同数据库可以平滑切换。

使用 ORM 的缺点:

  • ORM 代码转换为 SQL 语句时,需要花费一定的时间,执行效率会有所降低。
  • 长期写 ORM 代码,会降低编写 SQL 语句的能力。

ORM 解析过程:

  • 1、ORM 会将 Python 代码转成为 SQL 语句。
  • 2、SQL 语句通过 pymysql 传送到数据库服务端。
  • 3、在数据库中执行 SQL 语句并将结果返回。

ORM 对应关系表:

img

image-20210111164300169

配置数据库

将ttsx目录中的seting文件中的DATABASE中的信息修改为:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'ttsx',#数据库名,需要进入mysql命令行创建
        'HOST': 'localhost',#数据库的地址
        'PORT': '3306',#mysql端口,默认为3306
        'USER': 'root',#mysql数据库登录用户名
        'PASSWORD': '123456',#mysql数据库登录密码
        
    }

之后在项目文件目录中的__init__文件中修改为如下:

import pymysql
pymysql.install_as_MySQLdb()

数据表和字段介绍

一共需要四张数据库表:

GoodsCategory表,用于存储商品分类信息,它的列包括:

  • 分类显示名称
  • 分类显示样式
  • 分类显示图片

image-20210111171052057

image-20210111171143114

GoodsInfo表,用于存储商品具体信息,它的列包括:

  • 商品名称
  • 商品价格
  • 商品描述
  • 商品分类

image-20210111171756901

image-20210111171802204

商品属于哪个分类,又一个外键关联到主键id

关于购物车的部分,也分为两个表:

OrderInfo表,存储订单基本信息,它的列包括:

  • 订单编号
  • 收货地址
  • 收货人
  • 联系电话
  • 订单运费
  • 订单备注
  • 订单状态

image-20210112104005370

image-20210112104021164

OrderGoods表,存储订单所对应的商品信息,它的列包括:

  • 订单商品
  • 商品数量
  • 所属订单

接下来针对分析得到的表结构,创建对应的模型。要注意的是,自定义模型类需要定义在models.py模块中,并且该类必须继承自models.Model类。

在所创建的应用中,models.py就是用来创建数据表的

需要在models.py中写入模型类

必须继承自models.Model类(models模块下的Model类)

对应数据库中的一张表,表里面的字段就是类中的属性

charfield 表示当前字段是一个字符串

ImageField表示当前字段是一个图片。定义完imagefiled之后,实际在数据库中存储的是图片在服务器中的路径

加上一个upload_to属性,表示当前分类的图片要存储到该属性对应的值的文件夹中

普通字段

AutoField:自增字段,可以随着实例的创建而自动增加.

BooleanField:布尔类型字段,HTML挂件为CheckBoxInput.取值为:Ture/False,不能为null.默认值为None.

NullBooleanField:布尔类型,HTML挂件为NullBooleanSelect,取值为:True/False/null.

CharField:字符串类型的字段,HTML挂件为TextInput,必须接收一个CharField.max_length参数来指定其在数据库中的长度.

DateField:日期字段,使用的是python的datetime.date实例,有几个额外的参数.

DateField.auto_now_add:取值为False/True,作用为自动取值为实例创建的时间,创建于. DateField.auto_now:取值为:False/True,作用为自动设置值为最后一次保存的时间,更新于. auto_now,auto_now_add,default三个选项是互斥的.

DateTimeFild:日期类型,使用的是python 的datetime.datetime实例,参数个DateField一样.

TimeField:日期类型,使用的是python 的datetime.time实例,参数和上述一样.

查询python参考可知,Data主要用于日期,表示年月日,Time主要用于时间,表示时分秒,而DateTime则是完整的年月日时分秒都有.

DecimalField:十进制的浮点数字段,使用的是python的Decimal实例表示十进制的浮点数,也就是小数,Html默认挂件为TextInput,接收两个必须参数:

DecimalField.max_digits:数字的总位数,包括整数和小数部分. DecimalField.decimal_places:小数的位数

FloatField:十进制浮点数类型,使用的是python的float数据类型表示小数.

参考python文档网友博客可知,两者的区别在于精度,decimal是高精度类型.

EmailField:邮件类型,主要用于验证邮件地址的正确性,使用EmailValidator验证.

FileField:文件字段,用于上传文件.添加该字段后,会获得一个FieldFile管理文件

FilePathField:文件名类型,实质是一个CharField类型,只是类容做了限定,只能是文件的路径和名字.

ImageField:图片类型,除了继承自FileField外,还提供了额外的功能,比如图片校验等.需要调用Pillow库.

GenericlIPAdressField:IP地址类型.

SlugField:段标题,主要用于生成url或者其他唯一的链接.

TextField:大文本类型,HTML挂件为Textarea.

URLField:URL类型的字段,根本是CharField.

关系字段

ForeignKey:外键字段,也叫多对一关系,本Model是多,然后关联一个’一’,比如一个人可以写很多文章,那么此时的文正就是多,而人就是一,然后人就是文章的外键.

ForeignKey.limit_choices_to:值为一个字典,筛选出满足一定关系的Model实例,使得本Model的选择只能是满足上述模块的Model实例.

ForeginKry.relate_name:取值为字符串,用于设置本Model在关联实例中的名称.例如:本Model为文章,关联了人作为外键,那么对于人来说,人对他所写的这些文章的称呼就叫做’著作们’,relate_name就表示这个..

则:goods应用中,models.py中的代码如下:

from django.db import models

# Create your models here.

class GoodsCategory(models.Model):
    #分类的名称,max_length 最大长度,字段类型
    cag_name = models.CharField(max_length=30)
    #分类的样式
    cag_css = models.CharField(max_length=20)
    #分类的图片
    cag_img = models.ImageField(upload_to='cag')


#商品表
#模型类
class GoodsInfo(models.Model):
    #商品名字
    goods_name = models.CharField(max_length=100)
    #商品的价格
    goods_price = models.IntegerField(default=0)
    #商品的描述
    goods_desc = models.CharField(max_length=2000)
    #商品图片
    goods_img = models.ImageField(upload_to='goods')
    #商品所属的分类,定义了一个外键
    goods_cag = models.ForeignKey('GoodsCategory',on_delete=models.CASCADE)#上面那个GoodsCategory表所对应的外键





cart模块中models.py中的代码如下:

from django.db import models

# Create your models here.


class OrderInfo(models.Model):
    """订单信息模型"""
    # 定义一个元组,里面存储订单信息
    status = (
        (1,'待付款'),
        (2,'代发货'),
        (3,'待收货'),
        (4,'已完成'),
    )
    #订单编号
    order_id = models.CharField(max_length=100)
    #收获地址
    order_addr = models.CharField(max_length=100)
    #收货人
    order_recv = models.CharField(max_length=50)
    #联系电话
    order_tele = models.CharField(max_length=11)
    #运费
    order_fee = models.IntegerField(default=0)
    #订单备注
    order_extra = models.CharField(max_length=200)
    #订单状态
    order_statu = models.IntegerField(default=1,choices=status)


class OrderGoods(models.Model):
    """订单商品模型"""
    #所属商品
    goods_info = models.ForeignKey('goods.GoodsInfo',on_delete=models.CASCADE)
    #商品数量
    goods_num = models.IntegerField()
    #商品所属订单
    goods_order = models.ForeignKey('OrderInfo',on_delete=models.CASCADE)

如果不写主键,django会默认生成一个id的主键

字段常用选项:

选项类型 描述
null 如果为True,表示允许为空,默认值是False
db_column 字段的名称,如果未指定,则使用属性的名称
db_index 若值为True,则会在表中为此字段创建索引,默认值是False
default 默认值
primary_key 若值为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用
unique 如果为True,这个字段在表中必须有唯一值,默认值是False

创建和执行迁移文件生成表

文件中的代码改变之后,数据库中还没有生成那些表,需要执行一些命令来生成表,这就叫创建和执行迁移文件生成表

在项目目录下,使用命令:

python manage.py makemigrations来创建迁移文件

如果引用外键的地方没有使用到on_delete=models.CASCADE

则会出现报错:

TypeError: __init__() missing 1 required positional argument: 'on_delete'

报错原因:

classForeignKey(to,on_delete,** options)

多对一的关系,需要两个位置参数:模型相关的类和on_delete选项。(on_delete实际上并不需要,但是不提供它会给出弃用警告,这在Django 2.0中将是必需的,**1.8及以前的版本不需要)

要创建递归关系,即:与自身具有多对一关系的对象使用。

models.ForeignKey('self', on_delete=models.CASCADE)

创建迁移文件生成表之后,结构如下:

image-20210112145422876

迁移文件的类记录了每个模块中需要生成的数据表名和字段,来生成create语句。这些语句就是根据当前这些文件的内容来生成的

查看该文件所生成的SQL语句:

python manage.py sqlmigrate goods 0001.py

C:\Users\AdminLuo\Desktop\ttsx>python manage.py sqlmigrate goods 0001
--
-- Create model GoodsCategory
--
CREATE TABLE `goods_goodscategory` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `cag_name` varchar(30) NOT NULL, `cag_css` varchar(20) NOT NULL, `cag_img` va
rchar(100) NOT NULL);
--
-- Create model GoodsInfo
--
CREATE TABLE `goods_goodsinfo` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `goods_name` varchar(100) NOT NULL, `goods_price` integer NOT NULL, `goods_desc`
varchar(2000) NOT NULL, `goods_img` varchar(100) NOT NULL, `goods_cag_id` integer NOT NULL);
ALTER TABLE `goods_goodsinfo` ADD CONSTRAINT `goods_goodsinfo_goods_cag_id_a7b17a2d_fk_goods_goodscategory_id` FOREIGN KEY (`goods_cag_id`) REFERENCES `goods_goods
category` (`id`);
CREATE INDEX `goods_goodsinfo_goods_cag_id_a7b17a2d` ON `goods_goodsinfo` (`goods_cag_id`);

注:当前只是生成了语句,还没有执行。

使用命令python manage.py migrate来执行:

C:\Users\AdminLuo\Desktop\ttsx>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, cart, contenttypes, goods, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying goods.0001_initial... OK
  Applying cart.0001_initial... OK
  Applying sessions.0001_initial... OK

数据库操作

插入操作

数据库操作需要使用 python manage.py shell进入命令行进行操作

进入之后,需要导入goods下的models.py文件from goods.models import *

导入之后,就可以执行插入操作:

categories = [('时令水果','fruit',1),('海鲜水产','seafood',2)
             ('全品肉类','meet',3),('美味蛋品','egg',4)
             ('新鲜蔬菜','vegetaables',5),('低温奶制品','ice',6)]

for cag in categories:
    c = GoodsCategory()#实例化该模型类 
    c.cag_name = cag[0]
    c.cag_css = cag[1]
    c.cag_img = 'images/banner0%d.jpg'%cag[2]  #使用占位符
    c.save()			#执行insert操作

image-20210213102935997

注:暂时还没有该项目所需要使用的图片,无法解析图片地址

接下里再以同样的方式向数据库中插入一条商品数据

from goods.models import *
goods = GoodsInfo()#创建实例化对象
goods.goods_name = '新疆库尔勒香梨5斤'
goods.goods_price = 79
goods.goods_img = 'xiangli'
goods.goods_desc = '库尔勒香梨果面光滑,香气浓郁,酥脆可口'
goods.goods_cag_id = 1	#django会自动生成goods_cag_id属性,用来关联外键id
goods.save()

image-20210213102916434

查询操作

查询操作是项目中使用最多的数据库操作,本项目主要用到了Django框架提供的以下3个方法:

  • get方法:查询一条数据,如果返回结果有多条就会报错,如果没有也会报错
    • 如果匹配到的对象有多个,则get方法会触发MultipleObjectsReturned异常
    • 如果查询不到结果,则将触发DoesNotExist异常

image-20210214135342833

  • all方法:获得所有数据

all方法还可以进行切片

image-20210214135530258

所查询出来的是对象,输出使用以下语法:

image-20210214135721221

  • filter方法:根据条件过滤数据

虽然使用all方法能够获得一张数据库表中的所有数据的集合,但是在通常情况下,我们往往只需要获取满足特定条件的部分数据。这时,就可以使用filter方法来查询

image-20210214140820000

查询之前,需要导入模型类

GoodsInfo.objects.get(goods_name = '库尔勒香梨') #GoodsInfo模型类下有一个django提供的属性,为objects(称之为管理器,其中封装了模型类的增删改查的方法),其有一个get方法

该语句执行完之后,会返回一个当前goodsinfo的实例化对象

更新操作

Django创建和更新对象使用了同一个方法sava() 。当调用save()方法保存数据的时候,Django会判断当前对象是否有主键,如果逐渐存在则执行更新操作,如果主键不存在则执行插入操作。例如以下代码,将数据库中的商品“库尔勒香梨”的价格进行了修改:

goods = GoodsInfo.objects.get(goods_name='新疆库尔勒香梨5斤')
goods.goods_price = 100
goods.save()

删除操作

删除操作使用了管理器对象的delete方法。例如,以下代码将名为‘新疆库尔勒香梨5斤’的商品进行删除

goods = GoodsInfo.objects.get(goods_name='新疆库尔勒香梨5斤')
goods.delete()
#删除之后如果再执行查询语句,会报错

数据库操作一般都是使用当前你要操作的当前的模型类的objects管理器的方法来完成的

创建视图

视图就是一个函数

goods应用模块下的views.py文件

必须传递一个参数 request 请求对象 里面有用户发送的请求信息,比如url地址和其他数据 注:request可以随便命名

修改之后,goods/views.py文件内容如下:

from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.
def index(request):

    return HttpResponse('hello django')

ttsx/urls.py的文件内容如下:

"""ttsx URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path

from goods.views import index

urlpatterns = [
    path('admin/', admin.site.urls),
    #参数一:要访问的url地址的正则匹配
    #参数二:要访问的视图的函数名字
    path('index/',index ),
]

之后runserver,看到以下页面说明运行成功:

image-20210214145559806

模板文件的配置和使用

再项目根目录下新建一个文件夹,命名为templates(可以随意命名)

新建一个index.html文件

BASE_DIR为项目的跟路径的绝对路径地址

再项目目录中的setting.py文件中修改TEMPLATES中的'DIRS': [],'DIRS': [os.path.join(BASE_DIR,'templates')],

注:需要先导入os模块【import os】

之后修改视图文件views.py中的index函数为:

def index(request):
    
    #render函数中,参数一是请求的request对象
    #             参数二是需要返回的html页面
    return render(request,'index.html')

推荐阅读