zoukankan      html  css  js  c++  java
  • 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:Python27libsite-packagesdjango-1.10.8-py2.7.eggdjangodbmodelsmanager.py", line 85, in manager_method
        return getattr(self.get_queryset(), name)(*args, **kwargs)
      File "C:Python27libsite-packagesdjango-1.10.8-py2.7.eggdjangodbmodelsquery.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:Python27libsite-packagesdjango-1.10.8-py2.7.eggdjangodbmodelsmanager.py", line 85, in manager_method
          return getattr(self.get_queryset(), name)(*args, **kwargs)
        File "C:Python27libsite-packagesdjango-1.10.8-py2.7.eggdjangodbmodelsquery.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:Python27libsite-packagesdjango-1.10.8-py2.7.eggdjangodbmodelsfields
    elated_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)
  • 相关阅读:
    牛客寒假5-D.炫酷路途
    牛客寒假5-A.炫酷双截棍
    HDU-1024
    牛客寒假6-J.迷宫
    牛客寒假6-G.区间或和
    牛客寒假6-E.海啸
    【BZOJ3456】—城市规划(生成函数+多项式求逆)
    【BZOJ3456】—城市规划(生成函数+多项式求逆)
    【TopCoder SRM548 Div1】—KingdomAndCities(组合数学)
    【TopCoder SRM548 Div1】—KingdomAndCities(组合数学)
  • 原文地址:https://www.cnblogs.com/wxzhe/p/10306580.html
Copyright © 2011-2022 走看看