Django框架使用_环境搭建_创建项目_基本使用_Django进阶

Django框架使用

1、Django框架简介与环境搭建

##Django是python写的重量级开源web框架,它组件丰富、向用户提供完整的开发文档,使用Django可以用少量的代码就能完成一个网站的大部分内容,极大的提高了开发效率。
##Django基于MVC模型(模型+视图+控制器)设计,该模型应用使Django项目的修改、拓展和代码复用变得更加方便和容易,同时Django还强调快速开发和DRY原则(Do Not Repeat Youself),而基于MVC框架Django有一个自己的名字MVT。

1.1 MVC框架简介

MVC框架的运行流程,以用户登录为例,它有这么几个步骤:
Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第1张图片

当用户点击注册时,用户名密码被提交到服务器;由控制器C去接收页面提交的数据;再由M将用户名和密码保存进数据库,然后数据库返回保存结果,并将结果传回给控制器C,然后通过V产生html页面,再由C将页面返回给浏览器。

  • M: Model模型, 和数据库进行交互。
  • V: View视图,用于处理业务逻辑,产生html页面或数据(Django中为T)。
  • C: Controller控制器,接受请求,进行处理,并与M和V交互,返回应答(Django中为V)。

1.2 Django项目和应用创建

  • 安装Django环境:

    pip install django pip install django==版本号

  • 创建项目:

    	django-admin startproject 项目名
    

    项目目录结构(以test1项目为例):
    Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第2张图片

    • test1: 项目管理目录,在项目目录下,与项目目录同名
      • __ init__.py: 说明test1目录是一个python包
      • settings.py: 项目配置文件
      • urls.py: 用于url路由的配置
      • wsgi.py:服务器和Django项目交互入口
    • manage.py: 项目管理文件,在项目目录下
  • 创建应用(先要进入到项目中)

       python manage.py startapp 应用名
    

    此处创建的应用为booktest。
    一个项目通常由多个不同的功能模块组成,在Django中每个功能模块用一个Django应用来开发,每一个应用完成一个特定的功能,所以在开发之前先要进行功能模块的划分。
    应用目录结构:

Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第3张图片

	 - __init__.py: 说明booktest目录是一个python模块
	 - models.py: 用于写和数据库相关的内容
	 - views.py: 接受请求,处理请求,与M和T进行交互,返回应答,在该文件中定义**视图函数**
	 - tests.py: 用于写测试代码
	 - admin.py: 用于网站后台管理
	 - apps.py: 表示当前应用
	 - 目录migrations: 存放迁移文件
至此,项目和应用都已创建,但是要开发这个应用。还需要建立项目与应用之间的关系,即注册该应用。
  • 建立项目和应用之间的关系(注册应用)

    注册应用要在项目配置文件settings.py的INSTALLED_APPS中加入刚刚创建的应用名称。
    Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第4张图片
    在INSTALLED_APPS项中加入刚刚创建的应用名称:

    	INSTALLED_APPS = [
    		    'django.contrib.admin',
    		    'django.contrib.auth',
    		    'django.contrib.contenttypes',
    		    'django.contrib.sessions',
    		    'django.contrib.messages',
    		    'django.contrib.staticfiles',
    		    'booktest' # 注册应用
    		]
    
  • 启动项目,看项目有没有创建成功

    	# 注意要先进入项目中,默认8000端口
    	python manage.py runserver
    	# 如果提示端口被占用,换个端口
    	python manage.py runserver 127.0.0.1:8001
    

在浏览器地址栏中输入127.0.0.1:8000(此处写你自己定义的端口号)如果出现以下,说明项目创建成功。
Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第5张图片

2、Django的基本使用

2.1 ORM框架介绍

ORM(对象关系映射),它的作用是建立对象与关系型数据库表之间的映射,通过类和对象操作对应的数据表,避免了写复杂的SQL语句;ORM另一个作用是根据模型类迁移生成对应的数据表。Django中内置了ORM框架,在应用下的models.py文件中设计模型类。

  • 定义模型类

    	# 在booktest(应用)下的models.py文件中
    	from django.db import models
    
    	# Create your models here.
    	# 设计和表对应的类
    	
    	# 定义图书类(一类)
    	class BookInfo(models.Model):
    	    """图书模型类"""
    	    # id会自动生成
    	    # 字段名称,书名
    	    book_title = models.CharField(max_length=20)
    	    # 出版日期
    	    public_date = models.DateField()
    

    我们的目的是根据这个定义的模型类,生成数据库中对应的表,在Django中生成模型类对应的表两步走:

  • 进入项目中,在终端执行迁移:

    	# 第一步 生成迁移文件
    	python manage.py makemigrations
    	# 第二步 执行迁移生成表
    	python manage.py migrate
    

得到以下结果说明迁移成功:
Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第6张图片迁移成功之后我们在pycharm右侧数据库中可以看到已成功生成数据库:Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第7张图片

表中字段名称和模型类中的字段名称是一致的,表名格式是: 应用名_模型类名。注意Django默认数据库是sqlite3数据库,可以在项目配置文件settings.py中修改DATABASES配置项,将数据库换成mysql或其他。

2.2 通过模型类去操作数据表

先进入项目shell:

python manage.py shell

