django 操作数据库--orm(object relation mapping)---models

思想

django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM)。

  PHP:activerecord

  Java:Hibernate

  C#:Entity Framework

django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。

  • 创建数据库,设计表结构和字段
  • 使用 MySQLdb 来连接数据库,并编写数据访问层代码
  • 业务逻辑层去调用数据访问层执行数据库操作

三层架构

创建表

1、创建Model,之后可以根据Model来创建数据库表

完整表的orm创建语句,当忘记的时候可以作为参考

1、models.AutoField  自增列 = int(11)
  如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
2、models.CharField  字符串字段
  必须 max_length 参数
3、models.BooleanField  布尔类型=tinyint(1)
  不能为空,Blank=True
4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar
  继承CharField,所以必须 max_lenght 参数
5、models.DateField  日期类型 date
  对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
6、models.DateTimeField  日期类型 datetime
  同DateField的参数
7、models.Decimal  十进制小数类型 = decimal
  必须指定整数位max_digits和小数位decimal_places
8、models.EmailField  字符串类型(正则表达式邮箱) =varchar
  对字符串进行正则表达式
9、models.FloatField  浮点类型 = double
10、models.IntegerField  整形
11、models.BigIntegerField  长整形
  integer_field_ranges = {
    ‘SmallIntegerField‘: (-32768, 32767),
    ‘IntegerField‘: (-2147483648, 2147483647),
    ‘BigIntegerField‘: (-9223372036854775808, 9223372036854775807),
    ‘PositiveSmallIntegerField‘: (0, 32767),
    ‘PositiveIntegerField‘: (0, 2147483647),
  }
12、models.IPAddressField  字符串类型(ip4正则表达式)
13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)
  参数protocol可以是:both、ipv4、ipv6
  验证时,会根据设置报错
14、models.NullBooleanField  允许为空的布尔类型
15、models.PositiveIntegerFiel  正Integer
16、models.PositiveSmallIntegerField  正smallInteger
17、models.SlugField  减号、下划线、字母、数字
18、models.SmallIntegerField  数字
  数据库中的字段有:tinyint、smallint、int、bigint
19、models.TextField  字符串=longtext
20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]]
21、models.URLField  字符串,地址正则表达式
22、models.BinaryField  二进制
23、models.ImageField   图片
24、models.FilePathField 文件

更多字段

1、null=True
  数据库中字段是否可以为空
2、blank=True
  django的 Admin 中添加数据时是否可允许空值
3、primary_key = False
  主键,对AutoField设置主键后,就会代替原来的自增 id 列
4、auto_now 和 auto_now_add
  auto_now   自动创建---无论添加或修改,都是当前操作的时间
  auto_now_add  自动创建---永远是创建时的时间
5、choices
GENDER_CHOICE = (
        (u‘M‘, u‘Male‘),
        (u‘F‘, u‘Female‘),
    )
gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
6、max_length
7、default  默认值
8、verbose_name  Admin中字段的显示名称
9、name|db_column  数据库中的字段名称
10、unique=True  不允许重复
11、db_index = True  数据库索引
12、editable=True  在Admin里是否可编辑
13、error_messages=None  错误提示
14、auto_created=False  自动创建
15、help_text  在Admin中提示帮助信息
16、validators=[]
17、upload-to

更多参数

写完models 的orm语句,要生成表执行下面的语句

然后复制粘贴到models里面,,可惜,syncdb命令取消了,有哪些命令可以用python manage.py ---help查看,悲伤那么大

那么我们把生成的实体类代码到blog/models也是可以的

2.数据库配置

1      django默认支持sqlite,mysql, oracle,postgresql数据库。

    <1> sqlite

            django默认使用sqlite的数据库,默认自带sqlite的数据库驱动

            引擎名称:django.db.backends.sqlite3

     <2>mysql

            引擎名称:django.db.backends.mysql

2    mysql驱动程序

          MySQLdb(mysql python)

          mysqlclient

          MySQL

          PyMySQL(纯python的mysql驱动程序)

3     在django的项目中会默认使用sqlite数据库,在settings里有如下设置:

如果我们想要更改数据库,需要修改如下:

