一文读懂|Django之Model操作数据库详解


一、django ORM简介

O(objects):类和对象。R(Relation):关系,关系数据库中的表格。M(Mapping):映射。

Django ORM框架的功能:

1.建立模型类和表之间的对应关系,允许我们通过面向对象的方式来操作数据库。

2.根据设计的模型类生成数据库中的表格。

3.通过方便的配置就可以进行数据库的切换。

二、 数据库的配置

Django可以配置使用sqlite3,mysql,oracle,postgresql等数据库。Django默认使用的是sqlite3数据库,settigs.py里面:

DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.sqlite3',#默认使用的数据库引擎是sqlite3,项目自动创建

        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),#指定数据库所在的路径

    }

}

Django项目也可以配置使用mysql数据库,使用如下配置:

DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.mysql',#表示使用的是mysql数据库的引擎

        'NAME': 'db1',      #数据库的名字,可以在mysql的提示符下先创建好

        'USER':'root',      #数据库用户名

        'PASSWORD':'',      #数据库密码

        'HOST':'',          #数据库主机,留空默认为"localhost"

        'PORT':'3306',      #数据库使用的端口

    }

}

配置好数据库的信息后还必须安装数据库的驱动程序,Django默认导入的mysql的驱动程序是MySQLdb,然而MySQLdb对于py3支持不全,所以这里使用PyMySQL。

pip install pymysql

在项目名文件下的__init__.py文件中写入如下配置:

import pymysql

pymysql.install_as_MySQLdb()

三、创建数据库表结构文件

对应app目录下的models.py

1、生成一个简单的数据库表:

在未指定primary_key的情况下,Django会默认创建一个id自增字段作为主键。

from django.db import models

class Account(models.Model):

    account_name = models.CharField(max_length=20)

    account_id = models.IntegerField(primary_key=True)

    balance = models.DecimalField(max_digits=2, decimal_places=2)

2、执行命令生成到数据库

python manage.py makemigrations

python manage.py migrate # 生成数据表

四、数据库字段

AutoField(Field) - int自增列,必须填入参数 primary_key=True

BigAutoField(AutoField) - bigint自增列,必须填入参数 primary_key=True

SmallIntegerField(IntegerField): - 小整数 -32768 ~ 32767

PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整数 0 ~ 32767

IntegerField(Field) - 整数列(有符号的) -2147483648 ~ 2147483647

PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整数 0 ~ 2147483647

BigIntegerField(IntegerField): - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

BooleanField(Field) - 布尔值类型

NullBooleanField(Field): - 可以为空的布尔值

CharField(Field) - 字符类型

- 必须提供max_length参数, max_length表示字符长度

TextField(Field) - 文本类型

EmailField(CharField): - 字符串类型,Django Admin以及ModelForm中提供验证机制

IPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

GenericIPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6

- 参数:

protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"

unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"

URLField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证 URL

SlugField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

CommaSeparatedIntegerField(CharField) - 字符串类型,格式必须为逗号分割的数字

UUIDField(Field) - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能

- 参数:

path,                      文件夹路径

match=None,                正则匹配

recursive=False,          递归下面的文件夹

allow_files=True,          允许文件

allow_folders=False,      允许文件夹

FileField(Field) - 字符串,路径保存在数据库,文件上传到指定目录

- 参数:

upload_to = ""      上传文件的保存路径

storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

ImageField(FileField) - 字符串,路径保存在数据库,文件上传到指定目录

- 参数:

upload_to = ""      上传文件的保存路径

storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

width_field=None,  上传图片的高度保存的数据库字段名(字符串)

height_field=None  上传图片的宽度保存的数据库字段名(字符串)

DateTimeField(DateField) - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

DateField(DateTimeCheckMixin, Field) - 日期格式      YYYY-MM-DD

TimeField(DateTimeCheckMixin, Field) - 时间格式      HH:MM[:ss[.uuuuuu]]

DurationField(Field) - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

FloatField(Field) - 浮点型

DecimalField(Field) - 10进制小数

- 参数:

max_digits,小数总长度

decimal_places,小数位长度

BinaryField(Field)- 二进制类型

五、数据库字段参数

null                数据库中字段是否可以为空

db_column          数据库中字段的列名

default            数据库中字段的默认值

primary_key        数据库中字段是否为主键

db_index            数据库中字段是否可以建立索引

unique              数据库中字段是否可以建立唯一索引

unique_for_date    数据库中字段【日期】部分是否可以建立唯一索引

unique_for_month    数据库中字段【月】部分是否可以建立唯一索引

unique_for_year    数据库中字段【年】部分是否可以建立唯一索引

verbose_name        Admin中显示的字段名称

blank              Admin中是否允许用户输入为空

editable            Admin中是否可以编辑

help_text          Admin中该字段的提示信息

choices            Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作

如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;

字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date

如:{'null': "不能为空.", 'invalid': '格式错误'}

validators          自定义错误验证(列表类型),从而定制想要的验证规则

from django.core.validators import RegexValidator

from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\

MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator

如:

test = models.CharField(

max_length=32,

error_messages={

'c1': '优先错信息1',

'c2': '优先错信息2',

'c3': '优先错信息3',

},

validators=[

RegexValidator(regex='root_\d+', message='错误了', code='c1'),

RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),

EmailValidator(message='又错误了', code='c3'), ]


)

六、数据库Meta元信息

class UserInfo(models.Model):

        nid = models.AutoField(primary_key=True)

        username = models.CharField(max_length=32)

        class Meta:

            # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名

            db_table = "table_name"

            # 联合索引

            index_together = [

                ("pub_date", "deadline"),

            ]

            # 联合唯一索引

            unique_together = (("driver", "restaurant"),)

            # admin中显示的表名称

            verbose_name

            # verbose_name加s

            verbose_name_plural

七、关系字段

关系字段用于保存数据表之间的关系,包括ForeignKey, ManyToManyField等。

1、ForeignKey

ForeignKey(ForeignObject) # ForeignObject(RelatedField)

        to,                        # 要进行关联的表名

        to_field=None,              # 要关联的表中的字段名称

        on_delete=None,            # 当删除关联表中的数据时,当前表与其关联的行的行为

                                        - models.CASCADE,删除关联数据,与之关联也删除

                                        - models.DO_NOTHING,删除关联数据,引发错误IntegrityError

                                        - models.PROTECT,删除关联数据,引发错误ProtectedError

                                        - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)

                                        - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)

                                        - models.SET,删除关联数据,

                                                      a. 与之关联的值设置为指定值,设置:models.SET(值)

                                                      b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

                                                        def func():

                                                            return 10

                                                        class MyModel(models.Model):

                                                            user = models.ForeignKey(

                                                                to="User",

                                                                to_field="id"

                                                                on_delete=models.SET(func),)

        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()

        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】    如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')

        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:

                                    # 如:

                                            - limit_choices_to={'nid__gt': 5}

                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q

                                            - limit_choices_to=Q(nid__gt=10)

                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)

                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')

        db_constraint=True          # 是否在数据库中创建外键约束

        parent_link=False          # 在Admin中是否显示关联数据

2、OneToOneField

OneToOneField(ForeignKey)

        to,                        # 要进行关联的表名

        to_field=None              # 要关联的表中的字段名称

        on_delete=None,            # 当删除关联表中的数据时,当前表与其关联的行的行为

                                    ###### 对于一对一 ######

                                    # 1. 一对一其实就是 一对多 + 唯一索引

                                    # 2.当两个类之间有继承关系时,默认会创建一个一对一字段

                                    # 如下会在A表中额外增加一个c_ptr_id列且唯一:

                                            class C(models.Model):

                                                nid = models.AutoField(primary_key=True)

                                                part = models.CharField(max_length=12)

                                            class A(C):

                                                id = models.AutoField(primary_key=True)

                                                code = models.CharField(max_length=1)

3、ManyToManyField

