Django学习
一、简介
Django 是一个由 Python 编写的一个开放源代码的 Web 应用框架。
使用 Django,只要很少的代码,Python 的程序开发人员就可以轻松地完成一个正式网站所需要的大部分内容,并进一步开发出全功能的 Web 服务 。
Python 加 Django 是快速开发、设计、部署网站的最佳组合。
MVC模型
MVC 模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
MVC 以一种插件式的、松耦合的方式连接在一起。
- 模型(M)- 编写程序应有的功能,负责业务对象与数据库的映射(ORM)。
- 视图(V)- 图形界面,负责与用户的交互(页面)。
- 控制器(C)- 负责转发请求,对请求进行处理
MTV模型
Django 的 MTV 模式本质上和 MVC 是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django 的 MTV 分别是指:
- M 表示模型(Model):编写程序应有的功能,负责业务对象与数据库的映射(ORM)。
- T 表示模板 (Template):负责如何把页面(html)展示给用户。
- V 表示视图(View):负责业务逻辑,并在适当时候调用 Model和 Template
除了以上三层之外,还需要一个 URL 分发器,它的作用是将一个个 URL 的页面请求分发给不同的 View 处理,View 再调用相应的 Model 和 Template
二、安装使用
1、安装
下载地址:https://www.djangoproject.com/download/
2、创建项目
创建名为HelloWorld的项目:django-admin startproject HelloWorld
项目的目录结构:
|-- HelloWorld | |-- __init__.py # 一个空文件,告诉 Python 该目录是一个 Python 包 | |-- asgi.py # 一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目 | |-- settings.py # 该 Django 项目的设置/配置。 | |-- urls.py # 该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录" | `-- wsgi.py # 一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目 `-- manage.py # 一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互
在项目目录下,输入以下命令,启动服务器:python3 manage.py runserver 0.0.0.0:8000
0.0.0.0 让其它电脑可连接到开发服务器,8000 为端口号。如果不说明,那么端口号默认为 8000
3、视图和URL路由配置
视图用来接受http请求并响应
路由用来url和视图建立映射关系
1)在项目目录下新建一个view.py(视图)文件:
from django.http import HttpResponse def hello(request): return HttpResponse("Hello world ! ")
2)绑定URL与视图函数。打开urls.py文件,删除原来代码,粘贴以下代码:
from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.hello), # url() 方法:普通路径和正则路径均可使用,需要自己手动添加正则首位限制符号 ]
Django 2.2.x 之后的版本
path:用于普通路径,不需要自己手动添加正则首位限制符号,底层已经添加。
re_path:用于正则路径,需要自己手动添加正则首位限制符号。
from django.urls import re_path # 用re_path 需要引入 urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), # 普通路径 re_path(r'^articles/([0-9]{4})/$', views.articles), # 正则路径 ]
三、高级应用
1、模型
Django模型使用自带的ORM
ORM是通过使用描述对象之间的映射的元数据,将程序中的对象自动持久化到数据库中
ORM对应关系:
在项目setting.py配置文件中配置数据库连接信息:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 数据库引擎 'NAME': 'runoob', # 数据库名称 'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1 'PORT': 3306, # 端口 'USER': 'root', # 数据库用户名 'PASSWORD': '123456', # 数据库密码 } }
1)定义模型:
Django规定,如果要使用模型,必须创建一个app。如使用以下命令创建一个TestModel的app:
django-admin.py startapp TestModel
目录结构如下:
HelloWorld |-- HelloWorld |-- manage.py ... |-- TestModel | |-- __init__.py | |-- admin.py | |-- models.py | |-- tests.py | `-- views.py
接下来在接下来在 settings.py 中找到INSTALLED_APPS这一项,并添加新创建的模型名称
models.py内容如:
# models.py from django.db import models class Test(models.Model): name = models.CharField(max_length=20)
以上的类名代表了数据库表名,且继承了models.Model,类里面的字段代表数据表中的字段(name),数据类型则由CharField(相当于varchar)、DateField(相当于datetime), max_length 参数限定长度。
添加数据:先创建对象,再执行save()函数,相当于SQL中的insert。或者通过 ORM 提供的 objects 提供的方法 create 来实现(推荐)
删除数据:只需调用该对象的delete()方法即可
修改数据:修改数据可以使用 save() 或 update():
# 修改其中一个id=1的name字段,再save,相当于SQL中的UPDATE test1 = Test.objects.get(id=1) test1.name = 'Google' test1.save() # 另外一种方式 #Test.objects.filter(id=1).update(name='Google') # 修改所有的列 # Test.objects.all().update(name='Google')
获取数据:
# 通过objects这个模型管理器的all()获得所有数据行,相当于SQL中的SELECT * FROM list = Test.objects.all()
# filter相当于SQL中的WHERE,可设置条件过滤结果.返回的是 QuerySet 类型数据,类似于 list,里面放的是满足条件的模型类的对象,可用索引下标取出模型类的对象
response2 = Test.objects.filter(id=1)
# exclude() 方法用于查询不符合条件的数据 # 获取单个对象,用于查询符合条件的返回模型类的对象符合条件的对象只能为一个,如果符合筛选条件的对象超过了一个或者没有一个都会抛出错误 response3 = Test.objects.get(id=1) # 限制返回的数据 相当于 SQL 中的 OFFSET 0 LIMIT 2; Test.objects.order_by('name')[0:2] #数据排序,默认升序,降序为在字段前面加个负号 - Test.objects.order_by("id") # 上面的方法可以连锁使用 Test.objects.filter(name="runoob").order_by("id") # count() 方法用于查询数据的数量返回的数据是整数。 # first() 方法返回第一条数据返回的数据是模型类的对象也可以用索引下标 [0] # last() 方法返回最后一条数据返回的数据是模型类的对象不能用索引下标 [-1],ORM 没有逆序索引 # reverse() 方法用于对查询结果进行反转 # exists() 方法用于判断查询的结果 QuerySet 列表里是否有数据。返回的数据类型是布尔,有为 true,没有为 false。 # values() 方法用于查询部分字段的数据 # distinct() 方法用于对数据进行去重,distinct() 一般是联合 values 或者 values_list 使用
filter()方法基于双下划线的模糊查询(exclude 同理),字段后拼接,如 field__in=[1,2,3]
filter 中运算符号只能使用等于号 = ,不能使用大于号 > ,小于号 < ,等等其他符号。
__in 用于读取区间,= 号后面为列表 。
__gt 大于号 ,= 号后面为数字;
__gte 大于等于,= 号后面为数字;
__lt 小于,=号后面为数字;
__lte 小于等于,= 号后面为数字;
__range 在 ... 之间,左闭右闭区间,= 号后面为两个元素的列表;
__contains 包含,= 号后面为字符串;
__icontains 不区分大小写的包含,= 号后面为字符串;
__startswith 以指定字符开头,= 号后面为字符串;
__endswith 以指定字符结尾,= 号后面为字符串
2、多表实例
外键在一对多的多中设置:models.ForeignKey("关联类名", on_delete=models.CASCADE)
OneToOneField = ForeignKey(...,unique=True)设置一对一
若有模型类存在外键,创建数据时,要先创建外键关联的模型类的数据,不然创建包含外键的模型类的数据时,外键的关联模型类的数据会找不到
1)基于双下划线的跨表查询
正向(主表查询外键表): 属性名称__跨表的属性名称
反向(外键表查询主表):小写类名__跨表的属性名称
正向如,查询条件为Book表的外键Publish的name属性
res = models.Book.objects.filter(publish__name="菜鸟出版社").values_list("title", "price")
反向:通过 小写类名__跨表的属性名称(book__title,book__price) 跨表获取数据。
res = models.Publish.objects.filter(name="菜鸟出版社").values_list("book__title","book__price") return HttpResponse("ok")
3、视图(类似于Java中的Controller)
一个视图函数,简称视图,是一个简单的 Python 函数,它接受 Web 请求并且返回 Web 响应
每个视图函数都负责返回一个 HttpResponse 对象,对象中包含生成的响应。
视图层中有两个重要的对象:请求对象(request)与响应对象(HttpResponse)
HTTP请求
HTTP协议以"请求-回复"的方式工作。客户端发送请求时,可以在请求中附加数据。服务器通过解析请求,就可以获得用户传来的数据,并根据URL来提供特定的服务。
1、请求对象: HttpRequest (简称 request 对象)
常用的request属性:
1)GET
数据类型是QueryDict,一个类似于字典的对象,包含HTTP GET的所有参数。有相同的键,就把所有的值放到对应的列表里。
取值方式:对象.方法
get():返回字符串,如果该键对应有多个值,取出该键的最后一个值:如
def runoob(request): name = request.GET.get("name") return HttpResponse('姓名:{}'.format(name))
2)POST
数据类型是 QueryDict,一个类似于字典的对象,包含 HTTP POST 的所有参数。
常用于 form 表单,form 表单里的标签 name 属性对应参数的键,value 属性对应参数的值。
取值格式: 对象.方法。
get():返回字符串,如果该键对应有多个值,取出该键的最后一个值
def runoob(request): name = request.POST.get("name") return HttpResponse('姓名:{}'.format(name))
3)body
数据类型是二进制字节流,是原生请求体里的参数内容,在 HTTP 中用于 POST,因为 GET 没有请求体。
在 HTTP 中不常用,而在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML、Json 等
4)path
获取 URL 中的路径部分,数据类型是字符串
5)method
获取当前请求的方式,数据类型是字符串,且结果为大写
2、响应对象:HttpReponse
响应对象主要有三种形式:HttpResponse()、render()、redirect()。
HttpResponse(): 返回文本,参数为字符串,字符串中写文本内容。如果参数为字符串里含有 html 标签,也可以渲染
1)render(): 返回文本,第一个参数为 request,第二个参数为字符串(页面名称),第三个参数为字典(可选参数,向页面传递的参数:键为页面参数名,值为views参数名)
def runoob(request): name ="菜鸟教程" return render(request,"runoob.html",{"name":name})
2)redirect():重定向,跳转新页面。参数为字符串,字符串中填写页面路径。一般用于 form 表单提交后,跳转到新页面。
def runoob(request): return redirect("/index/")
render 和 redirect 是在 HttpResponse 的基础上进行了封装:
render:底层返回的也是 HttpResponse 对象
redirect:底层继承的是 HttpResponse 对象
附录:
settings.py配置示例:
""" Django settings for dvb_data_access project. Generated by 'django-admin startproject' using Django 3.2.9. For more information on this file, see https://docs.djangoproject.com/en/3.2/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/3.2/ref/settings/ """ import os import time from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'django-insecure-y_cn7v6jp35#&(oop(p_dj13@ef)!(&)tg#1u)9)9#c#fwz=16' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = ['*'] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'dvb_data_access', 'hubei', # 湖北数据接入 'hunan', # 湖南数据接入 ] 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', ] ROOT_URLCONF = 'project_name.urls' 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', ], }, }, ] WSGI_APPLICATION = 'project_name.wsgi.application' # Database # https://docs.djangoproject.com/en/3.2/ref/settings/#databases # DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': BASE_DIR / 'db.sqlite3', # } # } DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 数据库引擎 'NAME': 'database_name', # 数据库名称 'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1 'PORT': 3306, # 端口 'USER': 'user_name', # 数据库用户名 'PASSWORD': 'password', # 数据库密码 } } # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'Asia/Shanghai' #时区 USE_I18N = True USE_L10N = True USE_TZ = False # 为False时使用datetime.datetime.now()获取当前时间入库不会有时间偏差 # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ STATIC_URL = '/static/' # Default primary key field type # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' CABLE_REDIS = { 'HOST': '127.0.0.1', 'PORT': 6379, 'PASSWORD': '', 'TIMEOUT': 5.0, } REDIS_CABLE_DB = 0 LOG_PATH = '/home/work/log/project_name/' # 如果不存在这个logs文件夹,就自动创建一个 if not os.path.exists(LOG_PATH): os.makedirs(LOG_PATH) LOGGING = { 'version': 1, 'disable_existing_loggers': True, 'formatters': { # 日志格式 'standard': { 'format': '[%(asctime)s] [%(filename)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'}, 'simplify': { 'format': '[%(asctime)s] [%(module)s:%(lineno)d] [%(levelname)s]- %(message)s'} }, # 过滤 'filters': { }, 'handlers': { # 默认记录所有日志 'default': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', 'filename': os.path.join(LOG_PATH, 'all-{}.log'.format(time.strftime('%Y-%m-%d'))), # 日志输出文件 'maxBytes': 1024 * 1024 * 5, # 文件大小 'backupCount': 5, # 备份份数 'formatter': 'standard', # 使用哪种formatters日志格式 'encoding': 'utf-8', # 设置默认编码,否则打印出来汉字乱码 }, # 输出info日志 'info': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', 'filename': os.path.join(LOG_PATH, 'info-{}.log'.format(time.strftime('%Y-%m-%d'))), 'maxBytes': 1024 * 1024 * 5, 'backupCount': 5, 'formatter': 'standard', 'encoding': 'utf-8', # 设置默认编码 }, # 错误日志输出 'error': { 'level': 'ERROR', 'class': 'logging.handlers.RotatingFileHandler', 'filename': os.path.join(LOG_PATH, 'error-{}.log'.format(time.strftime('%Y-%m-%d'))), 'maxBytes': 1024 * 1024 * 5, # 文件大小 'backupCount': 5, # 备份数 'formatter': 'standard', # 输出格式 'encoding': 'utf-8', # 设置默认编码 }, # 控制台输出 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'standard' }, }, # 配置使用哪几种handlers来处理日志 'loggers': { 'django': { 'handlers': ['info', 'error'], 'level': 'INFO', 'propagate': True }, 'django.request': { 'handlers': ['info', 'error'], 'level': 'INFO', 'propagate': True, }, # log 调用时需要当作参数传入,如:logging.getLogger("log") 'log': { 'handlers': ['info', 'error'], 'level': 'INFO', 'propagate': True }, } }
END.