Django概念
优点
Django的主要目的是简便、快速的开发数据库驱动的网站。它强调代码复用,多个组件可以很方便的以”插件”形式服务于整个框架,Django有许多功能强大的第三方撬件,你甚至可以很方便的开发出自己的工具包。这使得Django具有很强的可扩展性。它还强调快速开发和DRY(DoNotRepeatYourself)原则。
对比Flask框架,Django原生提供了众多的功能组件,让开发更简便快速。
- 提供项目工程管理的自动化脚本工具
- 数据库更RM支持(对象奂系映射,英语: Object Relational Mapping )
- 模板
- 表单
- Admin管理站点
- 文件管理
- 认证权限
- session机制
- 缓存
MVC设计模式
后端服务器被分为M、V、C三个部分
M全拼为Model,主要封装对数据车层的访问,对数据库中的数据进行增、删、改、查操作。 V全拼为View,用于封装结果,生成页面展示的html内容。 C全拼为Controller↑用于接收请求↑处理业务逻辑,与Model和View交互:返回结果。
MVC处理过程
首先前端发送请求到后端服务器
后端服务器的Controller部分接收请求,并业务处理(如密码强度验证,身份认证….登陆操作)
如业务逻辑需要操作数据库,那么就去Model部分,Model作为数据库和Controller的中介,去请求数据库。
数据库返回结果给Model,Model将结果返回给Controller
Controller再将业务处理后的结果返回给View部分,View将要渲染的结果返回给Controller
Controller将结果渲染到前端
MVT设计模式
M全拼为Model,与MVC中的M功能相同,负责和数据库交互,进行数据处理。 V全拼为View,与MVC中的C功能相同,接收请求,进行业务处理,返回应答● T全拼为Template↑与MVC中的V功能相同↑负责封装构造要返回的html。
创建Django项目
创建项目
django-admin startpeoject application
cd application
目录结构
│ manage.py
│
└─application
asgi.py
settings.py
urls.py
wsgi.py
__init__.py
- manager:管理工具(例如创建子应用)
- settings:设置相关
- urls:路由相关
- usgi:程序入口
启动项目
python manage.py runserver
使用其他端口启动(默认8000)
python manage.py runserver 127.0.0.1:8001
查看帮助
python manager.
创建子应用
创建
python manage.py startapp login
子应用目录结构
│ manage.py
│
├─application
│ │ asgi.py
│ │ settings.py
│ │ urls.py
│ │ wsgi.py
│ │ __init__.py
│ │
│ └─__pycache__
│ settings.cpython-39.pyc
│ __init__.cpython-39.pyc
│
└─login
│ admin.py
│ apps.py
│ models.py
│ tests.py
│ views.py
│ __init__.py
│
└─migrations
__init__.py
- views:视图相关
- tests:测试相关
- models:模型相关
- migrations:迁移相关
- admin:后台相关
- apps:当前子应用相关
在settings.py中注册app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'login.apps.LoginConfig' # 自动生成的Config信息
]
- 子应用名
- 子应用名.apps.子应用名Config
Django数据库开发
数据库开发的提示
- IVT设计模式中的Mode1, 专门负责和数据库交互对应(models.py)
- 由于Model 中内嵌了ORM框架,所以不需要直接面向数据库编程.
- 而是定义模型类,通过模型类和对象完成数据库表的增删改查
- ORM框架就是把数据库表的行与相应的对象建立矣联,互相转换使得数据库的操作面向对象
数据库开发的步骤
1.定义模型类 2.模型迁移 3.操作数据库
在ORM框架中,Python中的类对应于数据表,类属性对应于字段,对象对应于数据行
模型定义
- 主键id会自动生成,无需自己定义
class account(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
模型的类型
模型字段参考 | Django 文档 | Django (djangoproject.com)
字段参数
- null:(bool类型)是否可以为空
- max_length:CharField必须有的属性
- unique:是否唯一
- default:设置默认值
- verbose_name:后台可视化的名字
修改默认表名
from django.db import models
# Create your models here.
class account(models.Model):
name = models.CharField(max_length=20)
# 修改默认表名
class Meta:
db_table = "account_info"
def __str__(self):
return self.name
定义候选值
顾名思义,只能在给定的值中选择
使用有序字典
from django.db import models
# Create your models here.
class account(models.Model):
name = models.CharField(max_length=20)
role = (
(0,"man"),
(1,'wuman')
)
gender = models.SmallIntegerField(choices=role)
# 修改默认表名
class Meta:
db_table = "account_info"
def __str__(self):
return self.name
外键
book = model.ForeignKey(Bookinfo) # 参数内容为外键具体的类
在设置外键时,需要通过on_ delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:
- CASCADE级联删除主表数据时连通一起删除外键表中数据
- PROTECT保护,通过抛出ProtectedError异常;来阻止删除主表中被外键应用的数据
- SET_NULL设置为NULL,仅在该字段null=True允许为nul时可用
- SET_DEFAULT设置为默认值,仅在该字段设置了默认值时可用
- SET()设置为特定值或者调用特定方法
- DO_NOTHING不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常
数据迁移
配置数据库
在settings.py中配置数据库信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
默认sqlite3
修改为MySQL
安装pymysql
pip install pymysql
修改settings
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
修改子程序的__init__
文件,引入mysql
import pymysql
pymysql.install_as_MySQLdb()
修改数据库配置信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST':'127.0.0.1',
'PORT':'3306',
'USER':'root',
'PASSWORD':'',
'NAME':'test_django' #数据库名
}
}
随后生成迁移文件,并迁移
生成迁移文件
python manage.py makemigrations
此时会在app目录中的migrations中创建文件
对应数据库中生成表
python manage.py migrate
此时会在数据库中生成数据表
新增数据
方法一:先创建后保存
使用Django的shell进行数据添加
先写好代码
from login.models import account
ac = account(
name="abcdefg"
)
ac.save()
再运行DjangoShell,粘贴代码,可以看到数据添加成功
因为我们的model已经继承了models.Model类,所以包含增删改查的方法
方法二:直接入库
objects为模型的管理类,可以利用它来增删改查
from login.models import account
account.objects.create(
name="defgaioj"
)
再用Shell运行代码
更新数据
方法一:先查后改
先查询数据
from login.models import account
ac = account.objects.get(id=1)
再更新数据
# 修改实例属性
ac.name='小智'
ac.save()
方法二:直接修改
from login.models import account
account.objects.first(name='小智').update(
name='新小智'
)
可以修改一个属性,也可以修改多个属性
删除数据
方式一:先查后删
from login.models import account
ac = account.objects.get(id=1)
ac.delete()
方式二:直接删除
from login.models import account
account.objects.filter(name="新小智").delete()
查询数据
基本查询
from login.models import account
account.objects.get(id=1)
如果id不存在,会抛出异常
account.objects.get(id=100)
需要try一下
from login.models import account
try:
account.objects.get(id=1)
except account.DoesNotExist as e:
print(e)
获取所有数据
from login.models import account
account.objects.all()
计数查询
account.objects.all().count()
或者
account.objects.count()
过滤查询
filter
筛选、过滤,返回n(n>=0)个结果,返回列表
account.objects.filter(字段名__运算符=值)
查询书名包含’智’的账户
account.objects.filter(name__contains="智")
查询书名以:“i”结尾的账户
account.objects.filter(name__endwith="i")
查询书名为空的账户
account.objects.filter(name__isnull=True)
查询编号为1或3或5的账户
account.objects.filter(id__in=[1,3,5])
查询编号大于3的账户
account.objects.filter(id__gt=3)
- gt:大于
- gte:大于等于
- lt:小于
- lte:小于等于
查询1988年注册的账户
account.objects.filter(date__year='1988')
查询1990年1月1日后注册的账户
account.objects.filter(date__gt='1990-1-1')
时间格式必须是YYYY-MM-DD
get
返回一个结果
查询编号为1的账户
account.objects.get(id__exact=1)
- exact表示准确的、确切的
相当于
account.objects.get(id=1)
exclude
排除符合条件后剩下的结果,返回列表
查询id不为1的用户
account.objects.exclude(id__exact=3)
F对象
语法格式
filter(字段名__运算符=F('字段名'))
当两个属性相比较的时候,需要用到F对象
查询体重大于等于年龄的账户。
account.objects.filter(weight__gte=F('age'))
查询体重大于等于年龄2倍的账户。
account.objects.filter(weight__gte=F('age')*2)
Q对象(与、或、非)
当两个条件需要同时满足时,如
查询id大于2并且体重大于20的账户
方式1
account.objects.filter(id__gt=2).filter(weight__gt=20)
方式2
account.objects.filter(id__gt=2,weight__gt=20)
但是两个条件满足一个即可时,需要使用Q对象
语法格式
Q(字段名__运算符=值)
逻辑运算:
与:Q()&Q()
或:Q()|Q()
非:~Q()
查询id大于2或者体重大于20的账户
from django.db.models import Q
account.objects.filter(Q(id__gt=2)|Q(weight__gt=20))
查询id不-等于2的账户
# 方式一
account.objects.exclude(id=3)
# 方式二
account.objects.filter(~Q(id=3))
聚合函数
常用的聚合函数有
- Sum
- Max
- Min
- Avg
- Count
聚合函数需要使用aggragte
语法格式
aggragte(聚合函数名(字段名))
from django.db.models import Max,Min,Avg,Count,Sum
account.objects.aggregate(Min('id'))
排序
account.objects.all().order_by('id')
默认升序
account.objects.all().order_by('-id') # 降序
基本关联查询
一对多查询
假设人物表People中对应书籍Book,一个人物对应多个书籍,书籍中不包含人物字段
需求如下:
查询书籍为1的所有人物信息
book = BookInfo.objects.get(id=1)
# 调用关联模型(系统自动生成)
book.peopleinfo_set.all()
多对一查询
查询书籍为1的所有人物信息查询人物为1的书籍信息
person = PeopleInfo.objects.get(id=1)
person.book # 实例对象,人物表中包含书籍字段
语法格式
主表模型(实例对象).关联模型类名小写_set.all()
从表模型(实例对象) .外键
关联查询筛选
一对多
语法格式
filter(关联模型类名小写__字段__运算符=值)
查询图书,要求图书人物为郭靖”
Book.objects.filter(People__name__exact=‘啊大大’)
或者
Book.objects.filter(People__name='add')
查询图书,要求图书中人物的描述包合”八”
Book.objects.filter(People__describ__contains="八")
多对一
语法格式
filter(外键__字段__运算符=值)
查询书名为“天龙八部”的所有人物
Book.objects.filter(People__name="天龙八部")
查询图书阅读量大于30的所有人物
Book.objects.filter(readcount__gt=30)
查询结果集
惰性执行
查询集,也称查询结果集、QuerySet,表示从数据库中获取的对象集合。
调用以下函数时,会返回查询集(而不是列表)
- all
- filter
- exclude
- order_by
两大特性
创建查询集不会访问数据库,直到调用数据时才会访问数据库,调用数据的情况包括迭代、序列化、与if合
例如,当执行如下语句时; 并未进行数据库查询,只是创建了一个查询集books
books = Bookinfo.objects.all()
继续执行逼历迭代操作后,才真正的进行了数据库的查询
for book in books:
print(book.name)
缓存
配置MySQL日志
MySql数据库日志配置
sudo vim /etc/mysqL/mysql.conf.d/mysqld.conf
修改为1
general = 1
重启
sudo service mysql restart
查看日志
tail -f /var/log/mysql/mysql.log
使用同一个查询集,第一次使用时会发生数据库的查询,然后Django会把结果缓存下来,再次使用这个查询集时会使用缓存的数据减少了数据库的查询次数。
情况一: 如下是两个查询集,无法重用缓存,每次查询都会与数据库进行一次交互,增加了数据库的负裁。
[book.id for book in Book.objects.all()]
[book.id for book in Book.objects.all()]
[book.id for book in Book.objects.all()]
优化缓存后
books = Book.objects.all()
[book.id for book in books]
[book.id for book in books]
[book.id for book in books]
优化后只会查询一次数据库
限制查询集
使用列表切片来限制查询集,不支持负索引
分页查询
from django.core import Paginator
books = Book.objects.all()
p = Paginator(books,2) # 每页2个元素
book_page = p.page(1) # 第一个元素
Django自带后台管理系统
输入
http://127.0.0.1:8000/admim
跳转至
http://127.0.0.1:8000/admin/login/?next=/admin/
修改配置
在settings.py中修改,将站点语言改为中文
LANGUAGE_CODE = 'en-us'
改为
LANGUAGE_CODE = 'zh-Hans'
时区修改
TIME_ZONE = 'UTC'
改为
TIME_ZONE = 'Asia/Shanghai'
创建超级管理员账户
python manage.py createsuperuser
此时需要在app的admin中注册我们的模型,以便后台可以管理数据
from django.contrib import admin
#导入模型类
from login.models import account
# Register your models here.
# 注册模型
admin.site.register(account)
后台可以看到数据了
为了能让数据更具体,需要区对应的model中写构造函数
from django.db import models
# Create your models here.
class account(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
Django视图View
所谓视图就是函数
函数的第一个参数是请求,是HttpRequest的实例对象
而函数的返回值就是HttpResponse的实例对象,指响应
from django.shortcuts import render
# 导入请求、响应类
from django.http import HttpRequest,HttpResponse
# Create your views here.
# 视图就是函数
def index(req):
'''
req:第一个参数是HttpRequest的实例对象,是指请求
'''
return HttpResponse("index")
URL匹配(路由)
我们通过浏览器请求一个页面的时候
首先会通过设置在settings的
ROOT_URLCONF = ‘application.urls’
获取到路由的入口
默认是应用名称.urls
path
from django.urls import include,path
再来到urls中
- urlpatterns是固定写法,值是个列表
- 在浏览器中输入的路径会顺次匹配,如果匹配成功,会直接引导至相应的模块,如果匹配不成功,则返回404
- 在url中,IP:端口号以及参数都不参与正则匹配
- 如果匹配成功,则进入子应用的urlpatterns中继续进行匹配
- 如果匹配不成功,则终止匹配
urlpatterns = [
path('admin/', admin.site.urls),
]
工程下的urls
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('login.urls')),
]
子应用login.urls
from django.urls import path,include
from login.views import index
urlpatterns = [
path('index/',index)
]
匹配过程:首先请求
http://127.0.0.1:8000/index/
会到第二个‘’
中,将所有的请求转入log.urls
再匹配到第一项index/
re_path
from django.urls import include,re_path
其中数据元素的规则如下
- r是指不进行转义
- ^表示严格的开始
- $表示严格的结束
上面的url如果使用re_path,则为
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r'^',include('login.urls')),
]
urlpatterns = [
re_path(r'^index/$',index)
]
效果是一样的
Django模板Template
创建模板文件夹
Seetings中关于模板的配置
TEMPLATES = [ { ‘BACKEND’: ‘django.template.backends.django.DjangoTemplates’, ‘DIRS’: [], ‘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’, ], }, }, ]
修改为
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR/'template'],
'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',
],
},
},
]
在子应用的views中调用render函数,渲染页面
def index(req):
'''
req:第一个参数是HttpRequest的实例对象,是指请求
'''
# 参数为:请求,模板名称
return render(req,'index.html')
render的第一个参数是请求,第二个参数是模板名称,第三个参数为请求参数内容
def index(req):
'''
req:第一个参数是HttpRequest的实例对象,是指请求
'''
name = '小智'
context = {
"name":name
}
# 参数为:请求,模板名称
return render(req,'index.html',context=context)
在页面中调用插值表达式进行显示
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h>Hello World {{ name }}</h>
</body>
</html>
后台返回数据给前端显示
首先到views里面,从ORM中获取到数据
并返回HttpResponse的context到前端
from django.shortcuts import render
# 导入请求、响应类
from django.http import HttpRequest,HttpResponse
# Create your views here.
# 导入模型类
from login.models import account
# 视图就是函数
def index(req):
'''
req:第一个参数是HttpRequest的实例对象,是指请求
'''
# 获取全部数据
accounts = account.objects.all()
# 构造返回数据
context = {
"accounts":accounts
}
# 参数为:请求,模板名称
return render(req,'index.html',context=context)
- 引入模型类
- 获取模型对应的所有数据
- 构造返回数据
- 通过HttpResponse返回数据到模板
再在模板中调用模板语法来遍历返回的数据
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h>Hello World</h>
<ul>
{% for account in accounts %}
<li>{{ account.name }}</li>
{% endfor %}
</ul>
</body>
</html>
静态资源配置
新建静态资源文件夹
配置静态资源文件夹位置
STATICFILES_DIRS = [
BASE_DIR/'static'
]
这个配置是指css、js等静态文件在这个目录里
STATIC_URL = 'static/'
这个配置是指在请求static这个url的时候,可以访问到静态资源
App相关配置
首先确保在settings中的INSTALLED_APPS中引入了子应用的配置
INSTALLED_APPS = [
'login.apps.LoginConfig'
]
这样配置才会生效
其次,需要在配置中添加配置项
from django.apps import AppConfig
class LoginConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'login'
# 模型命名
verbose_name = "后台相关"
添加后可以看到,由
变为了
DjangoShell
python manage.py shell
实现命令行式编程
数据的增删改查可以通过Shell也可以通过代码实现