ManyToManyField(RelatedField)

        to,                        # 要进行关联的表名

        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()

        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】    如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')

        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:

                                    # 如:

                                            - limit_choices_to={'nid__gt': 5}

                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q

                                            - limit_choices_to=Q(nid__gt=10)

                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)

                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')

        symmetrical=None,          # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段

                                    # 做如下操作时,不同的symmetrical会有不同的可选字段

                                        models.BB.objects.filter(...)

                                        # 可选字段有:code, id, m1

                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)

                                            m1 = models.ManyToManyField('self',symmetrical=True)

                                        # 可选字段有: bb, code, id, m1

                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)

                                            m1 = models.ManyToManyField('self',symmetrical=False)

        through=None,              # 自定义第三张表时,使用字段用于指定关系表

        through_fields=None,        # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表

                                        from django.db import models

                                        class Person(models.Model):

                                            name = models.CharField(max_length=50)

                                        class Group(models.Model):

                                            name = models.CharField(max_length=128)

                                            members = models.ManyToManyField(

                                                Person,

                                                through='Membership',

                                                through_fields=('group', 'person'),

                                            )

                                        class Membership(models.Model):

                                            group = models.ForeignKey(Group, on_delete=models.CASCADE)

                                            person = models.ForeignKey(Person, on_delete=models.CASCADE)

                                            inviter = models.ForeignKey(

                                                Person,

                                                on_delete=models.CASCADE,

                                                related_name="membership_invites",

                                            )

                                            invite_reason = models.CharField(max_length=64)

        db_constraint=True,        # 是否在数据库中创建外键约束

        db_table=None,              # 默认创建第三张表时,数据库中表的名称

八、数据库基本操作

​#创建一个书的类,继承models类

class Book(models.Model):

    #用models类创建书的名字,类型为字符串,CharField相当于mysql语句中的varchar,字段最长为32

    title = models.CharField(max_length=32)


    #创建书的价格,类型为浮点型,小数点前最长4位,小数点后最长2位

    price = models.DecimalField(max_digits=6, decimal_places=2)


    #创建书的出版社信息,其与出版社的外键关系为一对多,所以用外键

    publish = models.ForeignKey(Publish)


    #创建书的出版日期,类型为日期

    publication_date = models.DateField()


    #创建书的类型信息,为字符串类型,最长为20

    classification=models.CharField(max_length=20)


    #创建书的作者信息,书籍与作者的关系为多对多,所以使用many-to-many

    authors = models.ManyToManyField("Author")

1、增

1.1一对一信息的创建

a、使用create方式

方式一: Publish.objects.create("name"="人民出版社",city="北京"}

方式二: Publish.objects.create(**{"name":"文艺出版社","city":"上海"}}

b、使用save方式

方式一:

book1=Book(title="python",price="88",publish_id="1",publication_date="2017-06-18")

book1.save()

方式二:

author1=Author(name="jerry")

author1.save()

1.2一对多的信息的创建(Foreignkey)

方式一:

#获取出版社对象

publish_obj=Publish.objects.get(id=4) 

#将出版社的对象绑定到书籍的记录中

