亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Django ORM層日志的兩種實(shí)現(xiàn)方式

CKJOKER / 3072人閱讀

摘要:最近開發(fā)一個(gè)內(nèi)部的記錄系統(tǒng)其中有一個(gè)需求要求將所有數(shù)據(jù)庫(kù)操作記錄下來(lái)為此想了一些方案記錄一下思路演化這個(gè)需求出來(lái)的一瞬間我就否定了在業(yè)務(wù)邏輯層保存操作記錄的方案我認(rèn)為這樣耦合度比較高成本也太高代碼也會(huì)大量重復(fù)的操作中刪除操作會(huì)調(diào)用的方法增改

最近開發(fā)一個(gè)內(nèi)部的記錄系統(tǒng),其中有一個(gè)需求要求將所有數(shù)據(jù)庫(kù)操作記錄下來(lái),為此想了一些方案.記錄一下.

思路演化

這個(gè)需求出來(lái)的一瞬間我就否定了在業(yè)務(wù)邏輯層保存操作記錄的方案,我認(rèn)為這樣耦合度比較高,成本也太高. 代碼也會(huì)大量重復(fù).
Django的ORM操作中,刪除操作會(huì)調(diào)用models.Modeldelete方法,增改會(huì)調(diào)用save方法,修改這些方法能夠覆蓋除了查詢以外的所有ORM操作(查詢暫時(shí)跳過),修改savedelete的方法無(wú)外乎就是類繼承,裝飾器.

我也考慮了使用signal系統(tǒng),但是這樣依然要在業(yè)務(wù)邏輯層處理發(fā)送信號(hào)的問題,感覺更復(fù)雜一些(比如對(duì)照修改前后的數(shù)據(jù)不如直接在Model中操作方便,Model的save方法在存盤之前,self是待存數(shù)據(jù),根據(jù)self.pk從db中取出數(shù)據(jù)是舊數(shù)據(jù)方便對(duì)比.如果要在signal中拿到兩份數(shù)據(jù)比較麻煩,可能需要在業(yè)務(wù)層做更多的斟酌).

繼承

我首先嘗試了類繼承的方法

class TopSecret(models.Model):

    class Meta:
        db_table = "絕密文件"

    name = models.CharField(max_length=32)
    content = models.TextField()

這是原始的model,我改寫成了如下

class Logger(models.Model):

    def save(self, *args, **kwargs):
        print("Do some log")
        super(Logger, self).save(*args, **kwargs)


class TopSecret(Logger):

    class Meta:
        db_table = "絕密文件"

    name = models.CharField(max_length=32)
    content = models.TextField()

我覺得這樣應(yīng)該可以的.然而在調(diào)用save()方法時(shí)出現(xiàn)錯(cuò)誤OperationalError: no such table: logged_logger,可以看出,我在原始model定義的Meta信息失效了,框架轉(zhuǎn)而在Logger類中尋找Meta,未找到的情況下使用了框架的默認(rèn)值.
我嘗試將super(Logger, self).save(*args, **kwargs)改成super(self.__class__, self).save(*args, **kwargs),這樣super又成了調(diào)用TopSecret父類Logger的save(),如此反復(fù)形成了循環(huán)調(diào)用報(bào)錯(cuò).
我仔細(xì)想了一下,Model類尋找Meta的邏輯是肯定不去修改的,修改這個(gè)顯得不劃算,也違反了不隨便改框架的基本原則,當(dāng)時(shí)在此我轉(zhuǎn)向了裝飾器方法,而放棄了類繼承.
今天我寫這篇文章的時(shí)候隱約想起一件事情,Model好像有一個(gè)abstract的屬性,果然如此.定義這個(gè)Meta信息之后,框架會(huì)認(rèn)為這是一個(gè)抽象類,而不是數(shù)據(jù)模型,完美解決了問題.

class Logger(models.Model):

    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        print("Do some log")
        super(Logger, self).save(*args, **kwargs)


