Django操作之ORM与自定制分页

一.创建表

Django自带数据库ORM是基于SQLite,如果使用sqlite则不需要做配置修改,如果需要基于mysql连接则需要做相关配置:

1.在安装好的mysql中创建数据库,注意字符集选择utf8以便支持汉字(ORM不支持创建数据库,只能创建表)

2.在创建的Django项目同名文件夹中 setting.py 配置对于mysql数据库的连接:

 1 # 1.将默认的设置注释掉:
 2 # DATABASES = {
 3 #     'default': {
 4 #         'ENGINE': 'django.db.backends.sqlite3',
 5 #         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
 6 #     }
 7 # }
 8 
 9 # 2.设置对于mysql的连接:
10 DATABASES = {
11     'default': {
12         'ENGINE': 'django.db.backends.mysql',  
13         'NAME':'new',    #数据库名称
14         'USER': 'root',  #用户名
15         'PASSWORD': 'pwd',   #密码
16         'HOST': 'localhost',      #连接地址,可以不填
17         'PORT': 3306,    #端口
18     }
19 }    

3.在同层目录下的__init__.py文件导入对应模块:

 import pymysql 

 pymysql.install_as_MySQLdb() 

此时基本配置已经完成,接下来进入处理业务代码的app01文件夹下的models.py中进行对ORM的建表操作

 1 from django.db import models #导入django ORM对应模块
 2 
 3 # Create your models here.
 4 class Class1(models.Model):  #继承models模块定制类,即创建表,类名为表明
 5     cid = models.AutoField(primary_key=True)    #创建主键,AutoField为自增(主键可以不写,不写时默认生成一行名称为ID的主键列)
 6     cname = models.CharField(max_length=32)     #创建char类型字符串,最大长度32
 7     
 8 class Teacher(models.Model):
 9     tid = models.AutoField(primary_key=True)
10     tname = models.CharField(max_length=32)
11 
12 class Student(models.Model):
13     sid = models.AutoField(primary_key=True) 
14     sname = models.CharField(max_length=32)
15     Class = models.ForeignKey(Class1)  #创建外键,括号里面填写外键关系的表名 这个类在生成时,Class列会显示为Class_id即自写的列名加_id 
16 
17 class Guanxi(models.Model):
18     teacher = models.ForeignKey(Teacher)
19     Class = models.ForeignKey(Class1)
基于ORM类形式创建表

当类表定制完毕时,cmd切换到Django项目的根目录,运行命令:(注意将python添加至环境变量)

 python manage.py makemigrations  

 python manage.py migrate 

此时数据表即完成创建成功,如有报错,注意查看某个字段是否类型错误,检查之前步骤是否有遗漏。

如果是用的sqlite创建,可以用pycharm自带的可视化以及Django的sqlite结合查看表。(将项目中的sqlite3拖拽到pycharm编辑器右上角点开的Database中)

 

二:基于ORM对表进行增删改查:

本次操作在views模块中,因此首先导入之前创建的表类

from app01 import models

 1 查:
 2 res = models.UserType.objects.all() #获取表所有数据,得到一个QuerySet[obj,obj,obj],类似一个个对象组成的列表,循环列表取到的为对象,拥有表的字段属性。
 3 for row in res:
 4     print(row.cid,row.cname)
 5 
 6 res = models.UserType.objects.all() .first() #获取表所有数据的第一行,实际为一个Obj对象,可以res.cid,res.cname取值
 7 
 8 res = models.UserType.objects.filter(cid=1) 
 9 res = models.UserInfo.objects.filter(id__gt=1) id大于1