以下操作在终端中执行:

	# 导入模型类
	In [1]: from booktest.models import BookInfo
	# 实例化模型类
	In [2]: b = BookInfo()
	"""添加数据"""
	# 添加书名
	In [3]: b.book_title = "水浒传"
	# 导入日期模块
	In [4]: from datetime import date
	# 添加出版日期
	In [5]: b.public_date = date(2000,1,1)
	# 存入数据库
	In [6]: b.save()
	"""查询数据"""
	# 模型类.objects.get(条件)
	In [7]:  book_sh = BookInfo.objects.get(id=1)
	In [10]: book_sh.book_title
	Out[10]: '水浒传'
	In [11]: book_sh.public_date
	Out[11]: datetime.date(2000, 1, 1)
	"""修改数据"""
	In [12]: book_sh.public_date = date(2001,1,1)
	# 要保存一下,才能修改成功
	In [13]: book_sh.save()
	In [14]: book_sh.public_date
	Out[14]: datetime.date(2001, 1, 1)  # 可以看到出版日期已修改
	"""删除"""
	In [15]: book_sh.delete()
	"""退出终端"""
	In [16]: quit()

Django模型常用字段与属性:

字段名称 字段描述
CharField 字符串类型,必须设置max_length
IntergerField 整数类型,可设置默认值default
FloatField 小数类型,可设置默认值default, 其他参数同下
DecimalField 小数类型,参数max_digit表示总位,参数decimal_places表示位数
EmailField 邮箱格式字符串
TextField 文本类型
DateField 日期类型 , 参数auto_now_add=True表示创建时间,不需要给他传参数
FileField 文件类型,可以保存文件路径,同时自动上传文件,必须设置upload_to上传到媒体路径下的位置
ImageField 图片文件类型,可以保存文件路径,同时自动上传文件,必须设置upload_to上传到媒体路径下的位置
- -
属性名称 属性描述
default 设置默认值
primary_key 值为True,则该字段是主键,默认False
unique True,表示这个字段在表中只能出现一次,默认False
db_index True,则会在表中为此字段建立索引,默认False
db_columen 指定字段名称, 默认使类属性名称
null True,表示允许为空,默认为False。数据库的范畴
blank True,表示允许在后台管理添加数据时不填,默认为False

2.3 模型类一对多关系建立及关系查询

  • 建立图书类与英雄类之间一对多关系

    	# 定义图书类(一类)
    	class BookInfo(models.Model):
    	    """图书模型类"""
    	    # id会自动生成
    	    # 字段名称,书名
    	    book_title = models.CharField(max_length=20)
    	    # 出版日期
    	    public_date = models.DateField()
    	
    	
    	# 英雄人物类(多类)
    	# 英雄名 性别 年龄 备注
    	# 图书类与英雄人物类之间是一对多关系
    	class HeroInfo(models.Model):
    	    """英雄人物类"""
    	    # 英雄名
    	    hero_name = models.CharField(max_length=20)
    	    # 性别 BooleanField为布尔值, 默认False(男性)
    	    hero_gender = models.BooleanField(default=False)
    	    # 备注
    	    hero_demo = models.CharField(max_length=128)
    	    # 年龄
    	    hero_age = models.IntegerField()
    	    # 外键 图书类与英雄类之间的一对多关系,多表中有一个外键
    	    """多类中定义关系属性"""
    	    hero_book = models.ForeignKey(to='BookInfo', on_delete=models.CASCADE)
    

    定义完模型类,再次执行迁移,会在数据库中看到以下结果: Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第8张图片

  • 一对多关系操作
    以下操作在shell中执行: python manage.py shell 进入shell

    		"""一对多基本操作"""
    		# 导入模型类
    		In [1]: from booktest.models import BookInfo, HeroInfo
    		# 实例化一个图书模型类
    		In [2]: b = BookInfo()
    		# 导入日期函数
    		In [3]: from datetime import date
    		
    		# 实例化英雄模型类
    		In [4]: h = HeroInfo()
    		
    		# 添加一个英雄的信息
    		In [5]: h.hero_name = "林冲"
    		In [6]: h.hero_gender = False
    		In [7]: h.hero_age = 10
    		In [8]: h.hero_demo = "豹子头林冲"
    		
    		# 取出水浒传(id=1)
    		In [9]: book_sh = BookInfo.objects.get(id=1)
    		"""关联"""
    		# 关联英雄类与图书类
    		In [10]: h.hero_book = book_sh
    		
    		# 保存
    		In [11]: h.save()
    		"""一查多"""
    		# 查询一本书中所有的英雄(一查多: 一.多类名小写_set.all())
    		# 得到的结果是对象集合
    		In [12]: book_sh.heroinfo_set.all()
    		Out[12]: <QuerySet [<HeroInfo: HeroInfo object (1)>]>
    

查询函数
通过 模型类.objects 属性可以调用如下函数,实现模型类对数据表 的快速操作

函数名 功能 返回值 说明
get 返回表中满足条件的一条且只能有一条数据 模型类对象 查询到多条会抛出异常
all 返回表中满足条件的所有数据 QuerySet 返回值称作查询集
filter 返回满足条件的数据 QuerySet filter查询方法
exclude 返回不满足条件的数据 QuerySet 和filter用法一致,只是返回的数据和filter返回的数据相反
order_by 对查询结果进行排序 QuerySet 参数中写根据哪些条件进行排序
Q对象 用于查询条件之间的逻辑关系,not and or,可以对Q对象进行& ~ QuerySet 使用之前需要先导入form django.db.models import F 使用方法
F对象 用于属性之间的比较 QuerySet 使用之前需要先导入form django.db.models import Q
除上述用法之外,还有聚合函数。而QuerySet(得到的结果)还可以继续调用上述方法。query.exists()可以查询查询集是否为空,False为空。

2.4 Django后台管理

