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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM