django模型的crud操作

一个建立好的模型,django会生成一套完整的API,以便对对象进行crud操作,下面就详细介绍crud操作。

 先说一下操作环境: python2.7, django1.11.8, win7系统,借助于pycharm工具。

from django.db import models

# Create your models here.


class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __unicode__(self):              # __self__ on Python 3
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=200)
    email = models.EmailField()

    def __unicode__(self):              # __self__ on Python 3
        return self.name


class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __unicode__(self):              # __self__ on Python 3
        return self.headline

创建对象

Django 使用一种直观的方式把数据库表中的数据表示成Python 对象:一个模型类代表数据库中的一个表,一个模型类的实例代表这个数据库表中的一条特定的记录。

首先讲述单一对象(也就是不跨模型的crud操作)。

增加对象数据

使用关键字参数实例化模型实例来创建一个对象,然后调用save() 把它保存到数据库中。

>>> from mysite import models                #首先导入models模块

#第一种创建一个Blog对象,传参,调用save函数,需要注意只有在调用save函数的时候,才会与数据库交互。
>>> b = models.Blog(name="first", tagline="one") >>> b.save()

#第二种: 创建一个objects对象直接调用create方法,保存数据
>>> models.Blog.objects.create(name="second", tagline="two") <Blog: second>
#第三种方法和第一种差不多,只不过把传参过程单独写了出来 >>> bg = models.Blog() >>> bg.name = "third" >>> bg.tagline = "three" >>> bg.save()

#第四种:会尝试着先获取数据,若是数据不存在,则再创建。返回结果是一个布尔值,创建成功返回True,若是值已经存在则返回的是False。
>>> models.Blog.objects.get_or_create(name="fourth", tagline="four") (<Blog: fourth>, True)

#上面的四种方法都是向数据库中写入了数据,实质均是转为insert语句而已。

查看数据

获取全部的数据:

>>> models.Blog.objects.all()
<QuerySet [<Blog: first>, <Blog: second>, <Blog: third>, <Blog: fourth>, <Blog: first>, <Blog: second>]>
>>> models.Blog.objects.all()[:2] <QuerySet [<Blog: first>, <Blog: second>]>

#all():方法会获取对象中所有的数据,但是返回的结果是一个QuerySet对象。
#返回的结果是一个列表,因此支持切片操作。

过滤查询: 就像select语句一样,通常我们的查询都是有条件限制,不可能是获取全部的所有数据。

QuerySet查询有两个过滤设置:

  • filter(**kwargs):返回一个新的QuerySet,它包含满足查询参数的对象。
  • exclude(**kwargs):返回一个新的QuerySet,它包含满足查询参数的对象。
>>> models.Blog.objects.all().filter(name="first")      #返回符合条件的数据
<QuerySet [<Blog: first>, <Blog: first>]>
>>> models.Blog.objects.all().exclude(name="first")          #返回不符合条件的数据
<QuerySet [<Blog: second>, <Blog: third>, <Blog: fourth>, <Blog: second>]>

#链式过滤,先过滤出不包含name="first"的对象,然后再过滤出tagline="three"的对象
>>> models.Blog.objects.all().exclude(name="first").filter(tagline="three")
<QuerySet [<Blog: third>]>

QuerySet是惰性的,创建QuerySet对象不会造成任何数据库的访问,只有在使用这个QuerySet对象才会通过数据库访问获取数据。

get返回一个QuerySet对象:

上面的查询返回的QuerySet对象一般都不是一个结果,若是想要获取一个结果,可以使用get方法。

>>> models.Blog.objects.get(name="third")           #返回一个结果
<Blog: third>
>>> models.Blog.objects.get(name="first")           #若是查询出来的结果又多个,则get会报错
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "C:\Python27\lib\site-packages\django-1.10.8-py2.7.egg\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Python27\lib\site-packages\django-1.10.8-py2.7.egg\django\db\models\query.py", line 389, in get
    (self.model._meta.object_name, num)
MultipleObjectsReturned: get() returned more than one Blog -- it returned 2!

查询结果的values方法与value_list方法。

  • values(*fields, **expression): 正常的查询返回的是一个模型实例的可迭代对象,values返回的是一个模型字典的可迭代对象。
>>> models.Blog.objects.values()    #返回的是一个每个记录的key-value构成的字典。注意多了一个id字段,这个id是django自动创建的主键。
<QuerySet [{'tagline': u'one', u'id': 1, 'name': u'first'}, {'tagline': u'two', u'id': 2, 'name': u'second'}, {'tagline': u'three', u'id': 3, 'name': u'third'}, {'tagline': u'four', u'id': 4, 'name': u'fourth'}, {'tagline': u'one', u'id': 5, 'name': u'first'}, {'tagline': u'two', u'id': 6, 'name': u'second'}]>

>>> models.Blog.objects.values("id","name")  #fields参数,类似于select查询中要查询的字段,也就是显示指定的字段。
<QuerySet [{'id': 1, 'name': u'first'}, {'id': 2, 'name': u'second'}, {'id': 3, 'name': u'third'}, {'id': 4, 'name': u'fourth'}, {'id': 5, 'name': u'first'}, {'id': 6, 'name': u'second'}]>

values还有一个**expression参数,这是一个关键字参数,values会把关键字参数传递给annotate()方法。django1.11之后支持**expression参数。

  • values_llist(*fields, flat=False): 与values类似,只不过返回的是元组而不是字典。
    >>> models.Blog.objects.values_list()    
    <QuerySet [(1, u'first', u'one'), (2, u'second', u'two'), (3, u'third', u'three'), (4, u'fourth', u'four'), (5, u'first', u'one'), (6, u'second', u'two'), (7, u'SECOND', u'ABC')]>
    >>> models.Blog.objects.values_list("id","name")
    <QuerySet [(1, u'first'), (2, u'second'), (3, u'third'), (4, u'fourth'), (5, u'first'), (6, u'second'), (7, u'SECOND')]>

    当只查询一个字段时,设置flat为True,返回的结果不再是一个元组,而是单个值。若设置为False,则返回的仍然是元组。但是,查询有多个字段时,设置为True会报错。
    >>> models.Blog.objects.values_list("id", flat=True)
    <QuerySet [1, 2, 3, 4, 5, 6, 7]>
    >>> models.Blog.objects.values_list("id", flat=False)
    <QuerySet [(1,), (2,), (3,), (4,), (5,), (6,), (7,)]>


    >>> models.Blog.objects.values_list("id","name", flat=False)
    <QuerySet [(1, u'first'), (2, u'second'), (3, u'third'), (4, u'fourth'), (5, u'first'), (6, u'second'), (7, u'SECOND')]>
    >>> models.Blog.objects.values_list("id","name", flat=True) #报错
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "C:\Python27\lib\site-packages\django-1.10.8-py2.7.egg\django\db\models\manager.py", line 85, in manager_method
        return getattr(self.get_queryset(), name)(*args, **kwargs)
      File "C:\Python27\lib\site-packages\django-1.10.8-py2.7.egg\django\db\models\query.py", line 729, in values_list
        raise TypeError("'flat' is not valid when values_list is called with more than one field.")
    TypeError: 'flat' is not valid when values_list is called with more than one field.

     

  • 查询中的一些关键字使用以及正则表达式简单使用。
    #exact精确匹配,默认的就是这种匹配方式。
    >>> models.Blog.objects.all().filter(name="second")
    <QuerySet [<Blog: second>, <Blog: second>]>
    >>> models.Blog.objects.all().filter(name__exact="second")  #这里是双下划线
    <QuerySet [<Blog: second>, <Blog: second>]>
    
    #iexact忽略大小写
    >>> models.Blog.objects.all().filter(name__iexact="second")
    <QuerySet [<Blog: second>, <Blog: second>, <Blog: SECOND>]>
    
    #contains大小写敏感,包含关系测试;icontains大小写不敏感,不包含关系测试
    在数据库中修改数据,方便做测试。
    >>> models.Blog.objects.all().filter(name__contains="second")
    <QuerySet [<Blog: second>, <Blog: one second >]>
    >>> models.Blog.objects.all().filter(name__icontains="second")
    <QuerySet [<Blog: second>, <Blog: one second >, <Blog: one SECOND >]>
    
    
    #startwith和endwith分别表示以“xxx”开始和以“xxx”结尾。
    
    Person.objects.filter(name__regex="^abc") # 正则表达式查询
    Person.objects.filter(name__iregex="^abc")# 正则表达式不区分大小写

     

更新对象数据

更新数据和sql语句类似,查找到某一条数据更新,查找到某类型数据的集合更新。

>>> models.Blog.objects.all().filter(name__icontains="second")
<QuerySet [<Blog: second>, <Blog: one second >, <Blog: one SECOND >]>
>>> models.Blog.objects.values().filter(name="third")
<QuerySet [{'tagline': u'three', u'id': 3, 'name': u'third'}]>
>>> models.Blog.objects.values().filter(name="third").update(tagline="Fuck")           #更新一个特定的记录
1
>>> models.Blog.objects.values().filter(name="third")
<QuerySet [{'tagline': u'Fuck', u'id': 3, 'name': u'third'}]>

>>> models.Blog.objects.all().update(tagline="Wonderful")                        #批量更新,慎用!
7
>>> models.Blog.objects.values("tagline")
<QuerySet [{'tagline': u'Wonderful'}, {'tagline': u'Wonderful'}, {'tagline': u'Wonderful'}, {'tagline': u'Wonderful'}, {'tagline': u'Wonderful'}, {'tagline': u'Wonderful'}, {'tagline': u'Wonderful'}]>

 

删除数据

删除数据和更新一样,批量删除,和删除特定的数据。

>>> models.Blog.objects.all().filter(name="fourth").delete()
(1, {u'mysite.Blog': 1})

>>> models.Blog.objects.all().filter(name="first").delete()
(2, {u'mysite.Blog': 2})

django中自带的QuerySet API还是蛮多的,不太可能一一列举完成,这里给出文档连接:QuerySet API

 

跨模型操作

上面的crud操作都是针对单个模型的,下面来说明跨模型的操作。

有下面的model,我们根据下面的model来说明夸模型操作的应用。

class Business(models.Model):  # django中会默认创建主键id
    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=50, db_index=True)
    ip = models.GenericIPAddressField(protocol="IPV4")
    port = models.IntegerField()
    b = models.ForeignKey(to="Business", to_field="id")


class Application(models.Model):
    name = models.CharField(max_length=64)
    r = models.ManyToManyField("Host")

多对一关系的查询与添加:

插入外键的数据:

上面的models可知,host的字段b关联到Business中的隐藏主键(id),Business中的数据如下:

我们向host表中写入数据如下:

>>> from mysite import models
>>> h1 = models.Host()
>>> h1.hostname = "nginx-one"
>>> h1.ip = "10.0.102.110"
>>> h1.port = 80

#到这里为止一切都是美好的,然后开始向外键b写入数据。
>>> h1.b = 1
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "C:\Python27\lib\site-packages\django-1.10.8-py2.7.egg\django\db\models\fields\related_descriptors.py", line 211, in __set__
    self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "1": "Host.b" must be a "Business" instance.
因为外键b关联到Business表,因此这里报错说b必须是一个Business实例。
>>> id1 = models.Business.objects.get(caption="web")  #主机名是nginx自然归类到web中
>>> h1.b = id1
>>> h1.save()


#查看插入的数据
>>> models.Host.objects.values()
<QuerySet [{'ip': u'10.0.102.110', u'b_id': 1, 'hostname': u'nginx-one', 'port': 80, 'nid': 3}]>


#跨表查询,这个查询从子表----->父表
#这里仅查出了外键的数字值为1,因为Business中id字段值是数字,但是数字看起来没有任何的意义,我们想同时查处来,这个主机对应的caption值是多少?
>>> models.Host.objects.values("hostname","ip","port","b__caption") #注意这里的写法b后面是双下划线然后才是caption。
<QuerySet [{'b__caption': u'web', 'ip': u'10.0.102.110', 'hostname': u'nginx-one', 'port': 80}]>

#跨表查询,我们要从父表----->子表
>>> models.Business.objects.get(caption="web").host_set.values()
<QuerySet [{'ip': u'10.0.102.110', u'b_id': 1, 'hostname': u'nginx-one', 'port': 80, 'nid': 3}]>
Django默认每个主表对象都有一个外键的属性。 可以通过它来查询所有属于主表的子表信息, 查询方式:主表.子表_set(), 返回值为一个queryset对象
#在定义外键的时候也可以使用参数related_name指定这个外键关系的名字,在反向查询的时候可以直接使用这个名字。

#删除操作时根据on_delete参数的值,来确定如何删除数据。

多对多关系的操作

在上面的模型中Application应用与主机之间的关系是多对多的。上面的测试中,我们在Host表中插入了一条数据,继续再插入多条数据。

多对多关系的数据插入,分为两步。我们知道在多对多关系中,django另外创建一张表维护多对多的关系。因此插入数据时,先插入多对多的数据表,然后在插入多对多的关系表。
>>> app1 = models.Application()          #创建一个Application对象
>>> app1.name = "test_app"               #这个模型有个字段,先插入这个字段的值,然后再插入关系字段的值。
>>> app1.save()

>>> value_r = models.Host.objects.get(hostname="redis1")         #创建一个Host对象,然后把这个对象附加到app1上面。
>>> app1.r.add(value_r)

add方法可以接受多个参数,每个参数用逗号分隔,可以一次性添加多个关系。

多对多关系的查询:

#本质上是转化为一对多关系的查询。
>>> app2 = models.Application.objects.get(name="test_app") >>> app2.r.all() <QuerySet [<Host: Host object>]> >>> app2.r.values() <QuerySet [{'ip': u'10.0.104.66', u'b_id': 3, 'hostname': u'redis1', 'port': 6379, 'nid': 3}]>

#反向查询:【和上面的多对一的反向查询一样】
>>> h1 = models.Host.objects.get(hostname="redis1")
>>> h1.application_set.values()
<QuerySet [{u'id': 3, 'name': u'test_app'}]>

 

在关联对象时有几个方法可以使用:

https://yiyibooks.cn/xx/Django_1.11.6/ref/models/relations.html#django.db.models.fields.related.RelatedManager.add

add方法:

上面已经使用过了add方法:

add(*obj, bulk=True)
#添加一指定的模型对象到关联的对象集中。bulk的值请使用默认的!

create方法: 创建一个新的对象,将它保存并放在关联的对象集中。 返回新创建的对象:

>>> b = Blog.objects.get(id=1)
>>> e = b.entry_set.create(
...     headline='Hello',
...     body_text='Hi',
...     pub_date=datetime.date(2005, 1, 1)
... )

# 这里不需要调用e.save() — 它已经被保存。
# 这完全等价于下面的(不过更加简洁于):
>>> b = Blog.objects.get(id=1)
>>> e = Entry(
...     blog=b,
...     headline='Hello',
...     body_text='Hi',
...     pub_date=datetime.date(2005, 1, 1)
... )
>>> e.save(force_insert=True)

 

转载于:https://www.cnblogs.com/wxzhe/p/10306580.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值