后台管理的作用: 帮助我们管理数据表
Django提供了强大的后台管理功能,由应用下的admin.py管理。使用它需要执行以下步骤:

  • 本地化

      - 语言和时区本地化
      - 修改项目配置文件settings.py中的语言和时区项
      - `LANGUAGE_CODE = 'zh-hans'`
      - `TIME_ZONE = 'Asia/Shanghai'`
    
  • 创建管理员账户

    	python manage.py createsuperuser
    

    Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第9张图片

    登录后台管理页面:

    • 先启动Django项目:python manage.py runserver
    • 进入后台管理界面:http://127.0.0.1:8000/admin
    • 进去之后啥也没有,这时候就需要对模型类进行注册
  • 注册模型类

    应用下的admin.py中注册模型类,告诉Django框架根据注册的模型类来生成对应的管理界面。

    	from django.contrib import admin
    	# 导入图书模型类(其它模型类的注册方法也是一样的)
    	from .models import BookInfo
    	# Register your models here.
    	# 注册图书模型类
    	admin.site.register(BookInfo)
    

    注册完显示以下界面:Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第10张图片
    注册完可以在Django后台管理数据表,对表中的数据进行增删改查。

  • 自定义Django后台管理页面
    虽然已经将模型类注册,但是进去发现显示的信息不是我们想要的,此时就需要自定义模型管理类,来美化Django后台管理页面。

    	class BookInfoAdmin(admin.ModelAdmin):
    	    """自定义图书模型管理类"""
    	    # 定义要显示的字段列表
    	    list_display = ['id', 'book_title', 'public_date']
    
    	# 注册图书模型类,将自定义的模型管理类也传入register
    	admin.site.register(BookInfo, BookInfoAdmin)
    	"""其他模型类的注册方式也是一样的"""
    

写完之后,刷新后台管理页面,发现定义的字段已经显示出来了:
Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第11张图片

2.5 视图函数的使用

在Django中,通过浏览器去请求一个页面时,是使用视图函数来处理这个请求的,视图函数处理之后,要给浏览器返回页面内容。

  • 定义视图函数
    视图函数定义在应用下的views.py中,此时我们只有一个应用那么就在booktest应用目录下的views.py中定义视图函数,视图函数就是python中普通的函数,定义一个index视图函数当用户输入http://127.0.0.1:8000/index显示Hello, Django!:

    from django.shortcuts import render
    from django.http import HttpResponse
    
    # Create your views here.
    # 第一步定义视图函数
    # 第二步进行url配置,目的是建立url地址和视图之间的关系
    def index(request):
        """用户输入http://127.0.0.1:8000/index显示"""
        # 此处写处理,与M和T进行交互
        # 最终需要返回一个HttpResponse对象
        return HttpResponse("Hello, Django!")
    

    为了让Django知道URl对应的视图函数是这个视图函数,还需要进行URL配置

  • 配置URL
    首先在应用目录下面(此处是booktest)新建一个urls.py;然后在项目管理目录下的urls.py中加配置项:

    	"""项目管理目录下的urls.py中"""
    	from django.conf.urls import url
    	from django.contrib import admin
    	from django.urls import path, include
    	
    	# 项目的urls文件
    	urlpatterns = [
    	    path('admin/', admin.site.urls),  # 配置项
    	    url(r'^', include('booktest.urls')),  # 包含刚刚创建的应用booktest里面的urls文件
    	]
    

    然后回到刚刚新建的应用目录下面(此处是booktest)的urls.py中,通过URL函数建立视图函数和路由之间的关系:

    	"""应用目录下面(此处是booktest)的urls.py"""
    	from django.conf.urls import url
    	from . import views
    	
    	urlpatterns = [
    	    # 通过url函数设置url路由的配置项
    	    url(r'^index', views.index),  # 建立index视图和index路由之间的关系
    	]
    

    访问http://127.0.0.1:8000/index,成功显示:
    Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第12张图片
    当我们通过浏览器输入一个地址时,Django拿到的是去除域名后的这部分(/不参与匹配),它会拿这一部分先到项目的urls.py中进行查找,也就是和urlpatterns中的路由配置项正则表达式进行匹配; 匹配成功就执行include里面的动作,然后找到应用中的urls.py, 继续和URL函数设置的路由配置项进行匹配,匹配成功就执行该配置项中的视图函数,然后再由视图函数返回HttpResponse,渲染到页面就是我们看到的内容。
    为了让HttpResponse返回一个标准的html页面,就需要使用模板。

2.6 模板文件的使用

在上面的例子中,我们返回了一个字符串,要返回一个标准的HTML页面,就需要使用模板。Django中的模板不仅仅可以返回HTML文件,也可以返回变量,甚至是代码。

  • 创建模板目录templates
    项目目录下新建一个模板文件夹,以后所有的模板文件将放入这个文件夹:
    Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第13张图片
    建好模板目录之后,需要配置模板目录。

  • 配置模板目录
    在项目管理目录下的项目管理文件settings.py中,修改TEMPLATES项下的DIRS

    	TEMPLATES = [
    	    {
    	        'BACKEND': 'django.template.backends.django.DjangoTemplates',
    	        # BASE_DIR是项目所在绝对路径
    	        'DIRS': [os.path.join(BASE_DIR, 'templates')],
    	        'APP_DIRS': True,
    	        'OPTIONS': {
    	            'context_processors': [
    	                'django.template.context_processors.debug',
    	                'django.template.context_processors.request',
    	                'django.contrib.auth.context_processors.auth',
    	                'django.contrib.messages.context_processors.messages',
    	            ],
    	        },
    	    },
    	]
    
  • 使用模板文件
    Django中使用模板文件有四步:

    • 加载模板文件
    • 定义模板上下文,给模板文件传递数据
    • 模板渲染,产生标准的HTML内容
    • 给浏览器返回一个HttpRequest对象

    Django内部提供了一个render方法,使用时直接调用即可。
    重新定义模板文件(在应用下的views.py中):

    	from django.shortcuts import render
    	from django.http import HttpResponse
    	
    	# Create your views here.
    	# 第一步定义视图函数
    	# 第二步进行url配置,目的是建立url地址和视图之间的关系
    	
    	# def index(request):
    	#     """用户输入http://127.0.0.1:8000/index显示"""
    	#     return HttpResponse("Hello, Django!")
    	
    	def index(request):
    	    """用户输入http://127.0.0.1:8000/index显示"""
    	    # return HttpResponse("Hello, Django!")
    	    return render(request, 'booktest/index.html', {'content': "Hello, Django!"})
    

    渲染模板
    根据你使用的数据,替换页面上的显示的数据:

    	DOCTYPE html>
    	<html lang="en">
    	<head>
    	    <meta charset="UTF-8">
    	    <title>模板文件title>
    	head>
    	<body>
    	    <h3>这是一个模板文件h3>
    	    <h4>这是渲染过来的的数据:h4>
    	    /*jinjia2渲染模板*/
    	    <p>{{ content }}p>
    	body>
    	html>
    

    刷新页面显示:
    Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第14张图片

3、Django 后端配置、重定向、模型进阶(M)

**回顾:**
- 1.创建Django项目:django-admin startproject  项目名称
- 2.**进入项目**创建应用: python manage.py startapp 应用名称
- 3.在项目配置文件 settings.py中 注册app: 将app名加入到INSTALLED_APPS项中
- 4.本地化项目: 在 项目配置文件settings.py中 修改 LANGUAGE_CODE 与 TIME_ZONE
- 5.启动项目: python manage.py runserver
- 完成以上步骤,就可以进行基本开发了

多数时候,我们SQLITE数据库不能满足开发需要,通常我们使用MySQL数据库进行开发,那就需要配置MySQL数据库。

3.1 Django配置MySQL数据库

	"""在项目配置文件settings.py中"""
	DATABASES = {
	    'default': {
	        # 'ENGINE': 'django.db.backends.sqlite3',
	        'ENGINE': 'django.db.backends.mysql',
	        # 'NAME': BASE_DIR / 'db.sqlite3',
	        'NAME': 'test',  # mysql数据库名,注意这个数据库必须手动建好,否则报错
	        'USER': 'root',   # mysql用户名
	        'PASSWORD': 'root',  # 用户名对应的密码
	        'HOST': 'localhost',   # 指定mysql地址,此处是本地
	        'PORT': 3306  # 端口号
	    }
	}

然后启动项目,可能会出现以下错误:

django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
Did you install mysqlclient?

这时候按Ctrl+C退出,在应用下的__init__.py中添加下面两句:

	"""应用下的__init__.py中"""
	# 未安装pymysql,先安装pymysql
	import pymysql
	pymysql.install_as_MySQLdb()

重新启动项目,启动成功!
Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第15张图片

3.2 重定向

Django中的重定向: 当视图函数处理完成一个逻辑后,不需要向浏览器呈现数据,而是转回到其它页面(可以理解为调用其它的视图函数),给出一个大佬的博客Django重定向的几种方法。