DATABASES = {
    ‘default‘: {
        ‘ENGINE‘: ‘django.db.backends.mysql‘,
        ‘NAME‘:‘django_com‘,
        ‘USER‘:‘root‘,
        ‘PASSWORD‘:‘‘,
        ‘host‘:‘localhost‘ ,
    }
}

注意:NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建

USER和PASSWORD分别是数据库的用户名和密码。

设置完后,再启动我们的Django项目前,我们需要激活我们的mysql。

然后,启动项目,会报错:no module named MySQLdb

这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb对于py3有很大问题,所以我们需要的驱动是PyMySQL

所以,我们只需要找到项目名文件下的__init__,在里面写入:

import pymysql

pymysql.install_as_MySQLdb()

         问题就解决了!

         这时就可以正常启动了。

连表结构

  • 一对多:models.ForeignKey(其他表)
  • 多对多:models.ManyToManyField(其他表)
  • 一对一:models.OneToOneField(其他表)
应用场景:

一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
  例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。
多对多:在某表中创建一行数据是,有一个可以多选的下拉框
  例如:创建用户信息,需要为用户指定多个爱好
一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了
  例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据

数据库操作 ---增删改查

    • 增加:创建实例,并调用save
    • 更新:a.获取实例,再sava;b.update(指定列)
    • 删除:a. filter().delete(); b.all().delete()
    • 获取:a. 单个=get(id=1) ;b. 所有 = all()
    • 过滤:filter(name=‘xxx‘);filter(name__contains=‘‘);(id__in = [1,2,3]) ;
      icontains(大小写无关的LIKE),startswith和endswith, 还有range(SQLBETWEEN查询)‘gt‘, ‘in‘, ‘isnull‘, ‘endswith‘, ‘contains‘, ‘lt‘, ‘startswith‘, ‘iendswith‘, ‘icontains‘,‘range‘, ‘istartswith‘
    • 排序:order_by("name") =asc ;order_by("-name")=desc
    • 返回第n-m条:第n条[0];前两条[0:2]
    • 指定映射:values
    • 数量:count()
    • 聚合:from django.db.models import Min,Max,Sum objects.all().aggregate(Max(‘guest_id‘))
    • 原始SQL

   # 增
    #
    # models.Tb1.objects.create(c1=‘xx‘, c2=‘oo‘)  增加一条数据,可以接受字典类型数据 **kwargs

    # obj = models.Tb1(c1=‘xx‘, c2=‘oo‘)
    # obj.save()

    # 查
    #
    # models.Tb1.objects.get(id=123)         # 获取单条数据,不存在则报错(不建议)
    # models.Tb1.objects.all()               # 获取全部
    # models.Tb1.objects.filter(name=‘seven‘) # 获取指定条件的数据

    # 删
    #
    # models.Tb1.objects.filter(name=‘seven‘).delete() # 删除指定条件的数据

    # 改
    # models.Tb1.objects.filter(name=‘seven‘).update(gender=‘0‘)  # 将指定条件的数据更新,均支持 **kwargs
    # obj = models.Tb1.objects.get(id=1)
    # obj.c1 = ‘111‘
    # obj.save() 

案例-增删改查

进阶操作

利用双下划线将字段和对应的操作连接起来

    # 获取个数
    #
    # models.Tb1.objects.filter(name=‘seven‘).count()

    # 大于,小于
    #
    # models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
    # models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值
    # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值

    # in
    #
    # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
    # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

    # contains
    #
    # models.Tb1.objects.filter(name__contains="ven")
    # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
    # models.Tb1.objects.exclude(name__icontains="ven")

    # range
    #
    # models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and

    # 其他类似
    #
    # startswith,istartswith, endswith, iendswith,

    # order by
    #
    # models.Tb1.objects.filter(name=‘seven‘).order_by(‘id‘)    # asc
    # models.Tb1.objects.filter(name=‘seven‘).order_by(‘-id‘)   # desc

    # limit 、offset
    #
    # models.Tb1.objects.all()[10:20]

    # group by
    from django.db.models import Count, Min, Max, Sum
    # models.Tb1.objects.filter(c1=1).values(‘id‘).annotate(c=Count(‘num‘))
    # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"

对应代码

表结构实例

class UserProfile(models.Model):
    user_info = models.OneToOneField(‘UserInfo‘)
    username = models.CharField(max_length=64)
    password = models.CharField(max_length=64)

    def __unicode__(self):
        return self.username