10 res = models.UserInfo.objects.filter(id__lt=1) id小于1
11 #filter查询时,括号里面可以添加条件,得到的依然为QuerySet,需要取值依旧需要for 循环 或者后面加.first()方法,当然也可以按索引取值,得到的也是obj对象
12 
13 res = models.UserInfo.objects.all().values('id','name') #实际还是QuerySet,括号里面可以限定需要查询的列,不同的是,这里循环出来的不再是对象,而是一个个的字典 QuerySet[{'id':'xx','name':'xx'} ] 取值需按字典key取值。
14 # 跨表  __
15     # result = models.UserInfo.objects.all().values('id','name',"ut__title")
16     # for item in result:
17     #     print(item['id'],item['name'],item['ut__title'])
18 
19 
20 res = models.UserInfo.objects.all().values_list('id','name') #得到QuerySet[(1,'f'), ] 循环出来的还是一个个的列表,列表索引取值。
21 
22 # 跨表  __
23     # result = models.UserInfo.objects.all().values_list('id','name',"ut__title")
24     # for item in result:
25     #     print(item[0],item[1],item[2])
26 
27 
28 
29 增:
30 #增加为create(),括号里面填写数据行需要的各个数据即可
31    models.UserType.objects.create(title='普通用户')
32 
33 
34 
35 删:
36 #删除需在查询到数据的基础上,后面加上.delete()方法即可
37 models.UserInfo.objects.filter(id=1).delete()
38 
39 
40 改:
41 #对应的,修改也是在查询的基础上,加.update()方法
42 models.Student.objects.filter(sid=a1).update(sname=name,Class_id=cid)
43 
44 #外键操作:以下操作基于2个表已经建立外键关系的基础
45 ##正向操作:
46 # UserInfo,ut是FK字段 - 正向操作  PS: 一个用户只有一个用户类型
47 obj = models.UserInfo.objects.all().first()
48 print(obj.name,obj.age,obj.ut.title)  
49 #通过.外键名.对应关系表的字段列名即可拿到UserType表里面的title列值
50 #同样的如果有多个关系表连表操作时,可以一直.外键无穷无尽的连表取到需要的值
51 
52 #反向操作:
53 # UserType, 表名小写_set.all()  - 反向操作   PS: 一个用户类型下可以有很多用户
54 obj = models.UserType.objects.all().first() #取到用户类型的其中一个Obj
55 print('用户类型',obj.id,obj.title)
56 #通过用户类型查看该类型下有多少个用户
57  for row in obj.userinfo_set.all():  
58      print(row.name,row.age)
59 
60 
61 result = models.UserType.objects.all()
62     for item in result:
63         print(item.title,item.userinfo_set.filter(name='xx'))
Django ORM操作表

 

 1 有三个表:
 2 class Boy(models.Model):
 3     name = models.CharField(max_length=32)
 4 
 5 class Girl(models.Model):
 6     nick = models.CharField(max_length=32)
 7 
 8 class Love(models.Model):
 9     b = models.ForeignKey('Boy',null=True)
10     g = models.ForeignKey('Girl',null=True)
11     #联合唯一索引
12     #class Meta:
13       #  unique_together = [
14         #    ('b','g'),
15         #]
16 
17 1.通过Boy表中name为条件查找Girl表有关联的nick值:
18 插数据:
19 # obj_list = [
20     #     models.Boy(name='刘德华'),
21     #     models.Boy(name='张学友'),
22     #     models.Boy(name='郭富城'),
23     #     models.Boy(name='黎明'),
24     # ]
25     # objs = [
26     #     models.Girl(nick='陈慧琳'),
27     #     models.Girl(nick='容祖儿'),
28     #     models.Girl(nick='郑秀文'),
29     #     models.Girl(nick='蒙嘉慧'),
30     #     ]
31     # models.Boy.objects.bulk_create(obj_list,5)
32     # models.Girl.objects.bulk_create(objs,5)
33 建立关系
34     # models.Love.objects.create(b_id=1,g_id=1)
35     # models.Love.objects.create(b_id=1,g_id=4)
36     # models.Love.objects.create(b_id=2,g_id=2)
37     # models.Love.objects.create(b_id=2,g_id=3)
38     # models.Love.objects.create(b_id=2,g_id=4)
39 多对多的关系查询:
40     # lo_list = models.Love.objects.filter(b__name='刘德华').values('b__name','g__nick')
41     # for i in lo_list:
42     #     print(i['b__name'],i['g__nick'])
43     #
44     # lov_list = models.Love.objects.filter(b__name='张学友').select_related('b','g')
45     # for row in lov_list:
46     #     print(row.b.name,row.g.nick)
47 
48 二。两个表的关系也可以不再建关系表Love,通过Django内置ORM的功能同样可以建立表之间的关系,查找时通过间接查找。
49 class Boy(models.Model):
50     name = models.CharField(max_length=32)
51     m = models.ManyToManyField('Girl')
52 
53 class Girl(models.Model):
54     nick = models.CharField(max_length=32)
55 
56 如此,同样可以建立关系,只不过增删改查相应也有变化。
57 
58 obj = models.Boy.objects.filter(name='刘德华').first()  #取到筛选出的Boy对象:
59     #
60     obj.m.add(1)
61     obj.m.add(*[2,3,])
62 
63     # 删:
64     obj.m.remove(1,)
65     obj.m.remove(*[2,])
66 
67     #
68     obj.m.set([1,2,])  #实为重置,将之前的全部删除重新建立关系
69 
70     #
71     q = obj.m.all()  #q得到对应关系的Girl对象
ORM表多对多操作

 