3.3 模型进阶

  • 模型类关系

    • 一对多关系
      models.ForeignKey()定义在多的类中
      比如图书模型类与英雄模型类:

      	# to参数为一类类名
      	hero_book = models.ForeignKey(to='BookInfo', on_delete=models.CASCADE)
      
    • 多对多关系
      models.ManyToManyField() 定义在哪个类中都可以
      比如新闻模型类与新闻类型模型类:

      	# 新闻类型类
      	class NewsType(models.Model):
      	    # 新闻类型名
      	    type_name = models.CharField(max_length=20)
      	    """关系属性,也可以定义在新闻模型类中"""
      	    type_news = models.ManyToManyField(to='NewsInfo')
      	
      	
      	# 新闻类
      	class NewsInfo(models.Model):
      	    # 新闻标题
      	    news_title = models.CharField(max_length=128)
      	    # 发布时间
      	    news_date = models.DateField(auto_now_add=True)
      	    # 信息内容
      	    news_content = models.TextField()
      
    • 一对一关系
      models.OneToOneField() 定义在哪个类中都可以
      比如员工基本信息类与员工详细信息类,员工工号唯一

      	# 员工基本信息类
      	class EmployeeBasicInfo(models.Model):
      	    employ_name = models.CharField(max_length=20)
      	    employ_age = models.IntegerField()
      	    employ_gender = models.BooleanField(default=False)
      	    """关系属性,也可以定义在员工详细信息模型类中"""
      	    detail_employ = models.OneToOneField(to='EmployeeDetailInfo', on_delete=models.CASCADE)
      	
      	
      	# 员工详细信息类
      	class EmployeeDetailInfo(models.Model):
      	    employ_addr = models.CharField(max_length=256)
      	    employ_tel = models.CharField(max_length=20)
      
  • 一对多关联查询(通过模型类实现)
    在一对多关系中,一对应的类叫做一类,多对应的类叫做多类,我们把类中建立模型类与模型类关联的属性叫做关系属性。
    通过对象查询的方法:

    • 由一类的对象查询多类的时候:

      	一类的对象.多类名小写_set.all()
      
    • 由多类的对象查询一类的时候:

      	多类的对象.关联属性
      
    • 由多类的对象查询一类对象的id的时候:

      	多类的对象.关联属性_id
      

    通过模型类实现关联查询的方法:

    • 通过多类的条件查询一类的数据:

       	一类名.objects.filter(多类名小写__多类属性名__条件名)
      
    • 通过一类的条件查询多类的数据:

       	多类名.objects.filter(关联属性__一类属性名__条件名)
      

    例1:查询id为1的图书关联的英雄的信息:

    • 原来的查询方法(根据对象去查询):

      	# 先查询id为1的图书
      	b = BookInfo.objects.get(id=1)
      	# 再用这个[书]去查询它里面的英雄
      	b.heroinfo__set.all()
      
    • 通过模型类查询

      	# 通过一类的条件查询多类的数据
      	HeroInfo.objects.filter(hero_book__id=1)
      

    例2:查询id为1的英雄关联的图书的信息:

    • 原来的查询方法(根据对象去查询)

      	# 先查询id为1的英雄
      	h = HeroInfo.objects.get(id=1)
      	# 然后再用这个[英雄]去查和他相关的那本书
      	# hero_book是关系属性名
      	h_book =h.hero_book
      
    • 通过模型类查询

      	 # 通过多类的条件查询一类的数据
      	 # 	一类名.objects.filter(多类名小写__多类属性名__条件名)
      	 BookInfo.objects.filter(heroinfo__id=1)
      

    例3:查询图书信息,要求图书中英雄的描述包含’八’:

    • 通过模型类查询
      	# 通过多类的条件查询一类的数据
      	# 一类名.objects.filter(多类名小写__多类属性名__条件名)
      	BookInfo.objects.filter(heroinfo__hero_dmeo__contains='八')
      

    例4:查询图书信息,要求图书中的英雄的id大于3:

    • 通过模型类查询

      	# 通过多类的条件查询一类的数据
      	# 一类名.objects.filter(多类名小写__多类属性名__条件名)
      	BookInfo.objects.filter(heroinfo__id__gt=3)
      

    例5:查询书名为天龙八部的所有英雄:

    • 通过模型类查询

      	# 通过一类的条件查询多类的数据
      	# 多类名.objects.filter(关联属性__一类属性名__条件名)
      	HeroInfo.objects.filter(hero_book__book_title='天龙八部')
      
  • 模型-自关联
    所谓的自关联是一种特殊的一对多关系,只是这种一对多关系对用的数据都在一张表里。
    以地区自关联模型为例(最终结果是做一个显示徐州上下级地区的功能):

    • 定义地区模型类

      	# 地区模型类
      	class AreaInfo(models.Model):
      	    # 地区名称
      	    area_title = models.CharField(max_length=128)
      	    # 关系属性,代表当前地区的父级地区,null表示可以为空,self参数表示自关联
      	    area_parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)
      
    • 注册模型类

      	"""在应用下的admin.py中"""
      	# 注册地区模型类
      	admin.site.register(AreaInfo)
      
    • 迁移生成数据库

      	# 生成迁移文件
      	python manage.py makemigrations
      	# 执行迁移
      	python manage.py migrate
      
    • 向表中添加数据
      Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第16张图片

    • 定义视图函数

      	"""在应用下的views.py中"""
      	def areas(request):
      	    """获取徐州市的上几地区和下级地区"""
      	    # 获取徐州市的信息
      	    area = AreaInfo.objects.get(area_title='徐州市')
      	    # 查询徐州市的上级地区
      	    parent = area.area_parent
      	    # 查询江苏省的下级地区
      	    children = area.areainfo_set.all()
      	    # 使用模板
      	    return render(request, 'booktest/areas.html', {'area':area, 'parent':parent, 'children':children})
      
    • 配置路由

      """在应用下的urls.py中"""
      	from django.conf.urls import url
      	from . import views
      	
      	urlpatterns = [
      	    url(r'^index', views.index), 
      	    url(r'^areas', views.areas)  # 显示地区
      	]
      
    • 在地址栏输入

      	http://127.0.0.1:8000/areas
      

      Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第17张图片

  • 模型_管理器
    在查询的时候,BookInfo.objetcs.all()中的objects是什么呢?其实它是Django帮我们给每一个模型类自动生成的管理器对象,通过这个管理器可以实现对数据的查询。
    objects是models.Manger类的一个对象。当我们自定义管理器之后,Django不再帮我们生成默认的objects管理器。

    • 自定义管理器步骤

      • 自定义一个管理器类,这个类继承models.Manger类
      • 再在具体的模型类里定义一个自定义管理器对象
    • 自定义管理器类的应用场景:

      • 改变查询的结果集:比如将BookInfo.objects.all()让它返回没有删除的的图书的数据。
      • 添加额外的方法:管理器中定义一方法帮我们操作模型类对应的数据表。

    不过一般情况下,我们也不去修改这个东西,如果需要自定义管理器请参照Django开发文档(我的电脑不知道为什么进不了Django官网,在此就不放链接了)。

  • 模型元选项_指定模型类对应的表名
    当我们指定了模型类对应的表名之后,就可以随意修改应用名而不使程序因为修改应用名发生错误了。
    方法: 在模型类中再定义一个Meta类,然后将Meta类的类属性db_table = 指定的表名即可。
    以图书类为例:

    	# Create your models here.
    	# 建立图书模型类, 一类
    	class BookInfo(models.Model):
    	    book_title = models.CharField(max_length=20)
    	    public_date = models.DateField()
    	    book_read = models.IntegerField(default=0)
    	    book_comment = models.IntegerField(default=0)
    	    # 逻辑删除标记(软删除)
    	    is_delete = models.BooleanField(default=False)
    	    
    	    class Meta:
    	        """将图书模型类对应的表名指定为bookinfo"""
    	        db_table = 'bookinfo'
    	
    	    def __str__(self):
    	        return self.book_title
    

4、视图进阶