class UserInfo(models.Model):
    user_type_choice = (
        (0, u‘普通用户‘),
        (1, u‘高级用户‘),
    )
    user_type = models.IntegerField(choices=user_type_choice)
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    address = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name

class UserGroup(models.Model):

    caption = models.CharField(max_length=64)

    user_info = models.ManyToManyField(‘UserInfo‘)

    def __unicode__(self):
        return self.caption

class Host(models.Model):
    hostname = models.CharField(max_length=64)
    ip = models.GenericIPAddressField()
    user_group = models.ForeignKey(‘UserGroup‘)

    def __unicode__(self):
        return self.hostname

实例

create和save方法

注意:如果每次创建一个对象,想显示对应的raw sql,需要在settings加上日志记录部分:

LOGGING = {
#     ‘version‘: 1,
#     ‘disable_existing_loggers‘: False,
#     ‘handlers‘: {
#         ‘console‘:{
#             ‘level‘:‘DEBUG‘,
#             ‘class‘:‘logging.StreamHandler‘,
#         },
#     },
#     ‘loggers‘: {
#         ‘django.db.backends‘: {
#             ‘handlers‘: [‘console‘],
#             ‘propagate‘: True,
#             ‘level‘:‘DEBUG‘,
#         },
#     }
# }

那么如何插入存在外键和多对多关系的一本书的信息呢?

总结:

1   objects:   model默认管理器。

2   插入主外键关系的时候,可以用对象的方式,也可以用关联id的方式。

3   插入多对多关系的时候要分步操作。

4   create是管理器objects的方法

save是model对象的方法

update和save方法

实例:

注意:<1>不能用get的原因是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySet对象。

    

<2>  filter:

>>> Publisher.objects.filter(name__contains="press")
[   <Publisher: Apress>]

orm:  __contains相当于like"%%"的模糊匹配

<3> 在“插入和更新数据”小节中,我们有提到模型的save()方法,这个方法会更新一行里的所有列。 而某些情况下,我们只需要更新行里的某几列。例如说我们现在想要将Apress Publisher的名称由原来的”Apress”更改为”Apress Publishing”。若使用save()方法,如:

>>> p = Publisher.objects.get(name=‘Apress‘)
>>> p.name = ‘Apress Publishing‘
>>> p.save()

这等同于如下SQL语句:

SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = ‘Apress‘;

UPDATE books_publisher SET
    name = ‘Apress Publishing‘,
    address = ‘2855 Telegraph Ave.‘,
    city = ‘Berkeley‘,
    state_province = ‘CA‘,
    country = ‘U.S.A.‘,
    website = ‘http://www.apress.com‘
WHERE id = 52;

  注意在这里我们假设Apress的ID为52)

在这个例子里我们可以看到Django的save()方法更新了不仅仅是name列的值,还有更新了所有的列。 若name以外的列有可能会被其他的进程所改动的情况下,只更改name列显然是更加明智的。 更改某一指定的列,我们可以调用结果集(QuerySet)对象的update()方法: 示例如下:

>>> Publisher.objects.filter(id=52).update(name=‘Apress Publishing‘)

与之等同的SQL语句变得更高效,并且不会引起竞态条件。

UPDATE books_publisher
SET name = ‘Apress Publishing‘
WHERE id = 52;

update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录。 以下示例演示如何将所有Publisher的country字段值由’U.S.A’更改为’USA’:

>>> Publisher.objects.all().update(country=‘USA‘)

      >>> Book.objects.filter(id=1).delete()

       (3, {‘app01.Book_authors‘: 2, ‘app01.Book‘: 1})

我们表面上删除了一条信息,实际却删除了三条,因为我们删除的这本书在Book_authors表中有两条相关信息,这种删除方式就是django默认的级联删除。

先记住一句话,values是列表里面是字典,value_list是列表里面是元组

上图只是当自己忘记了看一眼怎么写(完整样式)

下面开始讲解

>>> Publisher.objects.all()
[<Publisher: 中国机械出版社>, <Publisher: American publisher>]

注意:

这相当于这个SQL语句:

SELECT id, name, address, city, state_province, country, website
FROM books_publisher;

注意到Django在选择所有数据时并没有使用 SELECT* ,而是显式列出了所有字段。

惰性机制:

所谓惰性机制:Publisher.objects.all()只是返回了一个QuerySet(查询结果集对象),并不会马上执行sql,而是当调用QuerySet的时候才执行。

QuerySet特点:

1   可迭代的

2   可切片

一  查询相关API:

 <1>get(**kwargs):        返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。

 <2>all():                       查询所有结果

 <3>filter(**kwargs):      它包含了与所给筛选条件相匹配的对象

 <4>exclude(**kwargs):  它包含了与所给筛选条件不匹配的对象

 <5>order_by(*field):      对查询结果排序

 <6>reverse():                对查询结果反向排序

 <7>distinct():                从返回结果中剔除重复纪录

 <8>values(*field):         返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一

                                     系列 model的实例化对象,而是一个可迭代的字典序列                [{‘user‘: ‘uesr‘, ‘user_type__caption‘: ‘普通用户‘},  {‘user‘: ‘uesr‘, ‘user_type__caption‘: ‘普通用户‘}]

 <9>values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 -----【(),(),()】

 <10>count():                返回数据库中匹配查询(QuerySet)的对象数量。

<11>first():                   返回第一条记录,等价于[:1][0]

<12>last():                   返回最后一条记录,等价于[::1][0]

 <13>exists():               如果QuerySet包含数据,就返回True,否则返回False。

实例:

1   查询id为2的书籍信息,并只显示书籍名称和出版日期

>>> Book.objects.filter(id=2).values("title","publication_date")
        [{‘title‘: ‘python Gone‘, ‘publication_date‘: datetime.date(2019, 5, 24)}]

2   查询所有的出版信息,并按id降序排列,并尝试使用reverse方法进行反向排序。

>>> Publisher.objects.all().order_by("id")
        [<Publisher: 中国机械出版社>, <Publisher: Boo>, <Publisher: 人民出版社>]
>>> Publisher.objects.all().order_by("id").reverse()
        [<Publisher: 人民出版社>, <Publisher: Boo>, <Publisher: 中国机械出版社>]                 

>>> Publisher.objects.all().order_by("-id")
        [<Publisher: 人民出版社>, <Publisher: Boo>, <Publisher: 中国机械出版社>]

3    查询出版社所在的城市信息,城市信息不要重复

>>> Publisher.objects.all().values("city").distinct()
        [{‘city‘: ‘北京‘}, {‘city‘: ‘beijing‘}]

4    查询城市是北京的出版社,尝试使用exclude方法

>>> Publisher.objects.all().filter(city=‘beijing‘)
        [<Publisher: Boo>]

5    查询男作者的数量

>>> AuthorDetail.objects.filter(sex=0).count()

查询一对一

user_info_obj = models.UserInfo.objects.filter(id=1).first()
print user_info_obj.user_type
print user_info_obj.get_user_type_display()
print user_info_obj.userprofile.password

user_info_obj = models.UserInfo.objects.filter(id=1).values(‘email‘, ‘userprofile__username‘).first()
print user_info_obj.keys()
print user_info_obj.values()

查询一对多

多表关联查询

多表正向查询

多表反向查询

创建多对多的表

1   外键关联查询

 >>> AuthorDetail.objects.all().values("author")

        [{‘author‘: 1}]
>>> AuthorDetail.objects.all().values("author__name")
        [{‘author__name‘: ‘alex‘}]

2  多对多关联查询

>>> Book.objects.all().filter(title=‘python Gone‘).values("authors")

        [{‘authors‘: 1}, {‘authors‘: 2}]
>>> Book.objects.all().filter(title=‘python Gone‘).values("authors__name")
        [{‘authors__name‘: ‘alex‘}, {‘authors__name‘: ‘alvin‘}]

>>> Book.objects.all().filter(authors__name=‘alex‘).values(‘title‘)
        [{‘title‘: ‘python Gone‘}]

多表查询技巧:

__:两个下划线可以生成连接查询,查询关联的字段信息

_set:提供了对象访问相关联表数据的方法。但是这种方法只能是相关类访问定义了关系的类(主键类访问外键类)

聚合查询和分组查询

1  annotate(*args,**kwargs):可以为QuerySet每一个对象添加注解。可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),用于分组查询

2  aggregate(*args,**kwargs):通过对QuerySet进行计算,返回一个聚合值的字典。

