社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库
ORM是“对象-关系-映射”的简称,主要任务是:
这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动;Django中的模型包含存储数据的字段和约束,对应着数据库中唯一的表
在虚拟环境中安装mysql包
# python2.7
pip install mysql-python
# python3.6
pip install pymysql
在mysql中创建数据库
create databases test2 charset=utf8
打开settings.py文件,修改DATABASES项
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test2',
'USER': '用户名',
'PASSWORD': '密码',
'HOST': '数据库服务器ip,本地可以使用localhost',
'PORT': '端口,默认为3306',
}
}
python manage.py inspectdb > booktest/models.py
1、在模型中定义属性,会生成表中的字段,django根据属性的类型确定以下信息:
2、django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
3、属性命名限制
`AutoField`:一个根据实际ID自动增长IntegerField,通常不指定
如果不指定,一个主键字段将自动添加到模型中
`BooleanField`:true/false 字段,此字段的默认表单控制是CheckboxInput
`NullBooleanField`:支持null、true、false三种值
`CharField(max_length=字符长度)`:字符串,默认的表单样式是 TextInput
`TextField`:大文本字段,一般超过4000使用,默认的表单控件是Textarea
`IntegerField`:整数
`DecimalField(max_digits=None, decimal_places=None)`:使用python的Decimal实例表示的十进制浮点数
`DecimalField.max_digits`:位数总数
`DecimalField.decimal_places`:小数点后的数字位数
`FloatField`:用Python的float实例来表示的浮点数
`DateField[auto_now=False, auto_now_add=False])`:使用Python的datetime.date实例表示的日期
# 参数DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false
# 参数DateField.auto_now_add:当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false
# 该字段默认对应的表单控件是一个TextInput. 在管理员站点添加了一个JavaScript写的日历控件,和一个“Today"的快捷按钮,包含了一个额外的invalid_date错误消息键
# auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果
`TimeField`:使用Python的datetime.time实例表示的时间,参数同DateField
`DateTimeField`:使用Python的datetime.datetime实例表示的日期和时间,参数同DateField
`FileField`:一个上传文件的字段
`ImageField`:继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image
通过字段选项,可以实现对字段的约束
在字段对象时通过关键字参数指定
`null`:如果为True,Django 将空值以NULL 存储到数据库中,默认值是 False
`blank`:如果为True,则该字段允许为空白,默认值是 False
对比:null是数据库范畴的概念,blank是表单验证证范畴的
`db_column`:字段的名称,如果未指定,则使用属性的名称
`db_index`:若值为 True, 则在表中会为此字段创建索引
`default`:默认值
`primary_key`:若为 True, 则该字段会成为模型的主键字段
`unique`:如果为 True, 这个字段在表中必须有唯一值
1、关系的类型包括
`ForeignKey`:一对多,将字段定义在多的端中
`ManyToManyField`:多对多,将字段定义在两端中
`OneToOneField`:一对一,将字段定义在任意一端中
2、可以维护递归的关联关系,使用’self’指定,详见“自关联”
3、用一访问多:对象.模型类小写_set
bookinfo.heroinfo_set
4、用一访问一:对象.模型类小写
heroinfo.bookinfo
5、访问id:对象.属性_id(mysql中的表属性名为:属性_id)
heroinfo.book_id
<app_name>_<model_name>
class BookInfo(models.Model):
...
class Meta():
ordering = ['id']
class BookInfo(models.Model):
...
class Meta():
ordering = ['-id']
排序会增加数据库的开销
创建test2项目,并创建booktest应用,使用mysql数据库
# 定义图书模型
class BookInfo(models.Model):
btitle = models.CharField(max_length=20)
bpub_date = models.DateTimeField()
bread = models.IntegerField(default=0)
bcommet = models.IntegerField(default=0)
isDelete = models.BooleanField(default=False)
# 英雄模型
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=100)
hbook = models.ForeignKey('BookInfo')
# 模型BookInfo的测试数据
insert into booktest_bookinfo(btitle,bpub_date,bread,bcommet,isDelete) values
('射雕英雄传','1980-5-1',12,34,0),
('天龙八部','1986-7-24',36,40,0),
('笑傲江湖','1995-12-24',20,80,0),
('雪山飞狐','1987-11-11',58,24,0)
# 模型HeroInfo的测试数据
insert into booktest_heroinfo(hname,hgender,hbook_id,hcontent,isDelete) values
('郭靖',1,1,'降龙十八掌',0),
('黄蓉',0,1,'打狗棍法',0),
('黄药师',1,1,'弹指神通',0),
('欧阳锋',1,1,'蛤蟆功',0),
('梅超风',0,1,'九阴白骨爪',0),
('乔峰',1,2,'降龙十八掌',0),
('段誉',1,2,'六脉神剑',0),
('虚竹',1,2,'天山六阳掌',0),
('王语嫣',0,2,'神仙姐姐',0),
('令狐冲',1,3,'独孤九剑',0),
('任盈盈',0,3,'弹琴',0),
('岳不群',1,3,'华山剑法',0),
('东方不败',0,3,'葵花宝典',0),
('胡斐',1,4,'胡家刀法',0),
('苗若兰',0,4,'黄衣',0),
('程灵素',0,4,'医术',0),
('袁紫衣',0,4,'六合拳',0)
class BookInfo(models.Model):
...
books = models.Manager()
class BookInfoManager(models.Manager):
def get_queryset(self):
return super(BookInfoManager, self).get_queryset().filter(isDelete=False)
class BookInfo(models.Model):
...
books = BookInfoManager()
当创建对象时,django不会对数据库进行读写操作
调用save()方法才与数据库交互,将对象保存到数据库中
使用关键字参数构造模型对象很麻烦,推荐使用下面的两种之式
说明: init 方法已经在基类models.Model中使用,在自定义模型中无法使用
方式一:在模型类中增加一个类方法
class BookInfo(models.Model):
...
@classmethod
def create(cls, title, pub_date):
book = cls(btitle=title, bpub_date=pub_date)
book.bread=0
book.bcommet=0
book.isDelete = False
return book
引入时间包:from datetime import *
调用:book=BookInfo.create("hello",datetime(1980,10,11));
保存:book.save()
方式二:在自定义管理器中添加一个方法
在管理器的方法中,可以通过self.model来得到它所属的模型类
class BookInfoManager(models.Manager):
def create_book(self, title, pub_date):
book = self.model()
book.btitle = title
book.bpub_date = pub_date
book.bread=0
book.bcommet=0
book.isDelete = False
return book
class BookInfo(models.Model):
...
books = BookInfoManager()
调用:book=BookInfo.books.create_book("abc",datetime(1980,1,1))
保存:book.save()
在方式二中,可以调用self.create()创建并保存对象,不需要再手动save()
class BookInfoManager(models.Manager):
def create_book(self, title, pub_date):
book = self.create(btitle = title,bpub_date = pub_date,bread=0,bcommet=0,isDelete = False)
return book
class BookInfo(models.Model):
...
books = BookInfoManager()
调用:book=Book.books.create_book("abc",datetime(1980,1,1))
查看:book.pk
all()
filter()
exclude()
order_by()
values():一个对象构成一个字典,然后构成一个列表返回
filter(键1=值1,键2=值2)
等价于
filter(键1=值1).filter(键2=值2)
`get()`:返回单个满足条件的对象
如果未找到会引发"模型类.DoesNotExist"异常
如果多条被返回,会引发"模型类.MultipleObjectsReturned"异常
`count()`:返回当前查询的总条数
`first()`:返回第一个对象
`last()`:返回最后一个对象
exists():判断查询集中是否有数据,如果有则返回True
print([e.title for e in Entry.objects.all()])
print([e.title for e in Entry.objects.all()])
情况二:两次循环使用同一个查询集,第二次使用缓存中的数据
querylist=Entry.objects.all()#这句话并没有取到数据
print([e.title for e in querylist])
print([e.title for e in querylist])
filter(title__contains="%")=>where title like '%%%',表示查找标题中包含%的
filter(isDelete=False)
exclude(btitle__contains='传')
exclude(btitle__endswith='传')
filter(btitle__isnull=False)
filter(pk__in=[1, 2, 3, 4, 5])
gt、gte、lt、lte:大于、大于等于、小于、小于等于
filter(id__gt=3)
filter(bpub_date__year=1980)
filter(bpub_date__gt=date(1980, 12, 31))
filter(heroinfo_ _hcontent_ _contains='八')
filter(pk__lt=6)
from django.db.models import Max
maxDate = list.aggregate(Max('bpub_date'))
count = list.count()
# bread和bcomment比较
list.filter(bread__gte=F('bcommet'))
list.filter(bread__gte=F('bcommet') * 2)
list.filter(isDelete=F('heroinfo__isDelete'))
list.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))
from django.db.models import Q
list.filter(Q(pk_ _lt=6))
list.filter(pk_ _lt=6).filter(bcommet_ _gt=10)
list.filter(Q(pk_ _lt=6) | Q(bcommet_ _gt=10))
list.filter(~Q(pk__lt=6))
http://www.itcast.cn/python/1/?i=1&p=new,只匹配“/python/1/”部分
url(r'^([0-9]+)/$', views.detail, name='detail'),
url(r'^(?P<id>[0-9]+)/$', views.detail, name='detail'),
from django.conf.urls import include, url
urlpatterns = [
url(r'^', include('booktest.urls', namespace='booktest')),
]
请求http://www.itcast.cn/booktest/1/
在sesstings.py中的配置:
url(r'^booktest/', include('booktest.urls', namespace='booktest')),
在booktest应用urls.py中的配置
url(r'^([0-9]+)/$', views.detail, name='detail'),
匹配部分是:/booktest/1/
匹配过程:在settings.py中与“booktest/”成功,再用“1/”与booktest应用的urls匹配
新建views1.py
#coding:utf-8
from django.http import HttpResponse
def index(request):
return HttpResponse("你好")
在urls.py中修改配置
from . import views1
url(r'^$', views1.index, name='index'),
defaults.page_not_found(request, template_name=’404.html’)
默认的404视图将传递一个变量给模板:request_path,它是导致错误的URL
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
找不到了
<hr/>
{{request_path}}
</body>
</html>
DEBUG = False
ALLOWED_HOSTS = ['*', ]
请求一个不存在的地址
http://127.0.0.1:8000/test/
is_ajax():如果请求是通过XMLHttpRequest发起的,则返回True
dict.get('键',default)
或简写为
dict['键']
dict.getlist('键',default)
创建视图getTest1用于定义链接,getTest2用于接收一键一值,getTest3用于接收一键多值
def getTest1(request):
return render(request,'booktest/getTest1.html')
def getTest2(request):
return render(request,'booktest/getTest2.html')
def getTest3(request):
return render(request,'booktest/getTest3.html')
url(r'^getTest1/$', views.getTest1),
url(r'^getTest2/$', views.getTest2),
url(r'^getTest3/$', views.getTest3),
创建getTest1.html,定义链接
<html>
<head>
<title>Title</title>
</head>
<body>
链接1:一个键传递一个值
<a href="/getTest2/?a=1&b=2">gettest2</a><br>
链接2:一个键传递多个值
<a href="/getTest3/?a=1&a=2&b=3">gettest3</a>
</body>
</html>
def getTest2(request):
a=request.GET['a']
b=request.GET['b']
context={'a':a,'b':b}
return render(request,'booktest/getTest2.html',context)
<html>
<head>
<title>Title</title>
</head>
<body>
a:{{ a }}<br>
b:{{ b }}
</body>
</html>
def getTest3(request):
a=request.GET.getlist('a')
b=request.GET['b']
context={'a':a,'b':b}
return render(request,'booktest/getTest3.html',context)
<html>
<head>
<title>Title</title>
</head>
<body>
a:{% for item in a %}
{{ item }}
{% endfor %}
<br>
b:{{ b }}
</body>
</html>
def postTest1(request):
return render(request,'booktest/postTest1.html')
url(r'^postTest1$',views.postTest1)
创建模板postTest1.html
<html>
<head>
<title>Title</title>
</head>
<body>
<form method="post" action="/postTest2/">
姓名:<input type="text" name="uname"/><br>
密码:<input type="password" name="upwd"/><br>
性别:<input type="radio" name="ugender" value="1"/>男
<input type="radio" name="ugender" value="0"/>女<br>
爱好:<input type="checkbox" name="uhobby" value="胸口碎大石"/>胸口碎大石
<input type="checkbox" name="uhobby" value="跳楼"/>跳楼
<input type="checkbox" name="uhobby" value="喝酒"/>喝酒
<input type="checkbox" name="uhobby" value="爬山"/>爬山<br>
<input type="submit" value="提交"/>
</form>
</body>
</html>
def postTest2(request):
uname=request.POST['uname']
upwd=request.POST['upwd']
ugender=request.POST['ugender']
uhobby=request.POST.getlist('uhobby')
context={'uname':uname,'upwd':upwd,'ugender':ugender,'uhobby':uhobby}
return render(request,'booktest/postTest2.html',context)
url(r'^postTest2$',views.postTest2)
<html>
<head>
<
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/mrwxh/article/details/80424735
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!