django
2017-10-27 14:16:04 193 举报Referer请求头
在Django社区上会经常看到django.newforms这个词语。当人们讨论django.newforms,其实就是我们本章里面介绍的django.forms。
改名其实有历史原因的。 当Django一次向公众发行时,它有一个复杂难懂的表单系统:django.forms。后来它被完全重写了,新的版本改叫作:django.newforms,这样人们还可以通过名称,使用旧版本。 当Django 1.0发布时,旧版本django.forms就不再使用了,而django.newforms也终于可以名正言顺的叫做:django.forms。
from
django
import
forms
class
ContactForm(forms.Form):
subject
=
forms.CharField()
email
=
forms.EmailField(required
=
False
)
message
=
forms.CharField()
>>>
print
f.as_ul()
<li><label
for
=
"id_subject"
>Subject:<
/
label> <
input
type
=
"text"
name
=
"subject"
id
=
"id_subject"
/
><
/
li>
<li><label
for
=
"id_email"
>Email:<
/
label> <
input
type
=
"text"
name
=
"email"
id
=
"id_email"
/
><
/
li>
<li><label
for
=
"id_message"
>Message:<
/
label> <
input
type
=
"text"
name
=
"message"
id
=
"id_message"
/
><
/
li>
>>>
print
f.as_p()
<p><label
for
=
"id_subject"
>Subject:<
/
label> <
input
type
=
"text"
name
=
"subject"
id
=
"id_subject"
/
><
/
p>
<p><label
for
=
"id_email"
>Email:<
/
label> <
input
type
=
"text"
name
=
"email"
id
=
"id_email"
/
><
/
p>
<p><label
for
=
"id_message"
>Message:<
/
label> <
input
type
=
"text"
name
=
"message"
id
=
"id_message"
/
><
/
p>
>>>
print
f[
'subject'
]
<
input
type
=
"text"
name
=
"subject"
id
=
"id_subject"
/
>
>>>
print
f[
'message'
]
<
input
type
=
"text"
name
=
"message"
id
=
"id_message"
/
>
f
=
ContactForm({
'subject'
:
'Hello'
,
'email'
:
'adrian@example.com'
,
'message'
:
'Nice site!'
}
>>> f
=
ContactForm({
'subject'
:
'Hello'
,
'message'
:
'Nice site!'
})
>>> f.is_valid()
True
>>> f
=
ContactForm({
'subject'
:
'Hello'
})
>>> f.is_valid()
False
>>> f
=
ContactForm({
'subject'
:
'Hello'
,
'message'
: ''})
>>> f.is_valid()
False
>>> f
=
ContactForm({
'subject'
:
'Hello'
,
'message'
: ''})
>>> f[
'message'
].errors
[u
'This field is required.'
]
>>> f[
'subject'
].errors
[]
>>> f[
'email'
].errors
[]
>>> f
=
ContactForm({
'subject'
:
'Hello'
,
'message'
: ''})
>>> f.errors
{
'message'
: [u
'This field is required.'
]}
>>> f
=
ContactForm({subject': Hello, email: adrian@example.com, message: Nice site!})
>>> f.is_valid()
True
>>> f.cleaned_data
{message': uNice site!, email: uadrian@example.com, subject: uHello}
name = models.CharField(max_length=64)
name = forms.CharField(validators=[validate_name],label='姓名',error_messages={'required':'必填'})
email=forms.EmailField(error_messages={'required':'默认报错方式','invalid':"邮箱格式错误"})
email=forms.EmailField(error_messages={'required':'默认报错','invalid':"邮箱格式错误"},
widget=forms.EmailInput(
attrs={
"class": "form-control email", "placeholder": "email","id":"exampleInputemal1"
}))
def clean(self):
if self.cleaned_data.get("password") is not None:
if self.cleaned_data.get("password")==self.cleaned_data.get("reqeat_password"):
return self.cleaned_data
else:
raise ValidationError("抛出两次密码不一致错误")
else:
return self.cleaned_data
def clean_password(self):
if len(self.cleaned_data.get("password"))>8:
return self.cleaned_data.get("password")
else:
raise ValidationError("密码长度不到8位")
if obj.is_valid():
obj.save() # 创建数据
修改表数据是,记得把instance
信息也传进去,不然是新建数据,而不是对某行数据进行修改。
编辑用户信息,新url方式保留默认数据
is_valid
是在BaseForm中定义的,所以ModelForm也能和Form一样使用各种钩子 def
index(request):
models.HostRelation.objects.create(
user
=
models.UserMap.objects.get(
id
=
1
),
host
=
models.HostInfo.objects.get(
id
=
1
)
)
return
HttpResponse(
'OK'
)
class
UserType(models.Model):
caption
=
models.CharField(max_length
=
32
)
class
UserInfo(models.Model):
user_type
=
models.ForeignKey(
'UserType'
)
#这个user_type是一个对象,对象里面封装了ID和caption
username
=
models.CharField(max_length
=
32
)
age
=
models.IntegerField()
def
index(request):
ret
=
models.UserInfo.objects.
all
()
#咱们看下他执行的什么SQL语句
print
( ret.query)
'''
SELECT "app01_userinfo"."id", "app01_userinfo"."user_type_id", "app01_userinfo"."username", "app01_userinfo"."age" FROM "app01_userinfo"
'''
def
user_info(request):
ret
=
models.UserInfo.objects.
all
().select_related()
#咱们看下他执行的什么SQL语句
print
ret.query
SELECT
"app01_userinfo"
.
"id"
,
"app01_userinfo"
.
"user_type_id"
,
"app01_userinfo"
.
"username"
,
"app01_userinfo"
.
"age"
,
"app01_usertype"
.
"id"
,
"app01_usertype"
.
"caption"
FROM
"app01_userinfo"
INNER JOIN
"app01_usertype"
ON (
"app01_userinfo"
.
"user_type_id"
=
"app01_usertype"
.
"id"
)
第一步:
#生成一个搜索对象
search_q
=
Q()
#在生成两个搜索对象
search1
=
Q()
search2
=
Q()
第二步:
#标记search1中的搜索条件为 ‘ 或’ 查询
search1.connector
=
'OR'
#把搜索条件加入到search1中
search1.children.append((
'字段名'
,
'字段内容'
))
search1.children.append((
'字段名'
,
'字段内容'
))
search1.children.append((
'字段名'
,
'字段内容'
))
search1.children.append((
'字段名'
,
'字段内容'
))
#标记search2中的搜索条件为 ‘ 或’ 查询
search2.connector
=
'OR'
#把搜索条件加入到search2中
search2.children.append((
'字段名'
,
'字段内容'
))
search2.children.append((
'字段名'
,
'字段内容'
))
search2.children.append((
'字段名'
,
'字段内容'
))
search2.children.append((
'字段名'
,
'字段内容'
))
第三步:
#把多个搜索条件进行合并
search_q.add(search1,
'AND'
)
search_q.add(search2,
'AND'
)
第四步:
#执行搜索
models.HostInfo.objects.
filter
(search_q)
from django.db.models import Avg,Min,Sum,Max 从整个查询集生成统计值。比如,你想要计算所有在售书的平均价钱。Django的查询语法提供了一种方式描述所有 图书的集合。 >>> Book.objects.all().aggregate(Avg('price')) {'price__avg': 34.35} aggregate()子句的参数描述了我们想要计算的聚合值,在这个例子中,是Book模型中price字段的平均值 aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的 标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定 一个名称,可以向聚合子句提供它: >>> Book.objects.aggregate(average_price=Avg('price')) {'average_price': 34.35} 如果你也想知道所有图书价格的最大值和最小值,可以这样查询: >>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) {'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
# models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 # # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in # # models.Tb1.objects.filter(name__contains="ven") # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感 # # models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and # # startswith,istartswith, endswith, iendswith,
# ret3=models.Book.objects.filter(title='Python').values('id') # print(ret3)#[{'id': 1}] #正向查找(条件)之一对多 ret4=models.Book.objects.filter(title='Python').values('publisher__city') print(ret4) #[{'publisher__city': '北京'}] #正向查找(条件)之多对多 ret5=models.Book.objects.filter(title='Python').values('author__name') print(ret5) ret6=models.Book.objects.filter(author__name="alex").values('title') print(ret6) #注意 #正向查找的publisher__city或者author__name中的publisher,author是book表中绑定的字段 #一对多和多对多在这里用法没区别
#反向查找之一对多: ret8=models.Publisher.objects.filter(book__title='Python').values('name') print(ret8)#[{'name': '人大出版社'}] 注意,book__title中的book就是Publisher的关联表名 ret9=models.Publisher.objects.filter(book__title='Python').values('book__authors') print(ret9)#[{'book__authors': 1}, {'book__authors': 2}] #反向查找之多对多: ret10=models.Author.objects.filter(book__title='Python').values('name') print(ret10)#[{'name': 'alex'}, {'name': 'alvin'}] #注意 #正向查找的book__title中的book是表名Book #一对多和多对多在这里用法没区别
<1> 第二种方式修改不能用get的原因是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySet对象(filter里面的条件可能有多个条件符合,比如name='alvin',可能有两个name='alvin'的行数据)。
<2>在“插入和更新数据”小节中,我们有提到模型的save()方法,这个方法会更新一行里的所有列。 而某些情况下,我们只需要更新行里的某几列。
#---------------- update方法直接设定对应属性---------------- models.Book.objects.filter(id=3).update(title="PHP") ##sql: ##UPDATE "app01_book" SET "title" = 'PHP' WHERE "app01_book"."id" = 3; args=('PHP', 3)
#--------------- save方法会将所有属性重新设定一遍,效率低----------- obj=models.Book.objects.filter(id=3)[0] obj.title="Python" obj.save() # SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", # "app01_book"."color", "app01_book"."page_num", # "app01_book"."publisher_id" FROM "app01_book" WHERE "app01_book"."id" = 3 LIMIT 1; # # UPDATE "app01_book" SET "title" = 'Python', "price" = 3333, "color" = 'red', "page_num" = 556, # "publisher_id" = 1 WHERE "app01_book"."id" = 3;
>>> Book.objects.filter(id=1).delete() (3, {'app01.Book_authors': 2, 'app01.Book': 1})
Django 的 Model 驱动对数据库层面上的实现细节关注的非常少,开发者定义模型的过程非常接近声明式而非过程式,对于新项目来说,可能是这个原因让 Django Model 比 SQLAlchemy 讨人喜欢。
传统的 SQLAlchemy 的使用方法是不入侵模型,在单独的地方定义表结构、映射规则,然后用 SQLAlchemy 驱动注入到模型类里去,这种方法可以完全避免模型与数据库的耦合,但是定义繁琐,要求开发者完全明白 engine、metadata、table、column、mapper 等概念,如果没有读过《企业应用架构模式》一类书籍会被弄得很乱。
现在 SQLAlchemy 提供了 declarative 的方式,和 Django Model 很像,但是和声明式模型还是有一定的距离,好在对于灵活性几乎没损失。但是我对比了一下 Django Model 和 SQLAlchemy declarative,发现 Django Model 还是更简洁一些。例如对于类关联,Django 只要直接声明外键,就自动产生关联对象,而 SQLAlcyhemy 要定义外键、relationship 对象,如果有多个外键还要自己指定 join 规则…… 总之灵活性是好东西,但是不是什么情况下都讨人喜欢的。
我本来想说这个是 ActiveRecord style 和 Data Mapper style 区别导致的,但是细想了一下,Django Model 并不是简单的 ActiveRecord,其对于复杂关联甚至继承的映射都有很好的适应性,应该和 SQLAlchemy 的 declarative 是同类型的,是对 Data Mapper 的 Active Record style 包装。sqlalchemy使用上有两个层次,1是使用sql expression, 说白可以让你用python写sql, 2是它的orm, orm是使用session的,自行管理session生存期,自行在多个过程中传递session,自行管理事务。写法上是通常的transaction script(java常说的贫血的domain model)模式。实际编码通常1和2混合编程。
django通过中间件部分隐藏了连接/事务管理的概念,写法上也比较简单,接近java常说的充血的domain model. 内容上也没有sqlalchemy 的sql expression层次。 易用性就体现出来了。
因为在Django世界中它的ORM就是事实标准。Django最重要的特色是什么?从ORM快速生成后台管理界面!另外还有ModelForm、数据迁移(migration)等等从Django ORM延伸出去的概念……如果你选用了SQLAlchemy,那么这一切都没有了,你必须自行搭建,或者选用第三方库。话说,没有了内置ORM、没有了内置后台管理界面、没有了内置ModelForm、没有了数据迁移的Django,还是Django吗?不如直接用其它更轻量或更松散的框架好了!
另外,在Django之外单独使用Django ORM是不靠谱的。如果是其它环境,使用SQLAlchemy就好了。from
django.core
import
serializers
ret
=
models.BookType.objects.
all
()
data
=
serializers.serialize(
"json"
, ret)
import
json
#ret = models.BookType.objects.all().values('caption')
ret
=
models.BookType.objects.
all
().values_list(
'caption'
)
ret
=
list
(ret)
result
=
json.dumps(ret)
import
json
from
datetime
import
date
from
datetime
import
datetime
class
JsonCustomEncoder(json.JSONEncoder):
def
default(
self
, field):
if
isinstance
(field, datetime):
return
o.strftime(
'%Y-%m-%d %H:%M:%S'
)
elif
isinstance
(field, date):
return
o.strftime(
'%Y-%m-%d'
)
else
:
return
json.JSONEncoder.default(
self
, field)
Model signals
pre_init
# django的modal执行其构造方法前,自动触发
post_init
# django的modal执行其构造方法后,自动触发
pre_save
# django的modal对象保存前,自动触发
post_save
# django的modal对象保存后,自动触发
pre_delete
# django的modal对象删除前,自动触发
post_delete
# django的modal对象删除后,自动触发
m2m_changed
# django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
class_prepared
# 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
pre_migrate
# 执行migrate命令前,自动触发
post_migrate
# 执行migrate命令后,自动触发
Request
/
response signals
request_started
# 请求到来前,自动触发
request_finished
# 请求结束后,自动触发
got_request_exception
# 请求异常后,自动触发
Test signals
setting_changed
# 使用test测试修改配置文件时,自动触发
template_rendered
# 使用test测试渲染模板时,自动触发
Database Wrappers
connection_created
# 创建数据库连接时,自动触发
from django.core.signals import request_finished from django.dispatch import receiver @receiver(request_finished) def my_callback(sender, **kwargs): print("Request finished!")
import django.dispatch pizza_done = django.dispatch.Signal(providing_args = [ "toppings" , "size" ])
|
def
callback(sender,
*
*
kwargs):
print
(
"callback"
)
print
(sender,kwargs)
pizza_done.connect(callback)
from
路径
import
pizza_done
pizza_done.send(sender
=
'seven'
,toppings
=
123
, size
=
456
)