aggregate()中每一个参数都指定一个包含在字典中的返回值。用于聚合查询。

聚合函数(Aggregation Functions)

所在位置:django.db.models

1 Avg:  返回所给字段的平均值

2 Count: 根据所给的关联字段返回被关联的model的数量

3 Max:返回所给字段的最大值

4 Sum:计算所给字段的总和

为了演示实例,在这里我们给Book加一个price字段:

然后同步数据库:makemigrations, migrate

索引

db_index = True  数据库索引

复合索引

唯一索引

				
时间: 2024-07-30 13:42:27

django 操作数据库--orm(object relation mapping)---models的相关文章

Object Relation Mapping ORM

对象关系映射(英语:Object Relation Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.从效果上说,它其实是创建了一个可在编程语言里使用的--"虚拟对象数据库". 面向对象是从软件工程基本原则(如耦合.聚合.封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别.为了解决这个不匹配的现象,对象关系映射技术应运而生. 对象关系映射(Object-Rela

django之数据库orm

django之数据库orm 一.数据库的配置 1 django默认支持sqlite,mysql, oracle,postgresql数据库. <1>sqlite django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 引擎名称:django.db.backends.sqlite3 <2>mysql 引擎名称:django.db.backends.mysql 2 mysql驱动程序 MySQLdb(mysql python) mysqlclient MySQL P

Django之 数据库ORM

一.ORM Django的 业务 少不了 跟数据库打交道,不然没有数据库保存一些数据将是一件很糟糕的事情.Django 对 数据库 支持原生的 SQL语句,但更好的对数据库支持,Django自己有一套对数据库操作的模块,在操作.性能.便捷上 有很好的提升.ORM,Object Relational Mapping,对象关系映射.从字面意思理解,面向对象编程把所有实体看成对象(object),关系型数据库则是采用实体之间的关系(relation)连接数据.很早就有人提出,关系也可以用对象表达,这样

django操作数据库增删改查

1.django初始化配置https://blog.51cto.com/yht1990/2382898 2.创建模型D:\mysite\polls\models.py from django.db import models class Publisher(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 name = models.CharField(max_length=64, null=False) 3.建表

django操作数据库之查询F,Q操作 和 seach搜索功能

# F 使用查询条件的值 # # from django.db.models import F # models.Tb1.objects.update(num=F('num')+1) # Q 构建搜索条件 from django.db.models import Q # con = Q() # # q1 = Q() # q1.connector = 'OR' # q1.children.append(('id', 1)) # q1.children.append(('id', 10)) # q1

手写SORM(simple object relation mapping)框架2—接口设计

首先在工程下建立3个包,分别是:core,utils,bean core: Query接口 package com.yf.sorm.core; import java.util.List; /** * 负责查询(对外提供服务的核心类) * @author yangf * */ public interface Query { /** * 直接执行一个DML语句 * @param sql sql语句 * @param params 参数 * @return 执行SQL语句后影响记录的行数 */ p

Django操作数据库

引入models的定义 from app.models import  myclass class  myclass(): aa =  models. CharField (max_length=None) bb =  models. CharField (max_length=None) def __unicode__(self): return self.aa 增 添加一行数据1 add = myclass(aa='wahaha',bb='hahawa' ) add.save() #不sav

在Django中使用ORM创建图书管理系统

一.ORM(对象关系映射) 很多语言的web框架中都有这个概念 1. 为什么要有ORM? 1. 写程序离不开数据,要使用数据就需要连接数据库,但是不同的数据库在sql语句上(mysql,oracle等)会有点区别, 因此直接在你的项目中使用sql语句的话,不便于以后的修改,万一更换了数据库,那所有sql语句不就要重新写吗? 所以这个时候ORM就体现出优点了,你只需要写ORM的代码,它就会根据你连接的数据库自动帮你翻译成对应的sql语句, 也就是说无论你使用的是mysql还是oracle,ORM操

python中cursor操作数据库(转)

原文出处:http://doudouclever.blog.163.com/blog/static/175112310201284115340663/ python 操作数据库,要安装一个Python和数据库交互的包MySQL-python-1.2.2.win32-py2.5.exe,然后我们就可以使用MySQLdb这个包进行数据库操作了.     操作步骤如下:    1.建立数据库连接     import MySQLdb     conn=MySQLdb.connect(host="loc