在脚本中如何进行Django的运行
if __name__ == '__main__':
import os
import djanGo
# 注意路径(当前所在的位置,要加载Django的配置文件)
os.environ.setdefault("DJANGO_SETTINGS_MODULE","ORM69.settings")
django.setup()
# 进行的操作
一.搭建环境
设置pip install 的源
创建虚拟环境
mkvirtualenv py6_django -p python3
查看当前目录下的虚拟环境
workon
设置Django的版本
pip install django==1.11.11
# 虚拟环境的指令
mkvirtualenv # 创建虚拟环境
rmvirtualenv # 删除虚拟环境
workon # 进入虚拟环境、查看所有虚拟环境
deactivate # 退出虚拟环境
ctrl + h 查看隐藏文件
# pip
pip install # 安装依赖包
pip uninstall # 卸载依赖包
pip list # 查看已安装的依赖包
pip freeze # 冻结当前环境的依赖包
workon + py6_django 进入当前的虚拟环境
切换到桌面下的code中,将创建的项目放到里面
cd ~/Desktop/code
django-admin startproject demo
查看树状图
执行 tree,结果显示如下的目录结构
与项目同名的目录,此处为demo
settings.py 是项目的整体配置文件
urls.py 是项目的URL配置文件
wsgi.py 是项目与WSGI兼容的WEB服务器入口
manage.py 是项目管理文件,通过它管理项目
运行开发服务器
python manage.py runserver
创建子应用(类似于蓝图)
Python manage.py startapp testdatabase
执行 tree,结果显示如下的目录结构
admin.py 文件跟网站的后台管理站点配置相关
apps.py 文件用于配置当前子应用的相关信息
migrations 目录用于存放数据库迁移历史文件
models.py 文件用户保存数据库模型类
tests.py 文件用于开发测试用例,编写单元测试
views.py 文件用于编写Web应用视图
创建完子应用时需要进行三个步骤:
第一步:设置路由
在工程配置文件settings.py中,INSTALLED_APPS项保存了工程中已经注册安装的子应用,
将刚创建的users子应用添加到工程中,可在INSTALLED_APPS列表中添加
'testdatabase.apps.TestdatabaseConfig'
第二步:在views中写视图函数
from django.Http import HttpResponse
# 写视图函数时需要注意必须要传request参数和返回一个HttpResponse的响应
def index(request):
"""
index视图
:param request: 包含了请求信息的请求对象
:return: 响应对象
"""
return HttpResponse("hello world!")
第三步:在子应用中创建urls.py,保存子应用中的地址
在users/urls.py文件中定义路由信息
from django.conf.urls import url
from . import views
# urlpatterns是被django自动识别的路由列表变量
urlpatterns = [
# 每个路由信息都需要使用url函数来构造
# url(路径, 视图)
# ^ / $ 需注意在子应用的urls.py中一定要有,
url(r'^index/$', views.index),
]
在该项目的(demo)urls.py中
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls), # django默认包含的
# 添加
# ^ / 需注意在子应用的urls.py中一定要有
url(r'^testdatabase/', include('testdatabase.urls')),
]
重新启动django程序
python manage.py runserver
配置文件
BASE_DIR
DEBUG
将语言和时区修改为中国大陆信息
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
静态文件
在项目根目录下创建static_files目录来保存静态文件。
在demo/settings.py中修改静态文件的两个参数为
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static_files'),
]
此时在static_files添加的任何静态文件都可以使用网址 /static/文件在static_files中的路径来访问了
用127.0.0.1:8000/static/index.html来访问
注意:
Django 仅在调试模式下(DEBUG=True)能对外提供静态文件,当DEBUG=False工作在生产模式时,Django不再对外提供静态文件,
需要是用collectstatic命令来收集静态文件并交由其他静态文件服务器来提供
路由说明
路由定义位置
路由解析顺序
从上至下
注意:需要注意定义路由的顺序,避免出现屏蔽效应。
路由命名与reverse反解析(逆向)
路由信息
在定义路由的时候,可以为路由命名,方便查找特定视图的具体路径信息。
1) 在使用include函数定义路由时,可以使用namespace参数定义路由的命名空间,如
url(r'^users/', include('users.urls', namespace='users')),
命名空间表示,凡是users.urls中定义的路由,均属于namespace指明的users名下。
命名空间的作用:避免不同应用中的路由使用了相同的名字发生冲突,使用命名空间区别开。
2) 在定义普通路由时,可以使用name参数指明路由的名字,如
urlpatterns = [
url(r'^index/$', views.index, name='index'),
url(r'^say', views.say, name='say'),
]
reverse反解析
使用reverse函数,可以根据路由名称,返回具体的路径,如:
from django.core.urlresolvers import reverse # 注意导包路径
def index(request):
return HttpResponse("hello the world!")
def say(request):
url = reverse('users:index') # 返回 /users/index/
print(url)
return HttpResponse('say')
对于未指明namespace的,reverse(路由name)
对于指明namespace的,reverse(命名空间namespace:路由name)
路径结尾斜线的说明
Django中定义路由时,通常以斜线/结尾,其好处是用户访问不以斜线/结尾的相同路径时,
Django会把用户重定向到以斜线/结尾的路径上,而不会返回404不存在。如
urlpatterns = [
url(r'^index/$', views.index, name='index'),
]
用户访问 index 或者 index/ 网址,均能访问到index视图。
说明:
虽然路由结尾带/能带来上述好处,但是却违背了HTTP中URL表示资源位置路径的设计理念。是否结尾带/以所属公司定义风格为准。
请求和响应
请求
利用HTTP协议向服务器传参有几种途径?
提取URL的特定部分,如/weather/beijing/2018,可以在服务器端的路由中用正则表达式截取
查询字符串(query string),形如key1=value1&key2=value2;
请求体(body)中发送的数据,比如表单数据、JSON、xml;
在http报文的头(header)中
具体如下:
request
传递数据的方式
a、以查询字符串的方式将参数放到了url中
http://127.0.0.1:8000/login?username=zhangsan&pwd=12345
b、将数据放到了请求体中
http://127.0.0.1:8000/login
c、路径参数:将数据放到了路径中
http://127.0.0.1:8000/login/zhangsan/123456
d、请求头:将数据放到了请求头中
URL路径参数
未命名参数传递
url(r'^weather/([a-z]+)/(\d{4})/$', views.weather),
def weather(request, city, year):
print('city=%s' % city)
print('year=%s' % year)
return HttpResponse('OK')
命名参数按名字的传递
url(r'^weather/(?P<city>[a-z]+)/(?P<year>\d{4})/$', views.weather),
def weather(request, year, city):
print('city=%s' % city)
print('year=%s' % year)
return HttpResponse('OK...')
Django中的QueryDict对象
定义在django.http.QueryDict
HttpRequest对象的属性GET、POST都是QueryDict类型的对象与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况
方法get():根据键获取值
如果一个键同时拥有多个值将获取最后一个值,如果键不存在则返回None值,可以设置默认值进行后续处理
dict.get('键',默认值)
可简写为
dict['键']
方法getlist():根据键获取值,值以列表返回,可以获取指定键的所有值,如果键不存在则返回空列表[],可以设置默认值进行后续处理
dict.getlist('键',默认值)
查询字符串Query String
获取请求路径中的查询字符串参数(形如?k1=v1&k2=v2),可以通过request.GET属性获取,
返回QueryDict对象
# /qs/?a=1&b=2&a=3
def qs(request):
a = request.GET.get('a')
b = request.GET.get('b')
alist = request.GET.getlist('a')
print(a) # 3
print(b) # 2
print(alist) # ['1', '3']
return HttpResponse('OK')
重要:查询字符串不区分请求方式,即假使客户端进行POST方式的请求,依然可以通过request.GET获取请求中的查询字符串数据。
请求体
表单类型 Form Data
前端发送的表单类型的请求体数据,可以通过request.POST属性获取,返回QueryDict对象
def get_body(request):
a = request.POST.get('a')
b = request.POST.get('b')
alist = request.POST.getlist('a')
print(a)
print(b)
print(alist)
return HttpResponse('OK')
非表单类型 Non-Form Data
非表单类型的请求体数据,Django无法自动解析,可以通过request.body属性获取最原始的请求体数据,自己按照请求体
格式(jsON、XML等)进行解析。request.body返回bytes类型。
例如要获取请求体中的如下JSON数据
{"a": 1, "b": 2}
可以进行如下方法操作:
import json
def get_body_json(request):
json_bytes = request.body
json_str = json_bytes.decode()
json_data = json.loads(json_str)
print(json_data['a'])
print(json_data['b'])
return HttpResponse('OK')
请求头
通过request.META属性获取请求头headers中的数据,request.META为字典类型
常见的请求头如:
CONTENT_LENGTH – The length of the request body (as a string).
CONTENT_TYPE – The MIME type of the request body.
HTTP_ACCEPT – Acceptable content types for the response.
HTTP_ACCEPT_ENcoding – Acceptable encodings for the response.
HTTP_ACCEPT_LANGUAGE – Acceptable languages for the response.
HTTP_HOST – The HTTP Host header sent by the client.
HTTP_REFERER – The referring page, if any.
HTTP_USER_AGENT – The client’s user-agent string.
QUERY_STRING – The query string, as a single (unparsed) string.
REMOTE_ADDR – The IP address of the client.
REMOTE_HOST – The hostname of the client.
REMOTE_USER – The user authenticated by the Web server, if any.
REQUEST_METHOD – A string such as "GET" or "POST".
SERVER_NAME – The hostname of the server.
SERVER_PORT – The port of the server (as a string).
具体使用如:
def get_headers(request):
print(request.META['CONTENT_TYPE'])
return HttpResponse('OK')
其他常用HttpRequest对象属性
method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'
user:请求的用户对象
path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分
encoding:一个字符串,表示提交的数据的编码方式,如果为None则表示使用浏览器的默认设置,一般为utf-8这个属性是可写的,可以通过修改它来
修改访问表单数据使用的编码, 接下来对属性的任何访问将使用新的encoding值
FILES:一个类似于字典的对象,包含所有的上传文件
响应
HttpResponse
可以使用django.http.HttpResponse来构造响应对象。
HttpResponse(content=响应体, content_type=响应体数据类型, status=状态码)也可通过HttpResponse对象属性来设置响应体、
响应体数据类型、状态码:
content:表示返回的内容。
status_code:返回的HTTP响应状态码。
content_type:指定返回数据的的MIME类型。
响应头可以直接将HttpResponse对象当做字典进行响应头键值对的设置:
response = HttpResponse()
response['Itcast'] = 'Python' # 自定义响应头Itcast, 值为Python
示例:
from django.http import HttpResponse
def demo_view(request):
return HttpResponse('itcast python', status=400)
或者
response = HttpResponse('itcast python')
response.status_code = 400
response['Itcast'] = 'Python'
return response
HttpResponse子类
Django提供了一系列HttpResponse的子类,可以快速设置状态码
HttpResponseRedirect 301
HttpResponsePermanentRedirect 302
HttpResponseNotModified 304
HttpResponseBadRequest 400
HttpResponseNotFound 404
HttpResponseForbidden 403
HttpResponseNotAllowed 405
HttpResponseGone 410
HttpResponseServerError 500
JsonResponse
若要返回json数据,可以使用JsonResponse来构造响应对象,作用:
1)帮助我们将数据转换为json字符串
2)设置响应头Content-Type为 application/json
from django.http import JsonResponse
def demo_view(request):
return JsonResponse({'city': 'beijing', 'subject': 'python'})
redirect重定向
from django.shortcuts import redirect
def demo_view(request):
return redirect('/index.html')
Cookie
Cookie的特点
Cookie以键值对的格式进行信息的存储。
Cookie基于域名安全,不同域名的Cookie是不能互相访问的,如访问itcast.cn时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,
无法访问到itcast.cn写的Cookie信息。当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有Cookie信息提交给网站服务器。
设置Cookie
可以通过HttpResponse对象中的set_cookie方法来设置cookie。
HttpResponse.set_cookie(cookie名, value=cookie值, max_age=cookie有效期)
max_age 单位为秒,默认为None。如果是临时cookie,可将max_age设置为None。
代码如下:
def demo_view(request):
response = HttpResponse('ok')
response.set_cookie('itcast1', 'python1') # 临时cookie
response.set_cookie('itcast2', 'python2', max_age=3600) # 有效期一小时
return response
读取Cookie
可以通过HttpRequest对象的COOKIES属性来读取本次请求携带的cookie值。
request.COOKIES为字典类型。
代码如下:
def demo_view(request):
cookie1 = request.COOKIES.get('itcast1')
print(cookie1)
return HttpResponse('OK')
Session
启用Session(Django默认启用)
存储方式
在settings.py文件中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等
本地缓存
存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。
SESSION_ENGINE='django.contrib.sessions.backends.cache'
混合存储
优先从本机内存中存取,如果没有则从数据库中存取。
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
Redis
在redis中保存session,需要引入第三方扩展,我们可以使用django-redis来解决
安装扩展
pip install django-redis
配置
在settings.py文件中做如下设置
"default" 只要两次设置的名字一样就可以啦
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
如果redis的ip地址不是本地回环127.0.0.1,而是其他地址,访问Django时,可能出现Redis连接错误
解决方法:
修改redis的配置文件,添加特定ip地址。
打开redis的配置文件
sudo vim /etc/redis/redis.conf
进行修改
在如下配置项进行修改(如要添加10.211.55.5地址)
bind 127.0.0.1 10.211.55.5
重新启动redis服务
sudo service redis-server restart
Seesion操作
通过HttpRequest对象的session属性进行会话的读写操作。
以键值对的格式写session。
request.session['键']=值
根据键读取值。
request.session.get('键',默认值)
清除所有session,在存储中删除值部分。
request.session.clear()
清除session数据,在存储中删除session的整条数据。
request.session.flush()
删除session中的指定键及值,在存储中只删除某个键及对应的值。
del request.session['键']
设置session的有效期
request.session.set_expiry(value)
如果value是一个整数,session将在value秒没有活动后过期。
如果value为0,那么用户session的Cookie将在用户的浏览器关闭时过期。
如果value为None,那么session有效期将采用系统默认值,默认为两周,
可以通过在settings.py中设置SESSION_COOKIE_AGE来设置全局默认值。
类视图
类视图的好处:
1)代码可读性好
2)类视图相对于函数视图有更高的复用性,如果其他地方需要用到某个类视图的某个特定逻辑,直接继承该类视图即可
代码如下:
在上面的子应用中
from django.views import View
def wrapper(func):
def inner(*args,**kwargs):
print("获取页面数据1")
ret = func(*args,**kwargs)
print("获取页面数据2")
return ret
return inner
class ReGISterView(View):
@wrapper
def get(self,*args,**kwargs):
print("test get page")
return HttpResponse("get page")
def post(self,*args,**kwargs):
print("test post page")
return HttpResponse("post page")
urlpatterns = [
url(r"^register/$", views.RegisterView.as_view()),
]
中间件
中间件的定义方法
在testdatabase应用中新建一个middleware.py文件,
def my_middleware(get_response):
print('init 被调用')
def middleware(request):
print('before request 被调用')
response = get_response(request)
print('after response 被调用')
return response
return middleware
定义好中间件后,需要在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',
'testdatabase.middleware.my_middleware', # 添加中间件
]
定义一个视图进行测试
def demo_view(request):
print('view 视图被调用')
return HttpResponse('OK')
多个中间件的执行顺序
在请求视图被处理前,中间件由上至下依次执行
在请求视图被处理后,中间件由下至上依次执行
代码如下:
定义两个中间件
def my_middleware(get_response):
print('init 被调用')
def middleware1(request):
print('before request 被调用')
response = get_response(request)
print('after response 被调用')
return response
return middleware
def my_middleware2(get_response):
print('init2 被调用')
def middleware(request):
print('before request 2 被调用')
response = get_response(request)
print('after response 2 被调用')
return response
return middleware
注册添加两个中间件
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',
'testdatabase.middleware.my_middleware1', # 添加中间件
'testdatabase.middleware.my_middleware2', # 添加中间件
]
执行结果为:
init2 被调用
init 被调用
before request 被调用
before request 2 被调用
view 视图被调用
after response 2 被调用
after response 被调用
数据库
ORM的关系
一对多 ForeignKey 在多的一方设置外键
多对多 ManyToMany 一般设置在处理业务逻辑比较多的一方
配置
在settings.py中保存了数据库的连接配置信息,Django默认初始配置使用sqlite数据库。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
使用Mysql数据库
pip install Pymysql
在Django的工程同名子目录的__init__.py文件中添加如下语句
# 将PyMySQL装饰成MySQLdb,方便Django识别
from pymysql import install_as_MySQLdb
install_as_MySQLdb()
修改DATABASES配置信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'root', # 数据库用户名
'PASSWord': 'mysql', # 数据库用户密码
'NAME': 'py6_django' # 数据库名字
}
}
在MySQL中创建数据库
create database py6_django default charset=utf8;
进行数据库的迁移操作
迁移文件的生成
python manage.py makemigrations
同步到数据库中
python manage.py migrate
如果不成功使用强制迁移
强制迁移
python manage.py migrate testdatabase --fake
查看MySQL数据库日志
......
tail -f /var/log/mysql/mysql.log # 可以实时查看数据库的日志内容
利用ORM创建表并手动增加数据
# 添加数据
book = BookInfo(
btitle='西游记',
bpub_date=date(1988, 1, 1),
bread=10,
bcomment=10)
book.save()
hero = HeroInfo(
hname="孙悟空",
hgender=0,
hcomment="七十二变",
hbook=book,
is_delete=0,
)
hero.save()
hero = HeroInfo(
hname="猪八戒",
hgender=0,
hbook_id=book.id,
is_delete=0,
)
hero.save()
HeroInfo.objects.create(
hname='沙悟净',
hgender=0,
hbook=book
)
# 基本查询
print(BookInfo.objects.all())
print(BookInfo.objects.get(btitle='雪山飞狐').id)
print(BookInfo.objects.get(id=3))
print(BookInfo.objects.get(pk=3))
# 将ID=3的排除,显示其他的
print(BookInfo.objects.exclude(id=3))
print(111111111)
try:
print(BookInfo.objects.get(id=12))
# except Exception as e:
# 使用get获取数据时,如果没有回抛出异常
except BookInfo.DoesNotExist:
print("未找到对应的ID")
print(BookInfo.objects.count())
# 关于values的查询
print("values".center(80,"*"))
print(BookInfo.objects.values("btitle","bpub_date"))
print("values_list".center(80,"#"))
print(BookInfo.objects.values_list("btitle","bpub_date"))
# 关于reverse的翻转
print("reverse".center(80,"*"))
print(BookInfo.objects.all().reverse())
# 获取最后一个数据
print("last".center(80,"#"))
print(BookInfo.objects.all().last())
# 获取第一个数据
print("first".center(80,"*"))
print(BookInfo.objects.all().first())
# 判断数据库中是否有数据
print(BookInfo.objects.exists())
# 过滤查询
# 表示判等
print(BookInfo.objects.filter(id__exact=1))
print(BookInfo.objects.filter(id=1)[0])
# 是否包含 contains
# 忽略大小写 icontains
print(BookInfo.objects.filter(btitle__contains="西"))
#相当于between and 左右闭区间 1 <= ret <=5
print(BookInfo.objects.filter(id__range(1,5)))
print(BookInfo.objects.filter(btitle__startswith="雪"))
print(BookInfo.objects.filter(btitle__endswith="传"))
# 时间和日期的查询
print(BookInfo.objects.filter(bpub_date__year=1986))
print(BookInfo.objects.filter(bpub_date__gt=date(1986,1,1)))
# 空查询
# 查询书名不为空的
print(BookInfo.objects.filter(btitle__isnull=False))
# 查询书名为空的
print(BookInfo.objects.filter(btitle__isnull=True))
# 范围查询
print(BookInfo.objects.filter(id__in=[1,2,3,5,7]))
# 比较查询
print(BookInfo.objects.filter(id__gt=3))
print(BookInfo.objects.filter(id__gte=3))
print(BookInfo.objects.filter(id__lt=3))
print(BookInfo.objects.filter(id__lte=3))
# F对象(两个字段作比较) -->横向比较,可以进行F(("bcomment")+1)*4操作
# 查询阅读量大于评论量的读书
print(BookInfo.objects.filter(bread__gt=10)) # 阅读量大于10
print(BookInfo.objects.filter(bread__gt=F("bcomment")))
# 查询阅读量大于2倍评论量的读书
print(BookInfo.objects.filter(bread__gt=F("bcomment")*2))
# 给每本书加版本
print(BookInfo.objects.update(btitle=Concat(F("btitle"),Value("(第一版)"))))
# Q对象 -->多个条件的 & | ~
# 查询阅读量大于20并且编号小于3
print(BookInfo.objects.filter(bread__gt=20,id__lt=3))
# 查询阅读量大于20,或者编号小于3
print(BookInfo.objects.filter(Q(bread__gt=20) | Q(id__lt=3)))
# 查询编号不为3的
print(BookInfo.objects.filter(~Q(id=3)))
# 聚合函数
# 查询所有的阅读数
print(BookInfo.objects.aggregate(get_sum = Sum("bread")))
# 查询所有的书籍
print(BookInfo.objects.count())
# 分组查询 annotate
books = BookInfo.objects.all().annotate(read = Count("bread"))
for book in books:
print(book.read)
# 排序
# 升序
print(BookInfo.objects.all().order_by("bread"))
# 降序
print(BookInfo.objects.all().order_by("-bread"))
# 关联查询
# 由一到多的访问语法 -->一对应的模型类对象,多对应的模型类名小写_set
book = BookInfo.objects.get(id=1)
print(book.heroinfo_set.all())
# 由多到一的访问语法 -->多对应模型类对象,一对应模型类中的关系类属性名
hero = HeroInfo.objects.get(id=1)
print(hero.hbook)
#访问一对应的模型类关联对象的id语法:多对应的模型类对象.关联类属性_id
hero = HeroInfo.objects.get(id=1)
print(hero.hbook_id)
# 关联过滤查询
# 由多模型类条件查询一模型类数据:
# 语法如下:
# 关联模型类名小写__属性名__条件运算符 = 值
# 注意:如果没有 "__运算符"部分,表示等于
# 图书英雄是孙悟空
print(BookInfo.objects.filter(heroinfo__hname="孙悟空"))
# 要求图书中英雄的描述包含八
print(BookInfo.objects.filter(heroinfo__hname__contains="郭"))
# 由一模型类条件查询多模型类数据:
# 语法如下:
# 一模型类关联属性名__一模型类属性名__条件运算符=值
# 注意:如果没有"__运算符"部分,表示等于
# 查询书名为天龙八部中的所欲英雄
print(HeroInfo.objects.filter(hbook__btitle="天龙八部"))
# 查询阅读量大于30的所有英雄
print(HeroInfo.objects.filter(hbook__bread__gt=30))
# 修改
# 修改方法一:
# 具体的对象没有updete方法.只有QuerySet对象才有update方法
hero = HeroInfo.objects.get(hname='猪八戒')
hero.hname = '猪悟能'
hero.save()
# 修改方法二:
HeroInfo.objects.filter(hname='沙悟净').update(hname='沙僧')
# 删除
# 模型类对象.delete()
hero = HeroInfo.objects.get(id=13)
hero.delete()
# 模型类.objects.filter().delete()
HeroInfo.objects.filter(id=17).delete()
查询集 QuerySet
概念:
Django的ORM中存在查询集的概念。
查询集,也称查询结果集、QuerySet,表示从数据库中获取的对象集合。
当调用如下过滤器方法时,Django会返回查询集(而不是简单的列表):
all():返回所有数据。
filter():返回满足条件的数据。
exclude():返回满足条件之外的数据。
order_by():对结果进行排序。
对查询集可以再次调用过滤器进行过滤,如
BookInfo.objects.filter(bread__gt=30).order_by('bpub_date')
也就意味着查询集可以含有零个、一个或多个过滤器.
过滤器基于所给的参数限制查询的结果
从SQL的角度讲,查询集与select语句等价,过滤器像where、limit、order by子句。
判断某一个查询集中是否有数据:
exists():判断查询集中是否有数据,如果有则返回True,没有则返回False。
两大特性
惰性执行
缓存
限制查询集
管理器Manager
概念:
管理器是Django的模型进行数据库操作的接口,Django应用的每个模型类都拥有
至少一个管理器。我们在通过模型类的objects属性提供的方法操作数据库时,
即是在使用一个管理器对象objects。当没有为模型类定义管理器时,
Django会为每一个模型类生成一个名为objects的管理器,它是models.Manager类的对象。
自定义管理器
我们可以自定义管理器,并应用到我们的模型类上。
注意:一旦为模型类指明自定义的过滤器后,Django不再生成默认管理对象objects。
自定义管理器类主要用于两种情况:
1. 修改原始查询集,重写all()方法。
a)打开booktest/models.py文件,定义类BookInfoManager
#图书管理器
class BookInfoManager(models.Manager):
def all(self):
#默认查询未删除的图书信息
#调用父类的成员语法为:super().方法名
return super().filter(is_delete=False)
b)在模型类BookInfo中定义管理器
class BookInfo(models.Model):
...
books = BookInfoManager()
c)使用方法
BookInfo.books.all()
2. 在管理器类中补充定义新的方法
a)打开booktest/models.py文件,定义方法create。
class BookInfoManager(models.Manager):
#创建模型类,接收参数为属性赋值
def create_book(self, title, pub_date):
#创建模型类对象self.model可以获得模型类
book = self.model()
book.btitle = title
book.bpub_date = pub_date
book.bread=0
book.bcommet=0
book.is_delete = False
# 将数据插入进数据表
book.save()
return book
b)为模型类BookInfo定义管理器books语法如下
class BookInfo(models.Model):
...
books = BookInfoManager()
c)调用语法如下:
book=BookInfo.books.create_book("abc",date(1980,1,1))
模板
1)配置文件
在工程中根目录下创建模板目录templates
在settings.py配置文件中修改TEMPLATES配置项的DIRS值
TEMPLATES = [
{
'DIRS': [os.path.join(BASE_DIR, 'templates')], # 此处修改
}
]
2)定义模板文件(index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ city }}</h1>
</body>
</html>
3)模板渲染
模板渲染需要三步
找到模板
定义上下文
渲染模板
第一种方法:
from django.http import HttpResponse
from django.template import loader, RequestContext
def index(request):
# 1.获取模板
template=loader.get_template('testdatabase/index.html')
# 2.定义上下文
context={'city': '北京'}
# 3.渲染模板
# httpresponse返回的是一个含有HTML的字符串
return HttpResponse(template.render(context))
第二种方法:
from django.shortcuts import render
def index(request):
context={'city': '北京'}
return render(request,'index.html',context)
4)模板语法
模板变量
视图函数代码如下:
def index(request):
context = {
'city': '北京',
'adict': {
'name': '西游记',
'author': '吴承恩'
},
'alist': [1, 2, 3, 4, 5]
}
return render(request, 'index.html', context)
# 前端代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ city }}</h1>
<h1>{{ adict }}</h1>
<h1>{{ adict.name }}</h1> 注意字典的取值方法
<h1>{{ alist }}</h1>
<h1>{{ alist.0 }}</h1> 注意列表的取值方法
</body>
</html>
模板语句
for循环
{% for item in 列表 %}
循环逻辑
{{forloop.counter}}表示当前是第几次循环,从1开始
{%empty%} 列表为空或不存在时执行此逻辑
{% endfor %}
if语句
{% if ... %}
逻辑1
{% elif ... %}
逻辑2
{% else %}
逻辑3
{% endif %}
注意:运算符左右两侧不能紧挨变量或常量,必须有空格。
{% if a == 1 %} # 正确
{% if a==1 %} # 错误
过滤器
语法如下:
变量|过滤器:参数
和flask一样基本没变化
注释
单行注释语法如下:
{#...#}
多行注释使用comment标签,语法如下:
{% comment %}
...
{% endcomment %}
模板继承
只有继承操作
{% extend "抽取的基类模板"%}
进行挖坑填坑操作
{% block 名称 %}
#实际填充内容
{{ block.super }}用于获取父模板中block的内容
{% endblock 名称 %}
表单
form表单
非form表单
admin站点
使用Django的管理模块,需要按照如下步骤操作:
1)管理界面本地化
在settings.py中设置语言和时区
LANGUAGE_CODE = 'zh-hans' # 使用中国语言
TIME_ZONE = 'Asia/Shanghai' # 使用中国上海时间
2)创建管理员
创建管理员的命令如下,按提示输入用户名、邮箱、密码。
python manage.py createsuperuser
创建成功可访问:
http://127.0.0.1:8000/admin/
3)注册模型类
打开testdatabase/admin.py文件,编写如下代码:
from django.contrib import admin
from booktest.models import BookInfo,HeroInfo
admin.site.register(BookInfo)
admin.site.register(HeroInfo)
4)自定义管理页面
具体看子应用testdabase的设置
0