day17-django的ORM与其他
老师手札
Django流程:
1 创建Django项目 : django-admin startproject projectname
2 创建应用: : python manage.py startapp appname
3 在控制器(urls.py)创建 url 与 视图函数的映射关系(一一对应)
4 创建视图函数,完成逻辑代码
5 从数据库取出集合对象
5 把数据库变量嵌入到模板进行渲染(render方法)
6 将渲染后的html页面返回给客户端
URL:协议+域名+端口+路径 eg:http://www.cnblogs.com/yuanchenqi/articles/6811632.html?a=1
协议:http
域名:www.cnblogs.com
端口:80
路径:yuanchenqi/articles/6811632.html
数据:a=1
URL配置中的正则表达式匹配的是一个url的路径部分
TEMPALTE(模板):HTML代码+逻辑控制代码
逻辑控制语法: {{}} 渲染变量 filter : {{var|方法:参数}}
{% %} 渲染标签
{% if %}
{% for %}
{% url %}
{% url %}
自定义filter和simpletag:
(1)在app中创建templatetags模块(必须的)
(2)创建任意 .py 文件,如:my_tags.py
from django import template
register = template.Library()
@register.filter
def filter_multi(v1,v2):
return v1 * v2
(3)创建任意 .py 文件,如:my_tags.py
在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py :{% load my_tags %}
(4)使用simple_tag和filter:
{% load xxx %} #首行
# num=12
{{ num|filter_multi:2 }} #24
总结:
filter: 只能接受一个参数,但是可以用if等语句
simpletag: 能接受多个参数,但是不可以用if等语句
ORM:
表之表之间的关系:
一对多 外键字段一定是在字表(一对多的多的表)中 Foreign KEY
多对多 在第三张表实现,通过两个Foreign KEY
一对一 在外键字段的基础上增加唯一约束。
表.object.filter():得到的是一个集合对象 比如 [obj1,obj2]
表.object.get(): 得到的是一个model对象
一对多的添加记录:
# 方法1:
# Book.objects.create(id=1,title="python",publication_date="2017-03-04",price=88.8,publisher_id=1)
#方法2
p1=Publisher.objects.get(name="人大出版社")
Book.objects.create(id=2,title="python",publication_date="2017-05-04",price=98.8,publisher=p1)
多对多的添加
ManyToMany只有一种添加方式:
book.authors.add(*[author1,author2])
book.authors.remove(*[author1,author2])
注意:理解 book_obj.publisher
book_obj.authors
自建第三张表
class Book2Author(models.Model):
author=models.ForeignKey("Author")
Book= models.ForeignKey("Book")
# 那么就还有一种方式:
author_obj=models.Author.objects.filter(id=2)[0]
book_obj =models.Book.objects.filter(id=3)[0]
s=models.Book2Author.objects.create(author_id=1,Book_id=2)
s.save()
s=models.Book2Author(author=author_obj,Book_id=1)
s.save()
修改操作update和save的区别:
update只是set指定的字段 save set所有字段,所以update 效率更高
查询:
今日概要:
1、name别名
2、模版的深度查询
3、模版语言之filter
4、自定义过滤器,filter和simpletag的区别
5、orm进阶
扫盲:url的组成
URL:协议+域名+端口+路径 eg:http:
//www
.cnblogs.com
/drango/articles/6811632
.html?a=1
协议:http
域名:www.cnblogs.com
端口:80
路径:drango
/articles/6811632
.html
数据:a=1
URL配置中的正则表达式匹配的是一个url的路径部分
1、url之name别名
设置别名的用途:可以随意在urls.py里更改传入url,不会影响模版渲染
用法: {% url 'REG' %}
'''
urlpatterns = [
url(r'^index',views.index,name='INDEX'),
]
###################
def index(req):
if req.method=='POST':
username=req.POST.get('username')
password=req.POST.get('password')
if username=='alex' and password=='123':
return HttpResponse("登陆成功")
return render(req,'index.html')
#####################
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# <form action="/index/" method="post">#}
<form action="{% url 'INDEX' %}" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
<input type="submit" value="submit">
</form>
</body>
</html>
#######################
'''
例子
cvf
url.conf里的配置:
url(r
'home/'
, views.Home.as_view()),
views里的配置:
'''先到dispatch'''
class
Home(View):
def
dispatch(
self
,request,
*
args,
*
*
kwargs):
'''此处类似于python的装饰器'''
'''调用父类中都dispath'''
print
(
'before'
)
result
=
super
(Home,
self
).dispatch(request,
*
args,
*
*
kwargs)
print
(
'after'
)
return
result
def
get(
self
,request):
print
(request.method)
return
render(request,
'home.html'
)
def
post(
self
,request):
print
(request.method)
return
render(request,
'home.html'
)
2、模版之深度查询
HTML代码+逻辑控制代码
字典通过模版语言进行取值:
#key value items
{% for k,item in dict.items %}
<
li
>{{ k }}-{{ item }}</
li
>
{% endfor %}
变量过滤之filter
# 1 add : 给变量加上相应的值
#
# 2 addslashes : 给变量中的引号前加上斜线
#
# 3 capfirst : 首字母大写
#
# 4 cut : 从字符串中移除指定的字符
#
# 5 date : 格式化日期字符串
#
# 6 default : 如果值是False,就替换成设置的默认值,否则就是用本来的值
#
# 7 default_if_none: 如果值是None,就替换成设置的默认值,否则就使用本来的值
#实例:
#value1="aBcDe"
{{ value1|upper }}<
br
>
#value2=5
{{ value2|add:3 }}<
br
>
#value3='he llo wo r ld'
{{ value3|cut:' ' }}<
br
>
#import datetime
#value4=datetime.datetime.now()
{{ value4|date:'Y-m-d' }}<
br
>
#value5=[]
{{ value5|default:'空的' }}<
br
>
#value6='<
a
href="#">跳转</
a
>'
{{ value6 }}
{% autoescape off %}
{{ value6 }}
{% endautoescape %}
{{ value6|safe }}<
br
>
{{ value6|striptags }}
#value7='1234'
{{ value7|filesizeformat }}<
br
>
{{ value7|first }}<
br
>
{{ value7|length }}<
br
>
{{ value7|slice:":-1" }}<
br
>
#value8='http://www.baidu.com/?a=1&b=3'
{{ value8|urlencode }}<
br
>
value9='hello I am yuan'
{% with %}
用更简单的变量名替代复杂的变量名
{% verbatim %}
禁止render
{% verbatim %}
{{ hello }}
{% endverbatim %}
{% load %}
加载static
模版继承
1、后台css样例:
<style>
.header {
position: fixed; #顶部用fixed
top:0;
left: 0;
background-color: aqua;
width: 100%;
height: 48px;
}
.left{
position: absolute;
top:48px;
left: 0;
bottom: 0;
width: 200px;
background-color: lightcoral;
}
.right{
position: absolute; #绝对定位
top:48px;
left: 200px;
right: 0;
bottom: 0;
overflow: scroll; {# 这是溢出情况会出滚轮 #}
}
.left a{
background-color: green;
width: 70px;
padding: 2px;
}
</style>
样例
2、{% extend 'html' %} 继承
模版:
<
div
class="header"></
div
>
<
div
class="box">
<
div
class="left">
<
a
href="/app01/add/">添加</
a
>
</
div
>
<
div
class="right">
{% block content %} #此处为继承自定义处,子模版如果不填任何值,会继承父模版的block内容,子模版修改block里内容后,就会覆盖父模版的block处
<
p
>yyyyyy</
p
>
{% endblock %}
</
div
>
</
div
>
子模版内容:
{% extends 'register.html' %}
{% block back %}
{% load Mytag %}
<
p
>
{% for person in person_list %}
{{ person.name }}
{% endfor %}
</
p
>
{% endblock %}
{% include 'html'%} ,include(模版包含)方法:
父模版:
<
div
><
a
href="#">测试</
a
></
div
>
子模版:
{% include 'tag.html' %}
{% include 'tag.html' %}
{% include 'tag.html' %}
{% include 'tag.html' %}
以下是其工作方式:
在加载 current_datetime.html 模板时,模板引擎发现了 {% extends %} 标签, 注意到该模板是一个子模板。 模板引擎立即装载其父模板,即本例中的 base.html 。此时,模板引擎注意到 base.html 中的三个 {% block %} 标签,并用子模板的内容替换这些 block 。因此,引擎将会使用我们在 { block title %} 中定义的标题,对 {% block content %} 也是如此。 所以,网页标题一块将由{% block title %}替换,同样地,网页的内容一块将由 {% block content %}替换。
注意由于子模板并没有定义 footer 块,模板系统将使用在父模板中定义的值。 父模板 {% block %} 标签中的内容总是被当作一条退路。继承并不会影响到模板的上下文。 换句话说,任何处在继承树上的模板都可以访问到你传到模板中的每一个模板变量。你可以根据需要使用任意多的继承次数。 使用继承的一种常见方式是下面的三层法:
<1> 创建 base.html 模板,在其中定义站点的主要外观感受。 这些都是不常修改甚至从不修改的部分。
<2> 为网站的每个区域创建 base_SECTION.html 模板(例如, base_photos.html 和 base_forum.html )。这些模板对base.html 进行拓展,
并包含区域特定的风格与设计。
<3> 为每种类型的页面创建独立的模板,例如论坛页面或者图片库。 这些模板拓展相应的区域模板。
这个方法可最大限度地重用代码,并使得向公共区域(如区域级的导航)添加内容成为一件轻松的工作。
以下是使用模板继承的一些诀窍:
<1>如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作用。
<2>一般来说,基础模板中的 {% block %} 标签越多越好。 记住,子模板不必定义父模板中所有的代码块,因此
你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。 俗话说,钩子越
多越好。
<3>如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。
如果你需要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出父模
板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。
<4>不允许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是因为block 标签的工作方式是双向的。
也就是说,block 标签不仅挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容。如果模板中出现了两个
相同名称的 {% block %} 标签,父模板将无从得知要使用哪个块的内容。
加载标签库:自定义filter和simple_tag
a、在app中创建templatetags模块(必须的)
b、创建任意 .py 文件,如:my_tags.py
from django import template
from django.utils.safestring import mark_safe
register = template.Library() #register的名字是固定的,不可改变
@register.filter
def filter_multi(v1,v2):
return v1 * v2
@register.simple_tag
def simple_tag_multi(v1,v2):
return v1 * v2
@register.simple_tag
def my_input(id,arg):
result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
return mark_safe(result)
c、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py :{% load my_tags %}
d、使用simple_tag和filter(如何调用)
-------------------------------.html
{% load xxx %} #首行
# num=12
{{ num|filter_multi:2 }} #24
{{ num|filter_multi:"[22,333,4444]" }}
{% simple_tag_multi 2 5 %} 参数不限,但不能放在if for语句中
{% simple_tag_multi num 5 %}
e、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
注意:
filter可以用在if等语句后,simple_tag不可以
{
%
if
num|filter_multi:
30
>
100
%
}
{{ num|filter_multi:
30
}}
{
%
endif
%
}
总结:
(
1
)在app中创建templatetags模块(必须的)
(
2
)创建任意 .py 文件,如:my_tags.py
from
django
import
template
register
=
template.Library()
@register
.
filter
def
filter_multi(v1,v2):
return
v1
*
v2
3
)创建任意 .py 文件,如:my_tags.py
在使用自定义simple_tag和
filter
的html文件中导入之前创建的 my_tags.py :{
%
load my_tags
%
}
4
)使用simple_tag和
filter
:
{
%
load xxx
%
}
#首行
# num=12
{{ num|filter_multi:
2
}}
#24
filter
: 只能接受一个参数,但是可以用
if
等语句
simpletag: 能接受多个参数,但是不可以用
if
等语句
3、数据库orm
django连接mysql的配置:
DATABASES = {
'default'
: {
'ENGINE'
:
'django.db.backends.mysql'
,
'NAME'
:
'books'
,
#你的数据库名称
'USER'
:
'root'
,
#你的数据库用户名
'PASSWORD'
:
''
,
#你的数据库密码
'HOST'
:
''
,
#你的数据库主机,留空默认为localhost
'PORT'
:
'3306'
,
#你的数据库端口
}
}
在项目的__init__.py里添加
import
pymysql
pymysql.install_as_MySQLdb()
ORM表和模型
表(模型)的创建:
实例:我们来假定下面这些概念,字段和关系
作者模型:一个作者有姓名。
作者详细模型:把作者的详情放到详情表,包含性别,email地址和出生日期,作者详情模型和作者模型之间是一对一的关系(one-to-one)(类似于每个人和他的身份证之间的关系),在大多数情况下我们没有必要将他们拆分成两张表,这里只是引出一对一的概念。
出版商模型:出版商有名称,地址,所在城市,省,国家和网站。
书籍模型:书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many),一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many),也被称作外键。
from
django.db
import
models<br>
class
Publisher(models.Model):
name
=
models.CharField(max_length
=
30
, verbose_name
=
"名称"
)
address
=
models.CharField(
"地址"
, max_length
=
50
)
city
=
models.CharField(
'城市'
,max_length
=
60
)
state_province
=
models.CharField(max_length
=
30
)
country
=
models.CharField(max_length
=
50
)
website
=
models.URLField()
class
Meta:
verbose_name
=
'出版商'
verbose_name_plural
=
verbose_name
def
__str__(
self
):
return
self
.name
class
Author(models.Model):
name
=
models.CharField(max_length
=
30
)
def
__str__(
self
):
return
self
.name
class
AuthorDetail(models.Model):
sex
=
models.BooleanField(max_length
=
1
, choices
=
((
0
,
'男'
),(
1
,
'女'
),))
email
=
models.EmailField()
address
=
models.CharField(max_length
=
50
)
birthday
=
models.DateField()
author
=
models.OneToOneField(Author)
class
Book(models.Model):
title
=
models.CharField(max_length
=
100
)
authors
=
models.ManyToManyField(Author)
publisher
=
models.ForeignKey(Publisher)
publication_date
=
models.DateField()
price
=
models.DecimalField(max_digits
=
5
,decimal_places
=
2
,default
=
10
)
def
__str__(
self
):
return
self
.title
分析代码:
<1> 每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。
<2> 每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。大家可以留意下其它的类型都和数据库里的什么字段对应。
<3> 模型之间的三种关系:一对一,一对多,多对多。
一对一:实质就是在主外键(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性;
一对多:就是主外键关系;(foreign key)
多对多:(ManyToManyField) 自动创建第三张表(当然我们也可以自己创建第三张表:两个foreign key)
如果创建一对多,多对多关系
#一对多(ForeignKey):
#方式一: 由于绑定一对多的字段,比如publish,存到数据库中的字段名叫publish_id,所以我们可以直接给这个
# 字段设定对应值:
Book.objects.create(title
=
'php'
,
publisher_id
=
2
,
#这里的2是指为该book对象绑定了Publisher表中id=2的行对象
publication_date
=
'2017-7-7'
,
price
=
99
)
#方式二:
# <1> 先获取要绑定的Publisher对象:
pub_obj
=
Publisher(name
=
'河大出版社'
,address
=
'保定'
,city
=
'保定'
,
state_province
=
'河北'
,country
=
'China'
,website
=
'http://www.hbu.com'
)
OR pub_obj
=
Publisher.objects.get(
id
=
1
)
# <2>将 publisher_id=2 改为 publisher=pub_obj
#多对多(ManyToManyField()):
author1
=
Author.objects.get(
id
=
1
)
author2
=
Author.objects.
filter
(name
=
'alvin'
)[
0
]
book
=
Book.objects.get(
id
=
1
)
book.authors.add(author1,author2)
#等同于:
book.authors.add(
*
[author1,author2])
book.authors.remove(
*
[author1,author2])
#-------------------
book
=
models.Book.objects.
filter
(id__gt
=
1
)
authors
=
models.Author.objects.
filter
(
id
=
1
)[
0
]
authors.book_set.add(
*
book)
authors.book_set.remove(
*
book)
#-------------------
book.authors.add(
1
)
book.authors.remove(
1
)
authors.book_set.add(
1
)
authors.book_set.remove(
1
)
#注意: 如果第三张表是通过models.ManyToManyField()自动创建的,那么绑定关系只有上面一种方式
# 如果第三张表是自己创建的:
class
Book2Author(models.Model):
author
=
models.ForeignKey(
"Author"
)
Book
=
models.ForeignKey(
"Book"
)
# 那么就还有一种方式:
author_obj
=
models.Author.objects.
filter
(
id
=
2
)[
0
]
book_obj
=
models.Book.objects.
filter
(
id
=
3
)[
0
]
s
=
models.Book2Author.objects.create(author_id
=
1
,Book_id
=
2
)
s.save()
s
=
models.Book2Author(author
=
author_obj,Book_id
=
1
)
s.save()
ORM之查询api
# 查询相关API:
# <1>filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
# <2>all(): 查询所有结果
# <3>get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
#-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()--------
# <4>values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列
# <5>exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
# <6>order_by(*field): 对查询结果排序
# <7>reverse(): 对查询结果反向排序
# <8>distinct(): 从返回结果中剔除重复纪录
# <9>values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
# <10>count(): 返回数据库中匹配查询(QuerySet)的对象数量。
# <11>first(): 返回第一条记录
# <12>last(): 返回最后一条记录
# <13>exists(): 如果QuerySet包含数据,就返回True,否则返回False
ORM之总结:
表之表之间的关系:
一对多 外键字段一定是在字表(一对多的多的表)中 Foreign KEY
多对多 在第三张表实现,通过两个Foreign KEY
一对一 在外键字段的基础上增加唯一约束。
表.
object
.
filter
():得到的是一个集合对象 比如 [obj1,obj2]
表.
object
.get(): 得到的是一个model对象
一对多的添加记录:
# 方法1:通过publisher_id进行创建
Book.objects.create(
id
=
1
,title
=
"python"
,publication_date
=
"2017-03-04"
,price
=
88.8
,publisher_id
=
1
)
#方法2 通过集合对象进行创建
p1
=
Publisher.objects.get(name
=
"人大出版社"
)
Book.objects.create(
id
=
2
,title
=
"python"
,publication_date
=
"2017-05-04"
,price
=
98.8
,publisher
=
p1)
多对多的添加
ManyToMany只有一种添加方式:
book.authors.add(
*
[author1,author2])
book.authors.remove(
*
[author1,author2])
注意:理解 book_obj.publisher
book_obj.authors
自建第三张表
class
Book2Author(models.Model):
author
=
models.ForeignKey(
"Author"
)
Book
=
models.ForeignKey(
"Book"
)
# 那么就还有一种方式:
author_obj
=
models.Author.objects.
filter
(
id
=
2
)[
0
]
book_obj
=
models.Book.objects.
filter
(
id
=
3
)[
0
]
s
=
models.Book2Author.objects.create(author_id
=
1
,Book_id
=
2
)
s.save()
s
=
models.Book2Author(author
=
author_obj,Book_id
=
1
)
s.save()
修改操作update和save的区别:
update只是
set
指定的字段 save
set
所有字段,所以update 效率更高