4.1 回顾

  • 视图的功能
    视图的功能:接受请求,进行处理,与M和T交互,返回应答。
    返回应答是html:render,也可能是重定向:redirect,还可能是JsonResponse。

  • 视图函数的使用

    • 定义视图函数
      视图函数就是一个普通的函数,必须要有request参数。这个request参数是一个HttpRequest类型的对象,参数名可以变化,但是不建议更改。

    • 配置url
      目的是建立url和视图函数之间的对应关系。

    • 定义模板文件
      有模板文件就在templates下面配置html文件

  • url配置的过程

    • 项目的urls文件中包含具体应用的urls文件,在具体应用的urls文件中包含具体url和视图的对应关系。
    • url配置项是定义在一个名叫urlpatterns的列表中,其中的每一个元素就是一个配置项,每一个配置项都调用url函数。
      Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第18张图片

4.2 视图进阶

  • 视图_错误视图
    当用户输入一个你的网站不存在的地址时,会显示Page not found(404)和项目url配置信息,这样url配置信息将会全部暴露给用户,为了避免这个问题,当项目开发完之后,要将项目配置文件settings.py中的DEBUG设置为False。然后刷新,将不会再出现项目url的配置信息,而是返回一个标准的404页面。有时候我们想返回一个自定义的404页面,那么应该怎么做?

    • 自定义404页面
      直接在Django项目模板目录templates(不是某个应用)下新建一个404.html,当用户输入一个不存在的地址出现url配置错误没有配置URl时,Django会自动返回这个页面。

    • 自定义500页面
      500是视图函数中出现了错误。同样的,如果你不想用Django默认的500页面,那么同样在Django项目模板目录templates下新建一个500.html,出现视图函数错误时,Django会自动返回这个页面。

  • 视图_捕获URL参数
    进行url匹配时,把所需要的捕获的部分设置成一个正则表达式组,这样Django框架就会自动把匹配成功后相应组的内容作为参数传递给视图函数。有两种类型:

    • 捕获位置参数
      参数名可以随意指定

      	"""在应用下的urls.py中定义url配置项"""
      	from django.conf.urls import url, include
      	from django.contrib import admin
      	from django.urls import path
      	from . import views
      	urlpatterns =[
      	    url(r'^index', views.index),
      	    # 定义一个测试的url,当输入这个地址时,Django会将组匹配到的参数传递给后面的视图函数
      	    url(r'test(\d+)', views.test),  # 捕获url位置参数,只要你捕获了参数,那么在定义相应的视图函数时,必须要有形参
      	]
      	
      	"""在应用下的views.py中定义测试url对应的视图函数"""
      	def test(request, para):
      		# para为捕获到的参数
          	return HttpResponse(para)
      
    • 捕获关键字参数
      在位置参数的基础上给正则表达式组命名即可。需要注意的是视图函数形参命名必须和该参数对应的组名一致。

      	"""在应用下的urls.py中定义url配置项"""
      	from django.conf.urls import url, include
      	from django.contrib import admin
      	from django.urls import path
      	from . import views
      	urlpatterns =[
      	    url(r'^index', views.index),
      	    # 定义一个测试的url,当输入这个地址时,Django会将组匹配到的参数传递给后面的视图函数
      	    url(r'^test(\d+)', views.test),  # 捕获url位置参数,只要你捕获了参数,那么在定义相应的视图函数时,必须要有形参
      	    # 需要注意的是视图函数形参命名必须和该参数对应的组名一致
      	    url(r'^test(?P\d+)', views.test),  # 捕获url关键字参数,只要你捕获了参数,那么在定义相应的视图函数时,必须要有形参
      	]
      
      	"""在应用下的views.py中定义测试url对应的视图函数"""
      		def test(request, num):
      			# para为捕获到的参数,参数名和正则表达式捕获到的组名一致
      	    	return HttpResponse(num)
      
  • 视图函数的参数的作用

    • 默认的request
      接受HttpRequest对象,也是视图的第一个参数。该对象包含了浏览器请求的参数,比如请求头、请求参数之类的东西。通过post/get请求提交的参数就保存在该对象中。

    • HttpRequest对象属性
      在视图函数中可以直接用request.属性名调用

      • path:一个字符串,表示请求页面的完整路径,不含域名和参数部分。
      • method:字符串,表示请求方式。
      • encoding:字符串,表示提交的数据的编码方式。
      • GET/POST:QueryDict类型对象,类似于字典,包含get/post请求的请求参数。
      • FILES:一个类似于字典的对象,包含所有的上传文件。
      • COOKIES:python标准字典,包含所有的cookie。
      • session:一个即可以读又可以写的类似于字典的对象,表示当前的会话,只有当Django启用会话支持时才可以用。
  • 视图_ajax(异步加载)
    在不重新加载整个页面(即浏览器不再重新请求这个页面)的情况下,对页面内容进行局部刷新,目的是为了加快响应速度,提升用户体验。

    • Ajax请求的过程
      前端页面发起Ajax请求;后端视图函数处理Ajax请求,处理完返回JsonResponse()数据;浏览器收到返回的JSON格式数据之后,执行回调函数,改动页面内容。
      Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第19张图片

    • 例:用ajax给页面加一个提示

      • 配置静态文件路径
        在项目目录下新建一个static文件夹(和模板目录templates同级),然后在该目录下创建三个文件夹:js、css、images分别保存项目的js文件、css文件和图片文件;最后将jquery-1.12.4.min.js放在js文件夹中。最后在项目配置文件settings.py中新增STATICFILES_DIRS项,该项值为:[os.path.join(BASE_DIR, ‘static’)]
        Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第20张图片

        	"""在项目配置文件settings.py中"""
        	STATIC_URL = '/static/'
        	# 静态文件目录
        	STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
        
      • 创建显示AJax页面的ajax.html模板文件

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Ajax请求测试</title>
        <!--    导入JS文件-->
            <script src="/static/js/jquery-1.12.4.min.js"></script>
        <!--    点击按钮执行的JS脚本-->
            <script>
                $(function () {
                    //绑定btn的点击事件
                    $('#btn').click(function () {
                        $.ajax({
                        	/*ajax请求的url*/
                            'url': '/ajax_handle',
                            'type': 'get',
                            'dataType': 'json'
                        }).success(function (data) {
                            //进行处理,data是Django后台(视图函数返回的数据)
                            //alert(data.res)
                            if (data.res == 1) {
                            	/*显示提示信息*/
                                $('#msg').show().html('提示信息!')
                            }
                        })
                    })
                })
            </script>
        <!--    ajax响应成功返回后在页面做的修改-->
            <style>
                #msg {
                    /*默认不显示*/
                    display: none;
                    color: red;
                }
            </style>
        </head>
        <body>
        <!--发送Ajax请求的按钮-->
        <input type="button" id="btn" value="Ajax请求">
        <div id="msg"></div>
        </body>
        </html>
        
      • 定义视图函数

        def ajax_test(request):
            """显示ajax页面"""
            return render(request, 'booktest/ajax.html')
        
        
        def ajax_handle(request):
            """处理ajax请求"""
            # 视图函数返回的数据{'res': 1}
            return JsonResponse({'res': 1})
        
      • 配置url

        """在应用的urls.py中的urlpatterns中添加下面这两项"""
        url(r'^ajax$', views.ajax_test),  # 显示ajax页面
        url(r'^ajax_handle$', views.ajax_handle)
        
      • 在地址栏中输入127.0.0.1:8000/ajax,进入,点击按钮
        Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第21张图片

5、cookie和session

cookie和session用于用户状态保持,可以让用户在一段时间内无需重复登录就可以访问网站内容。

5.1 cookie

cookie是由服务器生成,存储在浏览器端的一小段文本信息。

  • cookie的特点

    • 键值对方式进行存储
    • 通过浏览器访问一个网站时,会将浏览器存储的根网站相关的所有cookie信息发送给该网站的服务器。存在request.COOKIES中。
    • cookie是基于域名安全的
    • cookie可以设置过期时间,默认关闭浏览器就过期
  • 通过HttpRequest对象的COOKIES属性进行会话的读写操作

    • 设置cookieresponse.set_cookie('键', '值', max_age=秒数),设置cookie用的是HttpResponse对象
    • 获取cookierequest.COOKIES['键']
    • 判断是否存在cookie键 in request.COOKIES

5.2 session

session和cookie不同的一点是,session存储在服务器端。

  • session的特点

    • session是以键值对进行存储的
    • session依赖于cookie, 如果想还用Session,浏览器必须支持cookie.
    • session默认过期时间是两周
  • 通过HttpRequest对象的session属性进行会话的读写操作

    • 以键值对形式写session: request.session['键'] = 值
    • 根据键读取值: request.session.get('键', '默认值')
    • 清除所有session(删除值): request.session.clear()
    • 清除session数据(删除键值): request.session.flush()
    • 删除指定session: del request.session['键']
    • 设置session的过期时间: request.session.set_expiry(秒数),默认两周过期
      -检查是否有某个session: request.session.has_key('键')
  • cookie和session的应用场景

    • cookie:记住用户名,安全性较低
    • session:记住登录状态,保存密码等,安全性要求较高。

6、模板进阶(T)

6.1 回顾

  • 模板功能
    产生html,控制页面上展示的内容,模板文件不仅仅是一个html文件,模板文件包含两部分内容:

    • 静态内容:css、js、html
    • 动态内容:用于动态去产生一些网页内容,通过模板语言来产生
  • 模板文件的使用
    通常是在视图函数中使用模板产生html内容返回给客户端。

    • 加载模板文件:loader.get_template, 获取模板文件内容。产生一个模板对象。
    • 定义模板上下文,给模板文件传递数据:RequestContext
    • 渲染模板产生html内容:render
    • 上述步骤Django中已经封装成render方法了,可直接使用。
  • 模板文件的加载顺序

    • 首先去模板目录(templates)下面去找模板文件
    • 如果在模板目录下找不到,就去应用下的模板目录下(前提是你的应用下要有templates目录,此处未在应用下创建templates目录)面去找, 找不到就会报错。
  • 模板变量
    模板变量名是由数字、字母、下划线组成的,不能以下划线开头
    使用模板变量:{{ 模板变量名 }}

    • 模板变量的解析顺序
      例如:{{ book.book_title }}

      • 首先把book当成一个字典,把book_title当成键名进行取值,相当于book[‘book_title’]
      • 上述取不到,就把book当成一个对象,把book_title当成一个属性
      • 如果还是取不到,就把后面的book_title当成一个方法
      • 如果还是取不到,就出错,结果用空字符串代替
      • 就是说使用模板变量的时候,点前面可能是字典、对象、列表

6.2 模板标签

{% 代码段 %},代码段在大括号百分号中间。模板标签用于空值页面输出。

  • for循环

     {% for x in 列表 %}
     	// 列表不为空时执行
     {%  empty %}
     	// 列表为空时执行
     {% endfor %}
    

    可以通过 {{ forloop.counter }}得到for循环遍历到了第几次

  • if 条件控制

    {% if 条件 %}
    {% elif 条件 %}
    {% else %}
    {% endif %}
    

    关系比较运算符:>、<、>=、<=、==、!=
    逻辑运算: not and or
    ##注意比较操作符两边必须有空格

6.3 过滤器