Book.objects.create(

    title="python",

    price=48.00,

    publication_date="2017-07-12",

    publish=publish_obj,

方式二:

#直接把出版社的id号插入到书籍的记录中

Book.objects.create(

    title="python",

    price=48.00,

    publish_id=2,

    publication_date="2017-06-18",

)

1.3多对多信息的创建(ManyToManyField())

a、为一本书添加多个作者

author1=Author.objects.get(id=1)#获取id号为1的作者对象

author2=Author.objects.filter(name="tom")#获取名字为"tom"的作者对象

book1=Book.objects.get(id=2)#获取id号为2的书籍对象

book1.authors.add(author1,author2)#为书籍对象添加多个作者对象

也可以用这种方式:

book1.authors.add(*[author1,author2])#为书籍对象添加作者对象的列表

book1.authors.remove(*[author1,author2])#删除指定书籍的所有作者

b、为一个作者添加多本书

author_obj = Author.objects.filter(name="jerry")#获取名字为"jerry"的作者对象

book_obj=Book.objects.filter(id__gt=3)#获取id大于3的书籍对象集合

author_obj.book_set.add(*book_obj)#为作者对象添加书籍对象集合

author_obj.book_set.remove(*book_obj)#删除指定作者对象所有的书籍

使用models.ManyToManyField()会自动创建第三张表

1.4手动创建多对多的作者与书籍信息表

class Book2Author(models.Models):

    author=models.ForeignKey("Author")#为作者指定Author这张表做为外键

    book=models.ForeignKey("Book")#为书籍指定Book这张表做为外键

author_obj=models.Author.objects.filter(id=3)[0]#获取Author表中id为3的作者对象

book_obj=models.Book.objects.filter(id=4)[0]#获取Book表中id为4的书籍对象

方式一:

obj1=Book2Author.objects.create(author=author_obj,book=book_obj)

obj1.save()

方式二:

obj2=Book2Author(author=author_obj,book=book_obj)

obj2.save()

2、删

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

3、改

3.1使用save方法将所有属性重新设定一遍,效率低

author1=Author.objects.get(id=3)#获取id为3的作者对象

author1.name="jobs"#修改作者对象的名字

author1.save()#把更改写入数据库

3.2使用update方法直接设置对就的属性

Publish.objects.filter(id=2).update(name="北京出版社")

注意:update()是QuerySet对象的一个方法,get返回的是一个model对象,其没有update方法.

filter返回的是一个QuerySet对象,filter里可以设定多个过滤条件

4、查

查询数据使用QuerySet API。 QuerySet是惰性执行的,创建Query Set不会访问数据库,只有在访问具体查询结果的时候才会访问数据库。

4.1查询方法:

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

all()                      查询所有结果

get(**kwargs)              返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都是报错

values(*field)              返回一个ValueQuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列

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

order by(*field)            对查询结果排序

reverse()                  对查询结果反向排序

distinct()                  从返回结果中剔除重复记录

values_list(*field)        与values()非常相似,返回一个元组序列,values返回一个字典序列

count()                    返回数据库中匹配的记录的数量

first()                    返回数据库中匹配的对象的第一个对象

last()                      返回数据库中匹配的对象的最后一个对象

exists()                    判断一个对象集合中是否包含指定对象,包含返回True,不包含返回False

exclude()            排除满足条件的对象

annotate()            使用聚合函数

dates()                根据日期获取查询集

datetimes()            根据时间获取查询集

none()                创建空的查询集

union()                并集

intersection()        交集

difference()        差集

select_related()    附带查询关联对象

prefetch_related()    预先查询

extra()                附加SQL查询

defer()                不加载指定字段

only()                只加载指定的字段

using()                选择数据库

select_for_update()    锁住选择的对象,直到事务结束。

raw()                接收一个原始的SQL查询

1.filter():

    filter(**kwargs)

    返回满足查询参数的对象集合。

    查找的参数(**kwargs)应该满足下文字段查找中的格式。多个参数之间是和AND的关系。

    Student.objects.filter(age__lt=10)#查询满足年龄小于10岁的所有学生对象

2.exclude():

    exclude(**kwargs)

    返回一个新的QuerySet,它包含不满足给定的查找参数的对象

    Student.objects.exclude(age__gt=20, name='lin')#排除所有年龄大于20岁且名字为“lin”的学员集

3.annotate():

    nnotate(args, *kwargs)

    使用提供的聚合表达式查询对象。

    表达式可以是简单的值、对模型(或任何关联模型)上的字段的引用或者聚合表达式(平均值、总和等)。

    annotate()的每个参数都是一个annotation,它将添加到返回的QuerySet每个对象中。

    关键字参数指定的Annotation将使用关键字作为Annotation 的别名。 匿名参数的别名将基于聚合函数的名称和模型的字段生成。 只有引用单个字段的聚合表达式才可以使用匿名参数。 其它所有形式都必须用关键字参数。

    例如,如果正在操作一个Blog列表,你可能想知道每个Blog有多少Entry:

    >>> from django.db.models import Count

    >>> q = Blog.objects.annotate(Count('entry'))

    # The name of the first blog

    >>> q[0].name

    'Blogasaurus'

    # The number of entries on the first blog

    >>> q[0].entry__count

    42

4.order_by():

    order_by(*fields)

    默认情况下,根据模型的Meta类中的ordering属性对QuerySet中的对象进行排序

    Student.objects.filter(school="阳关小学").order_by('-age', 'name')

    上面的结果将按照age降序排序,然后再按照name升序排序。"-age"前面的负号表示降序顺序。 升序是默认的。 要随机排序,使用"?",如下所示:

    Student.objects.order_by('?')

5. reverse():

    reverse()    

    反向排序QuerySet中返回的元素。 第二次调用reverse()将恢复到原有的排序。    

    如要获取QuerySet中最后五个元素,可以这样做:   

    my_queryset.reverse()[:5]   

    这与Python直接使用负索引有点不一样。 Django不支持负索引。

6.distinct():

    distinct(*fields)

    去除查询结果中重复的行。 

    默认情况下,QuerySet不会去除重复的行。当查询跨越多张表的数据时,QuerySet可能得到重复的结果,这时候可以使用distinct()进行去重。

7. values():

    values(fields, *expressions)    

    返回一个包含数据的字典的queryset,而不是模型实例。    

    每个字典表示一个对象,键对应于模型对象的属性名称。如:    

    # 列表中包含的是Student对象

    >>> Student.objects.filter(name__startswith='Lin')

    <QuerySet [<Student: Lin Student>]>    

    # 列表中包含的是数据字典

    >>> Student.objects.filter(name__startswith='Lin').values()

    <QuerySet [{'id': 1, 'name': 'Linxiao', 'age': 20}]>    

    另外该方法接收可选的位置参数*fields,它指定values()应该限制哪些字段。如果指定字段,每个字典将只包含指定的字段的键/值。如果没有指定字段,每个字典将包含数据库表中所有字段的键和值。如下:

    >>> Student.objects.filter(name__startswith='Lin').values()

    <QuerySet [{'id': 1, 'name': 'Linxiao', 'age': 20}]>

    >>> Blog.objects.values('id', 'name')

    <QuerySet [{'id': 1, 'name': 'Linxiao'}]>

8.values_list():

    values_list(*fields, flat=False)    

    与values()类似,只是在迭代时返回的是元组而不是字典。每个元组包含传递给values_list()调用的相应字段或表达式的值,因此第一个项目是第一个字段等。 像这样:

    >>> Student.objects.values_list('id', 'name')

获取数据表的全部数据记录:

Account.objects.all()

返回值可以进行切片,但不支持负索引。或者使用:

Account.objects.get(field_name=val)

示例:

Account.objects.get(account_name='john')

或者使用过滤器查询多条记录:

    Account.objects.filter(accounnt_name=val)

    严格等于

    Account.objects.filter(account_name__iexact=val)

    忽略大小写

    Account.objects.filter(account_name__contains=val)

    名称中包含val

    Account.objects.filter(account_name__icontains=val)

    忽略大小写,包含

    Account.objects.filter(account_name__regex=val)

    正则表达式

    Account.objects.filter(account_name__iregex=val)

    正则表达式,忽略大小写

与filter相反exclude用于返回不满足条件的查询结果。

Account.objects.exclude(account_name__contains=val)

filter与exclude可以进行链式查询

Account.objects.exclude(account_name__contains='john').exlucde(balance=0)

对于查询结果可以使用distinct()去重或者使用order_by(field)进行排序。

Account.objects.filter(account_name__regex=val).distinct()

Account.objects.filter(account_name__regex=val).oreder_by('balance')

使用reverse()方法可以反转结果集中的元素顺序,调用两次将会恢复原顺序。

从SQL 的角度,QuerySet和SELECT 语句等价,过滤器是像WHERE 和LIMIT 一样的限制子句。

like:

    __exact        精确等于      like 'aaa'

    __iexact      精确等于      忽略大小写 ilike 'aaa'

    __contains    包含          like '%aaa%'

    __icontains    包含,忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。

in:

    __in


    查询在某一范围的书

    Book.objects.filter(publish__in=[10, 20, 30])

is null / is not null:

    __isnull  判空


    Book.objects.filter(name__isnull=True)    // 查询用户名为空的书

    Publish.objects.filter(name__isnull=False)  // 查询用户名不为空的书

不等于/不包含于:

    Book.objects.filter().excute(publishe=10)    // 查询出版社不为10的书

    Book.objects.filter().excute(publish__in=[10, 20])  // 查询出版社不在 [10, 20] 的书

其他常用模糊查询:

    __startswith 以…开头

    __istartswith 以…开头 忽略大小写

    __endswith 以…结尾

    __iendswith 以…结尾,忽略大小写

    __range 在…范围内

    __year 日期字段的年份

    __month 日期字段的月份

    __day 日期字段的日

4.2双下划线(__)查询

a、双下划线(__)之单表条件查询

例子:

table1.objects.filter(id__lt=10,id__gt=1)#获取id小于10,且大于1的记录

table1.objects.filter(id__in=[11,22,33,44])#获取id在[11,22,33,44]中的记录

table1.objects.exclude(id__in=[11,22,33,44])#获取id不在[11,22,33,44]中的记录

table1.objects.filter(name__contains="content1")#获取name中包含有"contents"的记录(区分大小写)

table1.objects.filter(name__icontains="content1")#获取name中包含有"content1"的记录(不区分大小写)

table1.objects.filter(id__range=[1,4])#获取id在1到4(不包含4)之间的的记录

b、双下划线(__)之多表条件查询

正向查找(条件)之一对一查询

#查询书名为"python"的书的id号

res3=Book.objects.filter(title="python").values("id")

print(res3)

正向查找(条件)之一对多查询

#查询书名为"python"的书对应的出版社的地址

res4=Book.objects.filter(title="python").values("publisher__city")

print(res4)

#查询"aaa"作者所写的所有的书的名字

res5=Book.objects.filter(author__name="aaa").values("title")

print(res5)

#查询"aaa"作者所写的所有的书的名字(与上面的用法没区别)

res6=Book.objects.filter(author__name="aaa").values("title")

print(res6)

反向查找之一对多查询

#查询出版了书名为"python"这本书的出版社的名字

res7=Publisher.objects.filter(book__title="python").values("name")

print(res7)

#查询写了书名为"python"的作者的名字

res8=Publisher.objects.filter(book__title="python").values("book__authors")

print(res8)

反向查找之多对多查询

#查询所写的书名为"python"的作者的名字

res9=Author.objects.filter(bool__title="python").values("name")

print(res9)

条件查询即与对象查询对应,是指filter,values等方法中的通过__来明确查询条件

4.3F查询和Q查询

F查询专门取对象中某列值的操作,F的作用:用来批量修改数据的

#导入F

from django.db.models import F

#把table1表中的num列中的每一个值在的基础上加10

table1.objects.all().update(num=F("num")+10)

Q构建搜索条件, Q的作用:Q是用来做条件查询的

#导入Q

from django.db.models import Q

Q对象可以对关键字参数进行封装,从而更好的应用多个查询

#查询table2表中以"aaa"开头的所有的title列

q1=table2.objects.filter(Q(title__startswith="aaa")).all()

print(q1)

Q对象可以组合使用&,|操作符,当一个操作符是用于两个Q对象时,会产生一个新的Q对象

#查找以"aaa"开头,或者以"bbb"结尾的所有title

Q(title__startswith="aaa") | Q(title__endswith="bbb")

Q对象可以用"~"操作符放在表达式前面表示否定,也可允许否定与不否定形式的组合

#查找以"aaa"开头,且不以"bbb"结尾的所有title

Q(title__startswith="aaa") & ~Q(title__endswith="bbb")

Q对象可以与关键字参数查询一起使用,Q对象放在关键字查询参数的前面

查询条件:

#查找以"aaa"开头,以"bbb"结尾的title且书的id号大于4的记录

Q(title__startswith="aaa") | Q(title__endswith="bbb"),book_id__gt=4

九、实例

1、Django的ORM中如何判断查询结果是否为空,判断django中的orm为空

result= Booking.objects.filter()

方法一 .exists()

if result.exists():

    print "QuerySet has Data"

else:

    print "QuerySet is empty"

方法二 .count()==0

if result.count() == 0:

    print "empty"

方法三

if result:

    print "QuerySet has Data"

else:

    print "QuerySet is empty"

总结:

QuerySet.exists() > QuerySet.count()==0 > QuerySet

2、模板中显示数据库内容的方法

 a、创建数据库

from django.db import models

from django.db import models

class Business(models.Model):

    caption = models.CharField(max_length=32)

    code = models.CharField(max_length=32)

class Host(models.Model):

    nid = models.AutoField(primary_key=True)

    hostname = models.CharField(max_length=32,db_index=True)

    ip = models.GenericIPAddressField(protocol='both',db_index=True)

    port = models.IntegerField()

    business = models.ForeignKey(to='Business',to_field='id',on_delete=models.CASCADE)

business.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

</head>

<body>

    <h1>业务线列表(对象)</h1>

    <ul>

        {% for row in v1 %}

            <li>{{ row.id }}-{{ row.caption }}-{{ row.code }}</li>

        {% endfor %}

    </ul>

    <h1>业务线列表(字典)</h1>

    <ul>

        {% for row2 in v2 %}

            <li>{{ row2.id }}-{{ row2.caption }}</li>

        {% endfor %}

    </ul>

</body>

</html>

host.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

</head>

<body>

    <h1>主机列表(对象)</h1>

    <table border="1">

        <tread>

            <tr>

                <th>主机ID</th>

                <th>IP</th>

                <th>端口</th>

                <th>业务线名称</th>

            </tr>

        </tread>

        <tbody>

            {% for row in v1 %}

                <tr>

                    <td>{{ row.hostname }}</td>

                    <td>{{ row.ip }}</td>

                    <td>{{ row.port }}</td>

                    <td>{{ row.business.caption }}</td>

                </tr>

            {% endfor %}

        </tbody>

    </table>

    <h1>主机列表(字典)</h1>

    <table border="1">

        <tread>

            <tr>

                <th>主机ID</th>

                <th>主机名</th>

                <th>业务线ID</th>

                <th>业务线名称</th>

            </tr>

        </tread>

        <tbody>

            {% for row in v2 %}

                <tr>

                    <td>{{ row.nid }}</td>

                    <td>{{ row.hostname }}</td>

                    <td>{{ row.business__id }}</td>

                    <td>{{ row.business__caption }}</td>

                </tr>

            {% endfor %}

        </tbody>

    </table>

    <h1>主机列表(元祖)</h1>

    <table border="1">

        <tread>

            <tr>

                <th>主机ID</th>

                <th>主机名</th>

                <th>业务线ID</th>

                <th>业务线名称</th>

            </tr>

        </tread>

        <tbody>

            {% for row in v3 %}

                <tr>

                    <td>{{ row.0 }}</td>

                    <td>{{ row.1 }}</td>

                    <td>{{ row.2 }}</td>

                    <td>{{ row.3 }}</td>

                </tr>

            {% endfor %}

        </tbody>

    </table>

</body>

</html>

views.py

from django.shortcuts import render,HttpResponse

from app01 import models

def business(request):

    # 第一种方式(是个对象)

    v1 = models.Business.objects.all()

    # 第二种方式,只取id和caption(是个字典)

    v2 = models.Business.objects.all().values('id','caption')

    return render(request,'business.html',{'v1':v1,'v2':v2})

def host(request):

    #总共三种方式,对象,字典,列表

    v1 = models.Host.objects.all()

    v2 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','business__id','business__caption')

    v3 = models.Host.objects.filter(nid__gt=0).values_list('nid','hostname','business__id','business__caption')

    return render(request,'host.html',{'v1':v1,'v2':v2,'v3':v3})

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容