class TopSecret(Logger):

    class Meta:
        db_table = "絕密文件"

    name = models.CharField(max_length=32)
    content = models.TextField()
In [1]: from logged.models import TopSecret

In [2]: obj = TopSecret(name="123",content="測(cè)試內(nèi)容")

In [3]: obj.save()
Do some log

In [4]:

在想起abstract之前我還想過其他的方案,比如多帶帶增加log類.這樣可以避免在Model父類和子類之間增加一層,解決了Meta信息的問題.

class Logger(object):

    def save(self, *args, **kwargs):
        print("Do some log")
        models.Model.save(self, *args, **kwargs)


class TopSecret(Logger, models.Model):

    class Meta:
        db_table = "絕密文件"

    name = models.CharField(max_length=32)
    content = models.TextField()

這樣做有好處也有壞處,好處是Logger不再繼承Model,算是解耦合增加了代碼的可讀性,壞處是我看Logger那里調(diào)用save方法的方式比較別扭,將實(shí)例方法當(dāng)做靜態(tài)方法調(diào)用手動(dòng)傳入實(shí)例有一種很違和的感覺,不過總算是能工作了.

裝飾器

裝飾器是當(dāng)時(shí)類繼承沒有成功,我走的另一條路.

首先因?yàn)槲覀兊难b飾器不可能裝到框架代碼里去,只能在我們定義的Model模型上使用類裝飾器.當(dāng)時(shí)我的實(shí)現(xiàn)是使用django自帶的method_decorator.這個(gè)函數(shù)可以將函數(shù)裝飾器變成方法裝飾器,裝飾到一個(gè)類的方法上,比較常見的用法是為dispatch方法去除csrf保護(hù).
但是使用這個(gè)方法會(huì)有一個(gè)問題,那就是寫一個(gè)函數(shù)裝飾器本身是不會(huì)取到類的實(shí)例本身的.還需要為save方法傳入類的實(shí)例本身才能取到類數(shù)據(jù)進(jìn)行日志操作,不行,不夠優(yōu)雅.

怎么辦?只能直接寫類裝飾器了.

之前沒寫過類裝飾器,其實(shí)類裝飾器和普通函數(shù)裝飾器一樣,思路和繼承的寫法也是一樣的.

def cbd_logger(obj):
    if hasattr(obj, "save"):
        save = obj.save 
        def _save(self, *args, **kwargs):
            print "do some log %s" % self.name
            return save(self, *args, **kwargs)
        setattr(obj, "save", _save)
    return obj


@cbd_logger
class TopSecret(models.Model):

    class Meta:
        db_table = "絕密文件"

    name = models.CharField(max_length=32)
    content = models.TextField()
值得注意的是,_save中不能直接return obj.save(self,*args,**kwargs),這么做會(huì)導(dǎo)致運(yùn)行時(shí)調(diào)用當(dāng)前實(shí)例的save方法,也就是_save本身,搞成無(wú)限遞歸  
我們分別打印一下cbd_logger下這些方法的id看一下
>>>obj.save()
save 90220624
obj.save 106285376
self.save 106285376
在裝飾后的save方法中,obj.save的地址和self.save的地址是一樣的,這個(gè)save已經(jīng)被裝飾器修改過了.
和下面這個(gè)閉包的原理差不多.
>>>fs = [lambda i:i*2 for i in range(3)]
>>>for f in fs:
...    print(f(1))
2
2
2
總結(jié)

類的繼承方法和裝飾器方法實(shí)際上都在做同一件事,就是在框架本身的savedelete方法外層增加日志操作.但是需求還沒有實(shí)現(xiàn),我們保存日志的時(shí)候,不只要知道數(shù)據(jù)變動(dòng),還要知道這些操作是誰(shuí)做的,如何優(yōu)雅的將這些信息傳遞給負(fù)責(zé)記錄的代碼?
目前我們選擇的是在操作Model時(shí),約定不使用objects,只使用TopSecret(name="",content="").save(request)這種方法,將request傳遞給save,再由之前實(shí)現(xiàn)的logger從request取出必要的信息進(jìn)行記錄,比如IP,User,甚至UA等等.這么做業(yè)務(wù)層需要多傳一個(gè)參數(shù),還是有了感知,但是也是沒辦法的事.對(duì)現(xiàn)有代碼的改動(dòng)也是我知道的辦法中最小的.
這套下來(lái)感覺django文檔中的給出的信息很充分,實(shí)現(xiàn)這個(gè)需求并不難.一開始出現(xiàn)的問題還是因?yàn)閷?duì)文檔印象不夠深,沒有第一時(shí)間解決問題.

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/41766.html

相關(guān)文章

  • 通過demo學(xué)習(xí)OpenStack開發(fā)所需的基礎(chǔ)知識(shí) -- 數(shù)據(jù)庫(kù)(1)

    摘要:另外,項(xiàng)目在單元測(cè)試中使用的是的內(nèi)存數(shù)據(jù)庫(kù),這樣開發(fā)者運(yùn)行單元測(cè)試的時(shí)候不需要安裝和配置復(fù)雜的數(shù)據(jù)庫(kù),只要安裝好就可以了。而且,數(shù)據(jù)庫(kù)是保存在內(nèi)存中的,會(huì)提高單元測(cè)試的速度。是實(shí)現(xiàn)層的基礎(chǔ)。項(xiàng)目一般會(huì)使用數(shù)據(jù)庫(kù)來(lái)運(yùn)行單元測(cè)試。 OpenStack中的關(guān)系型數(shù)據(jù)庫(kù)應(yīng)用 OpenStack中的數(shù)據(jù)庫(kù)應(yīng)用主要是關(guān)系型數(shù)據(jù)庫(kù),主要使用的是MySQL數(shù)據(jù)庫(kù)。當(dāng)然也有一些NoSQL的應(yīng)用,比如Ce...

    warnerwu 評(píng)論0 收藏0
  • Django Model View Template 之間的簡(jiǎn)單交互 (二)

    摘要:當(dāng)然還有其他高級(jí)的使用,日后再說完整的用戶名郵箱聯(lián)系地址留言信息用戶留言信息使用之前已經(jīng)定義好了數(shù)據(jù)模型的字段元數(shù)據(jù)方法等。 前言 接續(xù)前文,上一篇文章主要涉及了 Django 項(xiàng)目的基礎(chǔ)配置等,這篇主要涉及數(shù)據(jù)庫(kù)相關(guān)的 ORM ,也就是 Django 中的 Model 的使用,MVT 三層之間的交互 教程基本都是東拼西湊的,防止有些東西表述不準(zhǔn)確,因?yàn)槲抑皩?JavaScript ...

    Coding01 評(píng)論0 收藏0
  • Django ORM

    摘要:對(duì)象關(guān)系映射,簡(jiǎn)稱模式是一種為了解決面向?qū)ο笈c關(guān)系數(shù)據(jù)庫(kù)存在的互不匹配的現(xiàn)象的技術(shù)。在業(yè)務(wù)邏輯層和數(shù)據(jù)庫(kù)層之間充當(dāng)了橋梁的作用。每個(gè)字段被指定為一個(gè)類屬性,每個(gè)屬性映射到一個(gè)數(shù)據(jù)庫(kù)列。字符類型,必須提供參數(shù),表示字符長(zhǎng)度。 對(duì)象關(guān)系映射(Object Relational Mapping,簡(jiǎn)稱ORM)模式是一種為了解決面向?qū)ο笈c關(guān)系數(shù)據(jù)庫(kù)存在的互不匹配的現(xiàn)象的技術(shù)。 簡(jiǎn)單的說,ORM是...

    BlackHole1 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

CKJOKER

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<