一、Windows平台安装Django参考:
http://www.runoob.com/django/django-install.html
官网:https://www.djangoproject.com/download/
二、查看版本操作
1、查看版本:先导入,然后django.get_version()
三、创建项目(使用django-admin.py来创建HelloWorld项目)
1、
django-admin startproject HelloWorld
2、进入HelloWorld目录启动服务:
python manage.py runserver 127.0.0.1:8000(不写默认8000)
3、在浏览器输入:127.0.0.1:8000查看
四、视图和URL配置
1、配置view.py:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello world ! ")
2、绑定URL与视图函数,配置urls.py:
from django.urls import path
from . import view
urlpatterns = [
# 127.0.0.1:8000
path(‘’,view.hello),
# 127.0.0.1:8000/admin/
path(‘admin/’,view.hello),
]
五、Django模板
在HelloWorld目录下创建templates目录并建立hello.html文件
1、hello.html添加:<h1>{{hello}}</h1>
2、修改settings.py:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# 修改的地方
'DIRS': [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',
],
},
},
]
3、修改view.py,增加一个新的对象,用于向模板提交数据:
# from django.http import HttpResponse
from django.shortcuts import render
import datetime
def hello(request):
athlete_list = ["第一","第二","第三","第四"]
context = {}
context['current_date'] = datetime.datetime.now().strftime('%H:%M:%S %Y/%m/%d')
context['hellokey'] = 'Hello Word!'
context['num1'] = 7
context['num2'] = 6
context['num3'] = 6
context['num4'] = 6
context['athlete_list'] = athlete_list
return render(request,'hello.html',context)
# return HttpResponse("Hello World!!!!")
context 字典中元素的键值 "hello" 对应了模板中的变量 "{{ hello }}"。
六、Django模板标签
if/else标签,在hello.html中操作:
{% if num1 > num2 %}
<h2>{{ hellokey|first|lower}}取出第一个单词并小写</h2>
<h1>{{ hellokey|lower}}所有单词小写,upper大写</h1>
<h2>{{ hellokey|length}}hellokey的长度</h2>
<i>显示num1的值,num1= {{num1}}</i>
<br>
{% elif num1 == num2 %}
<h1>num1等于num2,值为:{{num1}}</h1>
{% else %}
<b>else语句加粗</b>
{% endif %}
ifequal/ifnotequal标签(比较两个值是否相等):
{% ifequal num3 num4 %}
<h3>num3等于num4,值为:{{num3}}</h3>
{% endifequal %}
for标签使用:
<ul>
{% for athlete in athlete_list %}
<li>{{athlete}}</li>
{# 注释:循环嵌套 #}
{% for h in hellokey %}
<li>{{h|truncatewords:”1”}}显示变量的前1个单词,0不显示用…代替</li>
{% endfor %}
{% endfor %}
</ul>
include标签:
{% include “base.html” %}
not使用:
{% if not num1 == 2 %}
<b>not使用</b>
{% endif %}
and使用:
{% if num1 == 7 and num2 == 6 %}
<b>and使用</b>
{% endif %}
or使用:
{% if num1 == 2 or num2 == 6 %}
<b>or使用</b>
{% endif %}
reversed反向迭代:
<div>
<!—加上reversed反向迭代-->
{% for athlete in athlete_list reversed %}
<div>
<b>{{athlete}}</b>
</div>
{% endfor %}
</div>
注释标签:
{# 这是一个注释,不会显示出来!#}
模板继承操作:
templates 目录中添加 base.html 文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板继承</title>
</head>
<body>
<h1>Hello World!继承操作</h1>
<p>Django测试继承</p>
{% block mainbody %}
<p>original</p>
{% endblock %}
</body>
</html>
以上代码中,名为 mainbody 的 block 标签是可以被继承者们替换掉的部分。
hello.html 中继承 base.html,并替换特定 block,hello.html 修改后的代码如下:
继承中extends必须是第一个标签,否则会报错
{% extends "base.html" %}
{% block mainbody %}
<p>继承了 base.html 文件</p>
<p>It is now {{ current_date }}</p>
===========include=========***************
{% include "base.html" %}
{% endblock %}
=============endblock之后的东西都不会显示======================
extends代码说明 hello.html 继承了 base.html 文件。可以看到,这里相同名字的 block 标签用以替换 base.html 的相应 block。
继承中extends必须是第一个标签,否则会报错
输出结果如下:
以下是hello.html全部代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Django模板标签</title>
</head>
<body>
继承中extends必须是第一个标签,否则会报错
{% extends "base.html" %}
{% block mainbody %}
<p>继承了 base.html 文件</p>
<p>It is now {{ current_date }}</p>
===========include=========***************
{% include "base.html" %}
{% endblock %}
=============endblock之后的东西都不会显示======================
<h1>{{ hellokey }}</h1>
<h2>{{hellokey}}</h2>
{# if判断取num1值的时候不加大括号#}
{% if num1 > num2 %}
<h1>============</h1>
<h2>{{ hellokey|first|lower}}取出第一个单词并小写</h2>
<h2>{{ hellokey|lower}}所有单词小写</h2>
<h2>{{ hellokey|length}}长度</h2>
{# 显示num1的值要加两个大括号 #}
<i>num1 = {{num1}}</i>
<br>
<i>num2 = {{num2}}</i>
<h1>============</h1>
{% elif num1 == num2 %}
<h1>num1等于num2,值为:{{num1}}</h1>
{% else %}
<b>else加粗</b>
{% endif %}
{% ifequal num3 num4 %}
<h3>num3等于num4,值为:{{num3}};{{ hellokey }}</h3>
{% endifequal %}
{% if num1 == 7 and num2 == 6 %}
<h2>and使用</h2>
{% endif %}
<!--or使用-->
{% if num1 == 7 or num2 == 8%}
<i>or使用</i>
{% endif %}
<br>
<!--not使用-->
{% if not num1 == 2 %}
<b>not使用</b>
{% endif %}
<ul>
{% for athlete in athlete_list %}
<li>{{athlete}}</li>
{% for h in hellokey %}
<li>{{h|truncatewords:"1"}}显示变量的前1个词,0不显示用...代替</li>
{% endfor %}
{% endfor %}
</ul>
<div>
<!--加上reversed反向迭代-->
{% for athlete in athlete_list reversed %}
<div>
<b>{{athlete}}</b>
</div>
{% endfor %}
</div>
</body>
</html>
七、Django模型-数据库配置
下载对应操作系统的 whl 文件安装mysqlclient:https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient
修改settings.py 文件的 DATABASES 配置项:
DATABASES = {
'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
'ENGINE': 'django.db.backends.mysql',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# 数据库名字
'NAME': 'python3',
# 用户
'USER':'root',
'PASSWORD':'123456',
'HOST':'localhost',
'PORT':'3306',
}
}
这里添加了中文注释,所以你需要在 HelloWorld/settings.py 文件头部添加 # -*- coding: UTF-8 -*-。上面包含数据库名称和用 户的信息,它们与 MySQL 中对应数据库和用户的设置相同。
定义模型-创建APP
django-admin startapp TestModel
修改 TestModel/models.py 文件,代码如下:
# -*- coding: UTF-8 -*-
from django.db import models
class Test(models.Model):
# 数据类型由CharField(相当于varchar)、DateField(相当于datetime), max_length 参数限定长度
name = models.CharField(max_length=20)
以上的类名代表了数据库表名,且继承了models.Model,类里面的字段代表数据表中的字段(name),数据类型则由 CharField(相当于varchar)、DateField(相当于datetime), max_length 参数限定长度。
接下来在settings.py中找到INSTALLED_APPS这一项,如下:
INSTALLED_APPS = [
'django.contrib.admin', # admin管理后台站点
'django.contrib.auth', # 身份认证系统
'django.contrib.contenttypes', # 内容类型框架
'django.contrib.sessions', # 会话框架
'django.contrib.messages', # 消息框架
'django.contrib.staticfiles', # 静态文件管理框架
# 新增此项
'TestModel',
]
在命令行中运行:
python manage.py migrate # 创建表结构
python manage.py makemigrations TestModel # 让 Django 知道我们在我们的模型有一些变更
python manage.py migrate TestModel # 创建表结构
数据库操作:
接下来我们在 HelloWorld 目录中添加 testdb.py 文件(下面介绍),并修改 urls.py:
from django.urls import path
from . import view,testdb
urlpatterns = [
# http://127.0.0.1:8000
path('',view.hello),
# http://127.0.0.1:8000/admin/
path('admin/', view.hello),
# http://127.0.0.1:8000/testdb/
path('testdb/', testdb.testdb),
]
添加数据(添加数据需要先创建对象,然后再执行 save 函数,相当于SQL中的INSERT)testdb.py:
# coding=utf-8
from django.http import HttpResponse
from TestModel.models import Test
# 数据库操作
def testdb(request):
test1 = Test(name='runoob')
test1.save()
return HttpResponse("<p>网页每刷新一次添加一次name的值,数据添加成功!</p>")
获取数据,一定要先添加数据,之后才能获取数据,上面的步骤网页每刷新一次就会添加一次name的值,:
修改 testdb.py:
#!/usr/bin/env python
# coding=utf-8
from django.http import HttpResponse
from TestModel.models import Test
# 数据库操作
def testdb(request):
# test1 = Test(name='runoob')
# test1.save()
# return HttpResponse("<p>网页每刷新一次添加一次name的值,数据添加成功!</p>")
#初始化
response = ""
response1 = ""
# 通过objects这个模型管理器的all()获得所有数据行,相当于SQl中的SELECT * FROM
list = Test.objects.all()
# filter相当于SQL中的WHERE,可设置条件过滤结果
response2 = Test.objects.filter(id=7)
# 获取单个对象
response3 = Test.objects.get(id=7)
# 更新数据:修改其中一个id=10的name字段,再save,相当于SQL中的UPDATE
update_test = Test.objects.get(id=10)
update_test.name = "python"
update_test.save()
# 更新数据另一种方法:
Test.objects.filter(id=8).update(name="java")
# 更新所有列:
# Test.objects.all().update(name = "python!")
# 删除数据,删除后此id则不会存在,再次调取会报错
# test1 = Test.objects.get(id=2)
# test1.delete()
# 删除数据另一种方法
# Test.objects.filter(id=3).delete()
# 删除所有
# Test.objects.all().delete()
# 限制返回的数据 相当于SQL中的OFFSET 0 LIMIT 2(从索引为0的数据开始取出2条数据)按照id排序
# response4 = Test.objects.order_by('id').all()[0::2]
response4 = Test.objects.order_by('id')[0::2]
# for i in response4:
# print(i.name)
# 数据排序
# Test.objects.order_by('id')
# 这个是筛选出name为python的所有数据,并按照id排序
re = Test.objects.filter(name="python").order_by("id")
for i in re:
print(i.id,i.name)
# 输出response4获取的数据 每个数据前面加上序号
for i in response4:
response += str(i.id) + " " + i.name + "<br>"
return HttpResponse("<p>" + response + "</p>")
# 输出所有数据
# for var in list:
# response1 += var.name + "<br>"
# response = response1
# return HttpResponse("<p>" +response.name +"</p>")
访问 http://127.0.0.1:8000/testdb 就可以看到数据,并且在mysql客户端(如Navicat中的testmodel_test表)可看到所有数据。
八、Django表单:
GET方法:在之前的项目中新建search.py
/HelloWorld/HelloWorld/search.py 文件代码:
#!/usr/bin/env python
# coding=utf-8
from django.http import HttpResponse
from django.shortcuts import render_to_response
# 表单操作 GET方法
def search_form(request):
return render_to_response('search_form.html')
# 接收请求的数据
def search(request):
request.encoding='utf-8'
if 'q' in request.GET:
if len(request.GET['q'])!=0:
message = "你搜索的内容为:"+ request.GET['q']
else:
message = "你提交了空表单"
else:
message = "你提交了空表单"
return HttpResponse(message)
在模板目录 templates 中添加 search_form.html 表单:
/HelloWorld/templates/search_form.html 文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>GET表单操作</title>
</head>
<body>
<form action="/search" method="get">
<input type="text" name="q">
<input type="submit" value="搜索">
</form>
</body>
</html>
urls.py 规则修改为如下形式:
# coding=utf-8
from django.urls import path
from . import view,testdb,search
urlpatterns = [
# http://127.0.0.1:8000
path('',view.hello),
# http://127.0.0.1:8000/admin/
path('admin/', view.hello),
# http://127.0.0.1:8000/testdb/
path('testdb/', testdb.testdb),
path('search-form/', search.search_form),
path('search/', search.search),
]
访问地址 http://127.0.0.1:8000/search-form 并搜索,结果如下所示:POS
POS方法: 用一个URL和处理函数,同时显示视图和处理请求。
在 templates 创建 post.html:
/HelloWorld/templates/post.html 文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>POST表单操作</title>
</head>
<body>
<form action="/search-post/" method="post">
{#csrf全称Cross Site Request Forgery。这是Django提供的防止伪装提交请求的功能。POST方法提交的表格,必须有此标签。#}
{% csrf_token %}
<input type="text" name="q">
<input type="submit" value="Submit">
</form>
<p>{{ rlt}}</p>
</body>
</html>
rlt 为表格处理结果预留位置。
注意:提交表单报错:RuntimeError: You called this URL via POST,but the URL doesn’t end in a slash and you have APPEND_SLASH set。。。可将form的action地址改为/结尾:action="/search-post/"或者在settings.py中添加:APPEND_SLASH=False,具体参考(http://www.cnblogs.com/zhxhdean/p/3173663.html)
在HelloWorld目录下新建 search2.py 文件并使用 search_post 函数来处理 POST 请求:
/HelloWorld/HelloWorld/search2.py 文件代码:
#!/usr/bin/env python
# coding=utf-8
from django.shortcuts import render
from django.views.decorators import csrf
# 接收POST请求数据
def search_post(request):
ctx={}
if request.POST:
result = request.POST['q']
if len(result)!=0:
# rlt获取输入的结果
ctx['rlt'] = '您输入的内容是:'+request.POST['q']
else:
ctx['rlt'] = '您未输入任何值!'
return render(request,"post.html",ctx)
urls.py 规则修改为如下形式:
from django.urls import path
from . import view,testdb,search,search2
urlpatterns = [
# http://127.0.0.1:8000
path('',view.hello),
# http://127.0.0.1:8000/admin/
path('admin/', view.hello),
# http://127.0.0.1:8000/testdb/
path('testdb/', testdb.testdb),
path('search-form/', search.search_form),
path('search/', search.search),
path('search-post/', search2.search_post),
]
访问 http://127.0.0.1:8000/search-post 显示结果如下:
九、Django Admin管理工具:
Django 自动管理工具是 django.contrib 的一部分。你可以在项目的 settings.py 中的 INSTALLED_APPS 看到它:
/HelloWorld/HelloWorld/settings.py 文件代码:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
激活管理工具:
/HelloWorld/HelloWorld/urls.py 文件代码:
from django.contrib import admin
from django.urls import path
urlpatterns = [
# admin管理工具http://127.0.0.1:8000/admin/
path('admin/',admin.site.urls),
]
启动开发服务器,然后在浏览器中访问 http://127.0.0.1:8000/admin/,得到如下界面:
这里是英文界面,修改为中文的方法:
/HelloWorld/HelloWorld/settings.py 文件代码:
# 修改admin后台管理为中文
LANGUAGE_CODE = 'zh-Hans'
# LANGUAGE_CODE = 'en-us'
# UTC协调世界时,又称世界统一时间、世界标准时间、国际协调时间。
# TIME_ZONE = 'UTC'
#修改时区为东八区
TIME_ZONE = 'Asia/Shanghai'
# 改为False
USE_TZ = False
通过命令 python manage.py createsuperuser 来创建超级用户,如下所示:
执行命令 python manage.py createsuperuser
Username (leave blank to use 'root'): admin
Email address: admin@163.com
Password:
Password (again):
Superuser created successfully.
之后输入用户名密码登录,界面如下:
为了让 admin 界面管理某个数据模型,我们需要先注册该数据模型到 admin。比如,我们之前在 TestModel 中已经创建了模型 Test 。修改 TestModel/admin.py:
HelloWorld/TestModel/admin.py: 文件代码:
from django.contrib import admin
from TestModel.models import Test
# Register your models here.
admin.site.register(Test)
刷新后即可看到 Testmodel 数据表:
复杂模型处理:
在 TestModel/models.py 中增加一个更复杂的数据模型(这里有两个表,Tag 以 Contact 为外部键。一个 Contact 可以对应多个 Tag。):
HelloWorld/TestModel/models.py: 文件代码:
# -*- coding: UTF-8 -*-
from django.db import models
class Test(models.Model):
# 数据类型由CharField(相当于varchar)、DateField(相当于datetime), max_length 参数限定长度
name = models.CharField(max_length=20)
class Contact(models.Model):
name = models.CharField(max_length=200)
age = models.IntegerField(default=0) # IntegerField 用于存储整数默认0
email = models.EmailField()
# def __unicode__(self):
# django admin下拉列表不显示值,显示为object的处理,python3用下面的方法
def __str__(self):
return self.name
class Tag(models.Model):
# 使用ForeignKey定义了一个外键关系,每一个Tag关联到一个对应的Contact,注意要将外键写在‘多’的一方
contact = models.ForeignKey('Contact',on_delete=models.CASCADE,)
name = models.CharField(max_length=50)
# def __unicode__(self):
# django admin下拉列表不显示值,显示为object的处理,python3用下面的方法
def __str__(self):
return self.name
在 TestModel/admin.py 注册多个模型并显示:
HelloWorld/TestModel/admin.py: 文件代码:
from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.
admin.site.register([Test,Contact,Tag])
如果之前还未创建表结构,可使用以下命令创建:
python manage.py makemigrations TestModel # 让 Django 知道我们在我们的模型有一些变更
python manage.py migrate TestModel # 创建表结构
自定义表单:
我们可以自定义管理页面,来取代默认的页面。比如上面的 "add" 页面。我们想只显示 name 和 email 部分。修改 TestModel/admin.py:
from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.
# 自定义管理页面admin,来取代默认的页面
class ContactAdmin(admin.ModelAdmin):
fields = ('name','email')
admin.site.register(Contact,ContactAdmin)
# 增加模型
admin.site.register([Test,Tag])
# 如果报错:django.contrib.admin.sites.NotRegistered: The model Contact is not registered
# 确认代码无误,再重新启动服务即可
以上代码定义了一个 ContactAdmin 类,用以说明管理页面的显示格式。 里面的 fields 属性定义了要显示的字段。 由于该类对应的是 Contact 数据模型,我们在注册的时候,需要将它们一起注册。显示效果如下:
还可以将输入栏分块,每个栏也可以定义自己的格式。修改 TestModel/admin.py为:
from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.
# 自定义管理页面admin,来取代默认的页面
class ContactAdmin(admin.ModelAdmin):
# 将输入栏分块
fieldsets = (
['Main必填项',{
'fields':('name','email'),
}],
# collapse折叠插件CSS样式里
['Advance可选项',{
'classes':('collapse',),
'fields':('age',),
}]
)
admin.site.register(Contact,ContactAdmin)
# 增加模型
admin.site.register([Test,Tag])
# 如果报错:django.contrib.admin.sites.NotRegistered: The model Contact is not registered
# 确认代码无误,再重新启动服务即可
内联(Inline)显示
上面的 Contact 是 Tag 的外部键,所以有外部参考的关系。
而在默认的页面显示中,将两者分离开来,无法体现出两者的从属关系。我们可以使用内联显示,让 Tag 附加在 Contact 的编辑页面上显示。
修改TestModel/admin.py:
from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.
# 内联显示 TabularInline表格形式嵌入;StackedInline默认嵌入
class TagInline(admin.TabularInline):
model = Tag
# 内联显示多少个
extra = 3
# 自定义管理页面admin,来取代默认的页面
class ContactAdmin(admin.ModelAdmin):
# 内联显示
inlines = [TagInline]
# 将输入栏分块
fieldsets = (
['Main必填项',{
'fields':('name','email'),
}],
# collapse折叠插件CSS样式里
['Advance可选项',{
'classes':('collapse',),
'fields':('age',),
}]
)
admin.site.register(Contact,ContactAdmin)
# 增加模型
admin.site.register([Test,Tag])
# 如果报错:django.contrib.admin.sites.NotRegistered: The model Contact is not registered
# 确认代码无误,再重新启动服务即可
列表页的显示(输入多条数据后):
可以自定义该页面的显示,比如在列表中显示更多的栏目,只需要在 ContactAdmin 中增加 list_display 属性:
HelloWorld/TestModel/admin.py: 文件代码:
from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.
# 内联显示
class TagInline(admin.TabularInline):
model = Tag
# 自定义管理页面admin,来取代默认的页面
class ContactAdmin(admin.ModelAdmin):
# 增加列表页显示更多栏目
list_display = ('name','age','email')
# 内联显示
inlines = [TagInline]
# 将输入栏分块
fieldsets = (
['Main必填项',{
'fields':('name','email'),
}],
# collapse折叠插件CSS样式里
['Advance可选项',{
'classes':('collapse',),
'fields':('age',),
}]
)
# admin.site.unregister(Contact)
admin.site.register(Contact,ContactAdmin)
# 增加模型
admin.site.register([Test,Tag])
# 如果报错:django.contrib.admin.sites.NotRegistered: The model Contact is not registered
# 确认代码无误,再重新启动服务即可
还可以在 ContactAdmin 中增加 list_filter 属性 ,增加过滤器:
# 过滤器
list_filter = ['name']
还可以在 ContactAdmin 中增加 list_per_page 属性 ,增加分页:
搜索功能在管理大量记录时非常有,我们可以使用 search_fields 为该列表页增加搜索栏:
HelloWorld/TestModel/admin.py: 文件代码:
from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.
# 内联显示
class TagInline(admin.TabularInline):
model = Tag
# 自定义管理页面admin,来取代默认的页面
class ContactAdmin(admin.ModelAdmin):
# 增加列表页显示更多栏目
list_display = ('name','age','email')
# 增加搜索功能,是一个列表或者元组,按name搜索,也可以增加多个
search_fields = ('name',)
# 内联显示
inlines = [TagInline]
# 将输入栏分块
fieldsets = (
['Main必填项',{
'fields':('name','email'),
}],
# collapse折叠插件CSS样式里
['Advance可选项',{
'classes':('collapse',),
'fields':('age',),
}]
)
# admin.site.unregister(Contact)
admin.site.register(Contact,ContactAdmin)
# 增加模型
admin.site.register([Test,Tag])
# 如果报错:django.contrib.admin.sites.NotRegistered: The model Contact is not registered
# 确认代码无误,再重新启动服务即可
如果models.py里有布尔值,会显示不友好(不是一个直观的结果):
from django.db import models
# 图书表结构设计
class BookInfo(models.Model):
# 图书名称
btitle = models.CharField('图书名称',max_length=20)
# 图书发布时间
bpub_date =models.DateTimeField('图书发布时间')
def __str__(self):
return self.btitle
# 英雄表结构设计
class HeroInfo(models.Model):
# 英雄姓名
hname = models.CharField('英雄姓名',max_length=10)
# 英雄性别
hgender = models.BooleanField(default='男')
# 英雄简介
hcontent = models.CharField('英雄简介',max_length=1000)
# 所属图书,外键,注意要将外键写在‘多’的一方
hbook = models.ForeignKey('BookInfo',on_delete=models.CASCADE)
def __str__(self):
return self.hname
admin.py:
from django.contrib import admin
from .models import *
# 向admin注册booktest的模型
# 增加内联 TabularInline
class HeroInline(admin.StackedInline):
model = HeroInfo
# 内联显示多少个
extra = 2
# 管理类修改
class BookInfoAdmin(admin.ModelAdmin):
list_display = ['id','btitle','bpub_date']
# 过滤器
list_filter = ['btitle']
# 搜索
search_fields = ['btitle']
# 分页
list_per_page = 1
# 分组
fieldsets = [
('基本字段',{'fields':['btitle']}),
# 'classes':['collapse']折叠高级字段
('高级字段',
{
'fields':['bpub_date'],
'classes':['collapse']
}
)
]
# 内联显示
inlines = [HeroInline]
class HeroInfoAdmin(admin.ModelAdmin):
list_display = ['id','hname','hgender','hcontent']
admin.site.register(HeroInfo,HeroInfoAdmin)
admin.site.register(BookInfo,BookInfoAdmin)
models.py修改为(增加gender类):
from django.db import models
# 图书表结构设计
class BookInfo(models.Model):
# 图书名称
btitle = models.CharField('图书名称',max_length=20)
# 图书发布时间
bpub_date =models.DateTimeField('图书发布时间')
def __str__(self):
return self.btitle
# 英雄表结构设计
class HeroInfo(models.Model):
# 英雄姓名
hname = models.CharField('英雄姓名',max_length=10)
# 英雄性别
hgender = models.BooleanField(default='男')
# 英雄简介
hcontent = models.CharField('英雄简介',max_length=1000)
# 所属图书,外键,注意要将外键写在‘多’的一方
hbook = models.ForeignKey('BookInfo',on_delete=models.CASCADE)
def __str__(self):
return self.hname
def gender(self):
if self.hgender:
return '男'
else:
return '女'
gender.short_description = '性别'
admin.py修改为(在admin注册中使用gender代替hgender):
from django.contrib import admin
from .models import *
# 向admin注册booktest的模型
# 增加内联 TabularInline
class HeroInline(admin.StackedInline):
model = HeroInfo
# 内联显示多少个
extra = 2
# 管理类修改
class BookInfoAdmin(admin.ModelAdmin):
list_display = ['id','btitle','bpub_date']
# 过滤器
list_filter = ['btitle']
# 搜索
search_fields = ['btitle']
# 分页
list_per_page = 1
# 分组
fieldsets = [
('基本字段',{'fields':['btitle']}),
# 'classes':['collapse']折叠高级字段
('高级字段',
{
'fields':['bpub_date'],
'classes':['collapse']
}
)
]
# 内联显示
inlines = [HeroInline]
class HeroInfoAdmin(admin.ModelAdmin):
list_display = ['id','hname','gender','hcontent']
admin.site.register(HeroInfo,HeroInfoAdmin)
admin.site.register(BookInfo,BookInfoAdmin)
设置哪些字段可以进入编辑界面以及排序,admin.py中:
from django.contrib import admin
from .models import *
class HeroInline(admin.TabularInline):
model = HeroInfo
# 装饰器注册
@admin.register(BookInfo)
class BookInfoAdmin(admin.ModelAdmin):
list_display = ['id','btitle','bpub_date']
# 设置列表页哪些字段可以点击进入编辑界面
list_display_links = ['btitle','bpub_date']
# 排序,注意是元组或者list,'-'倒序排序
ordering = ('-bpub_date','btitle')
# “操作选项”的位置,底部
# actions_on_bottom = True
fieldsets = [
('基本',{'fields':['btitle']}),
('高级',
{
'fields':['bpub_date'],
'classes':['collapse']
}
)
]
inlines = [
HeroInline,
]
class HeroInfoAdmin(admin.ModelAdmin):
list_display = ['id','hname']
list_filter = ['hname']
search_fields = ['hname']
# 显示字段的顺序,如果使用元组表示显示到一行上,新增的时候这两个字段会在一行
fields = [('hname', 'hcontent')]
# 不用装饰器注册情况
# admin.site.register(BookInfo,BookInfoAdmin)
admin.site.register(HeroInfo,HeroInfoAdmin)
十、自定义管理器对象:
自定义管理器类主要用于两种情况:
- 情况一:向管理器类中添加额外的方法,BookInfoManager中的create()方法
- 情况二:修改管理器返回的原始查询集:重写get_queryset()方法,BookInfoManager中的get_queryset()方法
models.py中操作:
from django.db import models
# 自定义管理器对象
class BookInfoManager(models.Manager):
def get_queryset(self):
# 自定义管理器类主要用于两种情况:①更改默认查询集的结果,这个例子按照isDelete=False查询
# 执行python manager.py shell 导入BookInfo(from booktest.models import BookInfo),
# BookInfo.books2.all() 这样结果会把isDelete=False的结果筛选出来
return super(BookInfoManager,self).get_queryset().filter(isDelete=False)
# 自定义管理器类主要用于两种情况:②向管理器类中添加额外的方法
# 定义一个模型类的方法,推荐此方法
# 执行python manager.py shell 导入BookInfo(from booktest.models import BookInfo),
# 使用:BookInfo.books2.create('某某书名','2019-1-1').save()添加数据
def create(self,btitle,bpub_date):
# b = BookInfo()和下面这个等同
b = self.model()
# 打印self为:booktest.BookInfo.books2
# print(self)
b.btitle = btitle
b.bpub_date = bpub_date
b.bread = 0
b.bcommet = 0
b.isDelete = False
return b
class BookInfo(models.Model):
# 默认管理器,使用方法:BookInfo.books1.all(),全部筛选出来,不能在使用:BookInfo.objects.all()
books1 = models.Manager()
# 自定义的管理器,使用方法:BookInfo.books2.all() 管理器是模型类的属性,用于将对象与数据表映射
books2 = BookInfoManager()
btitle = models.CharField('书名',max_length=20)
# db_column显示在数据库中的字段名字为:pub_date
bpub_date = models.DateTimeField(db_column='pub_date')
# 阅读量
bread = models.IntegerField(default=0)
# 评论数
bcommet = models.IntegerField(null=False)
isDelete = models.BooleanField(default=False)
# 元选项
class Meta:
# 表名称
db_table = 'bookinfo'
def __str__(self):
return self.btitle
# 自定义创建模型类对象方法,不推荐此方法
# 执行python manager.py shell 导入BookInfo(from booktest.models import BookInfo),
# 使用:BookInfo.create('abc','1990-1-1').save()
@classmethod # 类方法
def create(cls,btitle,bpub_date):
b = BookInfo()
b.btitle = btitle
b.bpub_date = bpub_date
b.bread = 0
b.bcommet = 0
b.isDelete = False
return b
class HeroInfo(models.Model):
hname = models.CharField(max_length=20)
hgender = models.BooleanField(default=True)
isDelete = models.BooleanField(default=False)
hcontent = models.CharField(max_length=1000)
hbook = models.ForeignKey('BookInfo',on_delete=models.CASCADE)
def __str__(self):
return self.hname
十一、查询集:
# values一个对象构成一个字典,然后构成一个列表返回
BookInfo.books2.values().order_by('-id') # 按照id倒序
# 筛选出bcommet评论数为0的个数
BookInfo.books2.all().filter(bcommet=0).count()
# first():返回评论数为0的第一个对象
BookInfo.books2.all().filter(bcommet=0).first()
# exists():判断查询集中是否有数据,如果有则返回True
BookInfo.books2.all().filter(bcommet=0).exists()
# 返回评论数为0的前三个对象,因为是列表所以可以索引(只能为正数)
# 如果没有数据,[0]引发IndexError异常,[0:1].get()引发DoesNotExist异常,shell执行的时候返回空
BookInfo.books2.all().filter(bcommet=0)[0:3]
# 查询集的缓存
# 情况一:这构成了两个查询集,无法重用缓存,每次查询都会与数据库进行一次交互,增加了数据库的负载
print([e.title for e in BookInfo.books1.all()])
print([e.title for e in BookInfo.books1.all()])
# 情况二:两次循环使用同一个查询集,第二次使用缓存中的数据
querylist=BookInfo.books1.all()
print([e.title for e in querylist])
print([e.title for e in querylist])
# 比较运算符
# exact:表示判等,大小写敏感;如果没有写“ 比较运算符”,表示判等
# contains:是否包含,大小写敏感
BookInfo.books1.filter(btitle__contains='天') # 标题包含天的书名
# startswith、endswith:以value开头或结尾,大小写敏感
BookInfo.books1.filter(btitle__startswith='天')
# isnull、isnotnull:是否为null
BookInfo.books1.filter(btitle__isnull=False)
# 在前面加个i表示不区分大小写,如iexact、icontains、istarswith、iendswith
# in:是否包含在范围内
BookInfo.books1.filter(id__in=[1,2,3])
# gt、gte、lt、lte:大于、大于等于、小于、小于等于
BookInfo.books1.filter(bpub_date__gt=('2019-1-1')) # 图书发布时间大于2019-1-1的书籍
# year、month、day、week_day、hour、minute、second:对日期间类型的属性进行运算
BookInfo.books1.filter(bpub_date__year=1990) # 发布时间为1990年的书籍
BookInfo.books1.filter(bpub_date__gt=(datetime(1985,1,1))) # 发布时间大于1985-1-1的书籍
# 跨关联关系的查询(书籍和英雄已通过hbook_id外键关联)
BookInfo.books1.filter(heroinfo__hcontent__contains='八')# 查询英雄表中hcontent包含八的书籍
# 聚合:使用aggregate()函数返回聚合函数的值
# 函数:Avg,Count,Max,Min,Sum
list= BookInfo.books1.filter(bpub_date__gt='1980-1-1')
# 筛选出list中最大的日期
from django.db.models import Max
maxDate = list.aggregate(Max('bpub_date'))
# F对象使用:
# 筛选出阅读量大于评论数的数据
from django.db.models import F
BookInfo.books1.filter(bread__gt=F('bcommet'))
# django支持对F()对象使用算数运算
BookInfo.books1.filter(bread__gte=F('bcommet') * 2)
# F()对象中还可以写作“模型类__列名”进行关联查询
# 筛选英雄中isDelete的值与其所属的书籍中的isDelete相等的书籍
BookInfo.books1.filter(isDelete=F('heroinfo__isDelete'))
# 对于date/time字段,可与timedelta()进行运算
from datetime import timedelta
# 筛选出发布日期为小于发布日期第二天的书籍
BookInfo.books1.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))
# Q对象使用:
from django.db.models import Q
# Q对象可以使用&(and)、|(or)操作符组合起来,当操作符应用在两个Q对象时,会产生一个新的Q对象
# 筛选出id小于4或标题包含天的书籍
BookInfo.books1.filter(Q(pk__lt=4)|Q(btitle__contains='天'))
# 筛选出id小于4并且书标题包含天的书籍
BookInfo.books1.filter(pk__lt=4,btitle__contains='天')
BookInfo.books1.filter(pk__lt=4).filter(btitle__contains='天')
# 使用~(not)操作符在Q对象前表示取反
# 查询id大于等于6的书籍
BookInfo.books1.filter(~Q(pk__lt=6))
十二:HttpResponse对象
属性:
- content:表示返回的内容,字符串类型
- charset:表示response采用的编码字符集,字符串类型
- status_code:响应的HTTP响应状态码
- content-type:指定输出的MIME类型
方法:
- init :使用页内容实例化HttpResponse对象
- write(content):以文件的方式写
- flush():以文件的方式输出缓存区
- set_cookie(key, value='', max_age=None, expires=None):设置Cookie
- key、value都是字符串类型
- max_age是一个整数,表示在指定秒数后过期
- expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期,注意datetime和timedelta值只有在使用PickleSerializer时才可序列化
- max_age与expires二选一
- 如果不指定过期时间,则两个星期后过期
- delete_cookie(key):删除指定的key的Cookie,如果key不存在则什么也不发生
在views.py中:
from django.shortcuts import HttpResponse
# cookie练习
def cookieTest(request):
response = HttpResponse()
cookie = request.COOKIES
# 先设置cookie,cookie显示为:t1=abc
response.set_cookie('t2','vbbbb')
# 然后判断是否存在,如果存在则显示在页面中
if 't1' in cookie:
response.write(cookie['t1']+'\n')
if 't2' in cookie:
response.write(cookie['t2'])
return response
在urls.py中:
from django.urls import re_path
urlpatterns = [
re_path(r'^cookieTest/$',views.cookieTest),
]
输入:http://127.0.0.1:8000/cookieTest/执行:
谷歌浏览器重F12查看:
重定向:
在views.py中:
# from django.shortcuts import HttpResponseRedirect
from django.shortcuts import redirect
# 重定向
def redTest1(request):
# 两个方法都可以
# return HttpResponseRedirect('/redTest2/')
return redirect('/redTest2/')
def redTest2(request):
return HttpResponse('转向来的页面!')
在urls.py中:
from django.urls import re_path
from booktest import views
urlpatterns = [
re_path(r'^redTest1/$',views.redTest1),
re_path(r'^redTest2/$',views.redTest2),
]
在浏览器输入:http://127.0.0.1:8000/redTest1/,自动跳转到redTest2页面,显示“转向来的页面!”这句话,同时url地址变为
http://127.0.0.1:8000/redTest2/
十三、session练习
使用session:
会话过期时间 :
- 启用会话后,每个HttpRequest对象将具有一个session属性,它是一个类字典对象
- get(key, default=None):根据键获取会话的值
- clear():清除所有会话
- flush():删除当前的会话数据并删除会话的Cookie
- del request.session['member_id']:删除会话
- set_expiry(value):设置会话的超时时间
- 如果没有指定,则两个星期后过期
- 如果value是一个整数,会话将在values秒没有活动后过期
- 若果value是一个imedelta对象,会话将在当前时间加上这个指定的日期/时间过期
- 如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期
- 如果value为None,那么会话永不过期
在views.py中:
from django.shortcuts import render,redirect
# session练习
def index(request):
uname = request.session.get('myname','未登录')
# 判断登录状态,默认未登录
state = False
# 有session情况,登录状态改为True
if 'myname' in request.session:
# session值为空的情况,删掉
if request.session['myname'] == '':
del request.session['myname']
state = True
context = {
'uname':uname,
'state':state,
}
return render(request,'index.html',context)
# 登录界面
def login(request):
return render(request,'login.html')
# 存储session
def login_handle(request):
# session是一个类字典对象,key值这里取名为'myname',value值为POST方式提交的值
request.session['myname'] = request.POST['uname']
# request.session.set_expiry(10)
# request.session.set_expiry(timedelta(days=5))
# 浏览器关闭时过期
request.session.set_expiry(0)
# request.session.set_expiry(None)
return redirect('/index/')
def login_out(request):
if 'myname' in request.session:
del request.session['myname']
return redirect('/index/')
在urls.py中:
from django.urls import path,re_path
from booktest import views
urlpatterns = [
re_path(r'^index/$',views.index),
re_path(r'^login/$',views.login),
re_path(r'^login_out/$',views.login_out),
re_path(r'^login_handle/$',views.login_handle),
]
templates文件夹中:
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index主页</title>
</head>
<body>
<h2>index主页</h2>
{% if uname == '' %}
登录名不能为空,请重新登录!
{% else %}
{% if state == True %}
已成功登录。
{% else %}
未登录,请您登录!
{% endif %}
{% endif %}
<hr >
{% if uname == '' %}
<a href="/login">点我登录</a><br >
{% else %}
{% if state == True %}
欢迎您:{{uname}}<br ><br >
<a href="/login_out">退出</a>
{% else %}
<a href="/login">点我登录</a><br >
{% endif %}
{% endif %}
</body>
</html>
login.html中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login页面</title>
</head>
<body>
<h2>login页面</h2>
<br >
<form method="post" action="/login_handle/">
<input type="text" name="uname">
<input type="submit" value="登录">
{% csrf_token %}
</form>
</body>
</html>
效果如下: