2016-11-28 51 views
1

我正在處理一個用戶/組API(對大多數事情使用django-rest-framework),並且掛上了作爲每個對象一部分的設置字典。如何創建一個Django模型字段,它是幾個查詢的聯合,以便實現覆蓋字段?

我的基本模式是這樣的:

class Group(models.Model): 
    name = models.CharField(null=False, unique=True) 
    is_active = models.BooleanField(null=False, default=True) 
    description = models.CharField(max_length=512) 

class User(models.Model): 
    name = models.CharField(null=False, unique=True, db_index=True) 
    group = models.ForeignKey('Group', related_name='users') 
    is_active = models.BooleanField(null=False, default=True) 

的JSON返回簡單(省略意見,唯一值得注意的事情是,我不使用的用戶領域的PrimaryKeyRelatedField)。

組:

{ 
    "id": 1, 
    "name": "Basic Group", 
    "is_active": true, 
    "description": "Just a simple group", 
    "users": [ 
     "Test User 1", 
     "Test User 2" 
    ] 
} 

用戶:

{ 
    "id": 1, 
    "name": "Test User 1", 
    "group": 1, 
    "is_active": true 
}, { 
    "id": 2, 
    "name": "Test User 2", 
    "group": 1, 
    "is_active": true 
} 

我想通過具有兩個組和用戶對象類型,被覆蓋了「設置」字典,以提高這一點。也就是說,組的設置字典將包括所有全局設置,除非在該組上設置了具有相同名稱的設置。同樣,除非已爲用戶設置了具有相同名稱的設置,否則用戶的設置字典將具有所有全局設置,並被組設置覆蓋。

想象大約如下的結構如下:

name  | value  | group | user 
---  | ---  | --- | --- 
setting 1 | value 1 |  | 
setting 1 | value 2 | 1  | 
setting 2 | SKFJDL | 1  | 
setting 2 | ABCD  | 1  | 2 

這將導致以下JSON返回第1組:

{ 
    "id": 1, 
    "name": "Basic Group", 
    "is_active": true, 
    "description": "Just a simple group", 
    "users": [ 
     "Test User 1", 
     "Test User 2" 
    ], 
    "settings": { 
     "setting 1": "value 2", 
     "setting 2": "SKFJDL" 
    } 
} 

對於用戶1,設置字典將如下所示:

"settings": { 
    "setting 1": "value 2", 
    "setting 2": "SKFJDL" 
} 

對於用戶2,它看起來像:

"settings": { 
    "setting 1": "value 2", 
    "setting 2": "ABCD" 
} 

這給我留下了兩個問題。

問題1:使我獲得所需輸出的SQL相對複雜。基本上是:

SELECT DISTINCT(name) * 
FROM (
    (SELECT * FROM setting WHERE group IS NULL AND user IS NULL) 
    UNION ALL 
    (SELECT * FROM setting WHERE group = 1 AND user IS NULL) 
    UNION ALL 
    (SELECT * FROM setting WHERE group = 1 AND user = 2)) 
    AS temp 

我想我可能將不得不吮吸它,做一些自定義查詢的寫作,而不是依賴於任何Django的ORM爲我提供開箱即用的......但我對於這件事我感到很高興。

問題2(大):在赫克實際上,我怎麼做?一個ForeignKey關係似乎沒有給我一種方法來定製在進行反向查找時被拉入的字段,至少不是我在一天左右就能找到的任何方式找到的。我有一種感覺,custom reverse manager幾乎肯定是我正在尋找的東西,但我實際上並沒有想到如何在模型的上下文中使用它,尤其是具有由DRF自動生成的下游視圖的模型。

任何幫助表示讚賞!

回答

0

我對此迅速採取了措施。在github上扔了一個非常基本的Django項目(使用testuser | testpass登錄管理員): https://github.com/junctionapps/so40854954

基本上,三個過濾器幾乎完全使用你在那裏的sql。然後用數據填充字典(或其他),根據優先級進行替換。所以把默認的(空/空),然後分組,然後用戶。我將模型CustomUser,CustomGroup和CustomSettings重命名爲不碰撞保留的Django對象。

存儲在模型中的設置(我認爲這是你的意思,我可能誤解了這一點)。

class CustomSettings(models.Model): 
    name = models.CharField(max_length=64) 
    value = models.CharField(max_length=64) 
    group = models.ForeignKey(CustomGroup, null=True, blank=True) 
    user = models.ForeignKey(CustomUser, null=True, blank=True) 

,並在視圖中類似如下(不完全滿意,與三個環路的一部分,有可能是一個巧妙方式)。

if user_id: 
    # a place to store the end values 
    custom_settings = {} 

    # get the user's group 
    custom_user = get_object_or_404(CustomUser, id=user_id) 

    # get the default values 
    # see some tips at http://stackoverflow.com/a/844572/4872140 
    default_settings = CustomSettings.objects.filter(group__isnull=True, 
                user__isnull=True) 
    # get the group values 
    group_settings = CustomSettings.objects.filter(group=custom_user.group, 
                user__isnull=True) 
    # get the user values 
    user_settings = CustomSettings.objects.filter(group=custom_user.group, 
                user=custom_user) 
    # probably a more 'pythonic' way to conflate, however: 
    # set the values: 
    for s in default_settings: 
     custom_settings[s.name] = s.value 
    for s in group_settings: 
     custom_settings[s.name] = s.value 
    for s in user_settings: 
     custom_settings[s.name] = s.value 

然後custom_settings應該在某些序列化程序中具有您想要在DRF中使用的值。

相關問題