三.Django之自定义分页

 由于Django自带分页具有局限性,且其它框架都不包含分页功能,因此这里自定义一个分页功能模块。

 1 # Create your views here.
 2 #定制分页类:
 3 class PageInfo(object):
 4     def __init__(self,current_page,all_count,per_page,base_url,show_page=11):
 5         """
 6 
 7                 :param current_page:当前页
 8                 :param all_count: 数据库总行数
 9                 :param per_page: 每页显示行数
10                 :param base_url: 需要分页的url
11                 :param show_page: 页面可以显示的页数
12                 :return:
13          """
14         """将传入的当前页转为int 如果传入的为字符串,抛出异常直接
15         将当前页设置为第一页"""
16         try:
17             self.current_page = int(current_page)
18         except Exception as e:
19             self.current_page = 1
20 
21         self.per_page = per_page
22         """通过数据库所有数据的行数除以每页显示的行数,得到需要一共
23         显示的页数,如果有余数则商要+1,余下的行单独一页"""
24         a,b = divmod(all_count,per_page)
25         if b:
26             a = a+1
27         self.all_pager = a
28         self.show_page = show_page
29         self.base_url = base_url
30 
31     """通过当前页码以及页面显示行数来获取页面上显示的具体行的数据
32     如第1页就是1-10行,第2页为11-20行,"""
33     def start(self):
34         return (self.current_page-1) * self.per_page
35     def end(self):
36         return self.current_page * self.per_page
37 
38     """实际执行函数"""
39     def pager(self):
40 
41         page_list = []
42         #如果页面上显示11页,样式应该是当前页前面一半后面一半,所以-1然后/2
43         half = int((self.show_page-1)/2)
44         # 如果数据总页数<11 show_page,即不足11页,就只显示数据一共能显示的页数
45         if self.all_pager < self.show_page:
46             begin = 1
47             stop = self.all_pager
48         # :param begin:当前页面显示的最左页,即第一页
49         # :param stop: 当前显示的最右,即最后一页
50         else:
51             # 如果当前页 <=5,永远显示1,11
52             if self.current_page <= half:
53                 begin = 1
54                 stop =self.show_page
55             else:
56                 # 如果当前页+5 大于实际存在的最大页,比如一共有35页,当前页为
57                 # 32,再取后5页就是37,则36、37为空,所以加个判定,超过极限就
58                 # 取最右页为实际最大页,最左就是-11,即还是一共显示11页,
59                 if self.current_page + half > self.all_pager:
60                     begin = self.all_pager - self.show_page + 1
61                     stop = self.all_pager
62                 else:
63                     #这里为正常情况,显示当前页的前5页跟后5页
64                     begin = self.current_page-half
65                     stop = self.current_page + half 
66 
67         #上一页功能    
68         #当前页小于等于1,上一页没有内容
69         if self.current_page <= 1:
70             prev = "<li><a href='#'>上一页</a></li>"
71         #拼接字符串生成li a标签 上一页页数为当前页-1,添加到列表中    
72         else:
73             prev = "<li><a href='%s?page=%s'>上一页</a></li>" %(self.base_url,self.current_page-1,)
74         page_list.append(prev)
75         
76         #当前页面同时显示的页面,由上面赋值的最左与最右页决定,+1是因为for循环range不顾尾
77         for i in range(begin,stop+1):
78             if i == self.current_page:
79                 # 当前页给一个class,CSS显示效果区别于其它页
80                 temp = "<li class='active'><a  href='%s?page=%s'>%s</a></li>" % (self.base_url, i, i,)
81             else:
82                 temp = "<li><a href='%s?page=%s'>%s</a></li>" % (self.base_url, i, i,)
83             page_list.append(temp)    
84         
85         #下一页功能,同样的当前页>=最大页一样不跳转    
86         if self.current_page >= self.all_pager:
87             nex = "<li><a href='#'>下一页</a></li>"
88         else:
89             nex = "<li><a href='%s?page=%s'>下一页</a></li>" % (self.base_url, self.current_page + 1,)
90         page_list.append(nex)
91         #此时列表中按顺序含有上一页的li a标签,需要显示的11页li a标签,以及下一页标签
92         #拼接成字符串并作为函数的返回值以供调用接收
93         return ''.join(page_list)
自定义分页功能代码

 

posted @ 2017-06-26 16:08  Mitsuis  阅读(2628)  评论(0编辑  收藏  举报