过滤器用于对模板变量进行操作,改变模板变量的默认输出。
格式: {{ 模板变量 | 过滤器: 参数 }}

  • 默认过滤器

    • 参考资料
  • 自定义过滤器
    自定义过滤器必须定义在应用下的templatetags包下,而且必须要有一个参数,最多只能有两个参数。

    • 应用下新建一个包,叫templatetags

    • 然后在templatetags下新建一个py文件

      """booktest/templatetags/filter.py中"""
      # 自定义过滤器
      # 过滤器的本质其实就是Python函数
      
      from django.template import Library
      
      # 实例化一个Library对象
      register = Library()
      
      
      @register.filter
      def mod(num):
          """自定义过滤器判断num是否为偶数"""
          return num % 2 == 0
      
    • 在模板目录templates下对应应用下的模板文件中使用自定义过滤器

      DOCTYPE html>
      <html lang="en">
      
      {% load filter %}
      <head>
          <meta charset="UTF-8">
          <title>Titletitle>
      head>
      <body>
          
          {% if val|mod %}
              <h2>val是偶数h2>
          {% else %}
              <h2>val不是偶数h2>
      body>
      html>
      

6.4 模板注释

  • 单行注释:{# 注释内容 #}

  • 多行注释:

    {# comment #}

     注释内容
    

    {# endcomment #}

6.5 模板继承

模板继承是为了复用html页面中共有的代码,比如同一网站的导航条与版权信息。

  • 继承
    在子页面中:{% extends 'booktest/base.html' %},然后base.html有的内容子页面也就有了。需要注意的是,在父模板中要给子页面独有的内容预留位置,叫预留块。用: {% block 块名%}...{% endblock 块名 %}

  • 子模板中重写块
    在子模板中不重写块的内容,继承时就会使用父模板中的内容。
    重写子模板中的内容:

    {% block 块名%}

     子模板内容
    

    {% endblock 块名 %}

  • 即用父模板内容又要重写父模板内容
    {% block.super %} // 先继承父模板block内容,然后再重写

    {% block 块名%}

     子模板内容
    

    {% endblock 块名 %}

  • 模板继承什么时候用?
    将所有页面共有的内容放在父模板中,什么位置的内容不同,就在什么地方预留块,然后在子页面中重写这个块。

6.6 html转义

在模板变量中如果包含<、>、&、'、"等,会被自动转义,原样显示(被当成字符串显示)。但是我就想让它能被当成正常的html语句怎么办?办法就是在模板文件中关闭html转义

  • 通过safe过滤器关闭

    {{ 变量名|safe }}

    此时该变量会被当成html语句渲染到页面。

  • 使用autoescape模板标签

    {% autoescape %}

     模板变量
    

    {% endautoescape %}

6.7 CSRF攻击

Django是默认开启CSRF保护的,在项目配置文件settings.py中MIDDLEWARE项下:

'django.middleware.csrf.CsrfViewMiddleware',  # Django默认开启CSRF,但是只针对post请求

无CSRF时,攻击者可以从其他站点发起相同的http请求,从而获取会话中的COOKIE/SESSION等用户信息,造成安全隐患。

  • CSRF配置
    • 页面中

      <form action="/login/" method="POST">
          {% csrf_token %}
          <input type="text" name="username" placeholder="用户名"/>
          <input type="password" name="password" placeholder="密码"/>
          <input type="submit" value="登录"/>
      form>	
      
    • Ajax配置
      注意要引用脚本jquery.cookie.js

      <script src="/static/js/jquery-1.12.4.js"></script>
      <script src="/static/js/jquery.cookie.js"></script>
      <script>
      	// ajax csrf配置
          var csrftoken = $.cookie('csrftoken');
      
          function csrfSafeMethod(method) {
              return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
          }
          $.ajaxSetup({
              beforeSend: function(xhr, settings) {
                  if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                      xhr.setRequestHeader("X-CSRFToken", csrftoken);
                  }
              }
          });
      </script>
      
  • 视图函数配置
    Django中已经写好了CSRF的装饰器,便于我们给某个具体的视图函数配置CSRF。
    • 给视图函数添加CSRF

      from django.views.decorators.csrf import csrf_exempt, csrf_protect
      
      @csrf_protect
      def login(request):
          """显示登录界面"""
          # 有用户session
          if request.session.has_key('isLogin'):
              return redirect('/index')
          # 无用户session,返回登录页
          else:
              # 获取cookie和username
              if 'account' in request.COOKIES:
                  # 获取账号
                  account = request.COOKIES['account']
              else:
                  account = ''
              return render(request, 'booktest/login.html', {'account': account})
      

      如果要关闭某个视图函数的CSRF,使用csrf_exempt装饰器即可。

6.8 URL反向解析

作用:当某一个url配置的地址发生变化时,页面上使用反向解析生成的地址不需要发生变化。
暂时没有用到,放一篇参考文献。

7、Django其他技术

7.1 静态文件

在网页中使用的JS、CSS、图片、JSON文件等都属于静态文件。

  • 项目目录下新建static目录,然后在此目录下分别给每一类静态文件创建一个文件夹:
    Django框架使用_环境搭建_创建项目_基本使用_Django进阶_第22张图片

  • 项目配置文件settings.py中配置静态文件的路径

    STATIC_URL = '/static/'
    STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
    使用的时候直接: /static/css/xx.css就可以了。

7.2 中间件

中间件函数是Django框架留给我们预留的函数接口,让我们干预请求和应答过程。

  • 获取浏览器端的IP地址
    request.META[‘REMOTE_ADDR’], 通过视图函数的request参数可以获取到客户机的IP地址

还有一部分内容,后期用的时候再补充吧

你可能感兴趣的:(全栈开发,django,python,后端,pycharm)