2015-08-27 39 views
0

有沒有辦法可以子類Django ManyRelatedManager a.k.a. ManyToManyField子類Django ManyRelatedManager又名ManyToManyField

目標是在通過標記deleted=None調用ManyRelatedManager時對所有相關模型進行預過濾。如果deleted=None那麼它是有效的Model

到目前爲止,這是代碼,但它似乎並沒有工作。

class ExcludeDeletedManyToManyField(models.ManyToManyField): 

    def get_queryset(self): 
     qs = super(ExcludeDeletedManyToManyField, self).get_queryset() 
     return qs.filter(deleted__isnull=True) 


class SelfRefrencingModel(models.Model): 

    children = ExcludeDeletedManyToManyField('self', blank=True, 
     symmetrical=False, related_name='parents') 

回答

1

您可以創建SelfRefrencingModelproxy model和覆蓋默認manager。然後在ManyToManyField中使用此代理模型。

子類化ManyToManyField不會幫助您,因爲對於生成的查詢集ManyRelatedManger負責。

代理模式的方法:

from django.db import models 

class A(models.Model): 
    children = models.ManyToManyField('AProxy') 
    name = models.TextField() 
    deleted = models.NullBooleanField(null=True) 


class FilterDeletedManager(models.Manager): 
    def get_queryset(self): 
     qs = super(FilterDeletedManager, self).get_query_set() 
     return qs.filter(deleted__isnull=True) 


class AProxy(A): 
    objects = FilterDeletedManager() 
    class Meta: 
     proxy = True 

買者這種方法是,現在的Django預計,childrenAProxy實例。

所以也許更好的可讀性和可維護性的方法將是在__init__中添加另一個屬性。

from django.db import models 

class A(models.Model): 
    children = models.ManyToManyField('self') 
    name = models.TextField() 
    deleted = models.NullBooleanField(null=True) 

    def __init__(self, *args, **kwargs): 
     super(A, self).__init__(*args, **kwargs) 
     self.deleted_null_children = self.children.filter(deleted__isnull=True) 
+0

'代理Models'是在模型上定義額外的行爲,並且沒有任何字段。我不認爲這會工作....你有一個代碼示例讓這個工作? –

0

如果您的意圖是將其與Django Admin或ModelForm一起使用;您不需要子類ManyToManyField。見django documentation

class SelfRefrencingModel(models.Model): 

    children = models.ManyToManyField('self', blank=True, symmetrical=False, 
     related_name='parents', limit_choices_to={'deleted': False})) 

注:如果deletedBooleanField它必須是TrueFalse。它不能是None/NULL

beezz's使用代理模型的想法也是一個好主意。

我有時做的是自定義默認經理
class MyModelManager(models.Manager): 
    use_for_related_fields = True 

    def get_queryset(self): 
     qs = super(MyModelManager, self).get_queryset() 
     return qs.filter(deleted=False) 


class MyModelManager(models.Model): 
    objects = MyModelManager() 
    _objects = models.Manger() 

    deleted = models.BooleanField(default=False) 

默認deleted對象將被隱藏,但如果需要他們在你的查詢集,您可以使用_objects

+1

我不確定'limit_choices_to'參數。正如django的文檔中所述,它僅適用於管理員和'ModelForm',但在這裏也許就是這種情況。 – beezz

+0

例如,我調用'model.children.all()'時無法使'limit_choices_to'工作。 –

+0

我已更新答案以包含您的觀察結果。 – demux

0

這是我的解決方案。 @beezz,你可能是正確的使用代理模式要做到這一點,但我沒有用代理模式之前,此模式,所以這是我解決了這個:

class SelfRefrencingQuerySet(models.query.QuerySet): 
    pass 

class SelfRefrencingManager(BaseManager): 

    def get_queryset(self): 
     return SelfRefrencingQuerySet(self.model, self._db).filter(
      deleted__isnull=True) 

class SelfRefrencingBaseModel(models.Model): 

    children = models.ManyToManyField('self', blank=True, symmetrical=False, 
     related_name='parents') 

    # Manager 
    objects = SelfRefrencingManager() 
    objects_all = models.Manager()  # So you still have acccess to the 
             # default Manager 
+0

但是在重寫默認管理器的情況下,無法通過'deleted__isnull = False'獲取模型。不僅僅是場上的「孩子」,而是全部。 – beezz

+0

@beezz同樣會覆蓋'ManyToMany'字段來排除它們嗎?使用我的解決方案,您仍然可以保留默認的'models.Manager'並讓'Model'有2個管理器。這是我正在使用的模式。 99%的時間我們不希望被刪除的記錄,所以這種模式很好。謝謝。 –