web-dev-qa-db-ja.com

Django adminでデフォルトのクエリセットを上書きする

私のモデルの1つには、オブジェクトをグローバルに非表示にするために使用される削除済みフラグがあります。

class NondeletedManager(models.Manager):
    """Returns only objects which haven't been deleted"""

    def get_query_set(self):
        return super(NondeletedManager, self).get_query_set().exclude(deleted=True)

class Conversation(BaseModel):
    ...
    deleted = models.BooleanField(default=False)
    objects = NondeletedManager()
    all_conversations = models.Manager() # includes deleted conversations

Django= adminモジュールが使用するデフォルトのクエリセットをオーバーライドして、削除された会話を含めるにはどうすればよいですか?

62
Natan Yellin

オーバーライドget_querysetモデル管理クラスのメソッド。

class MyModelAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        qs = super(MyModelAdmin, self).get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(author=request.user)

Django <= 1.5では、メソッドの名前はquerysetだけでした。

115
Konrad Hałas

Konradは正しいですが、これはドキュメントに記載されている例よりも困難です。

削除された会話は、既に除外されているクエリセットに含めることはできません。したがって、admin.ModelAdmin.querysetを完全に再実装する以外のオプションはありません。

class ConversationAdmin (admin.ModelAdmin):

    def queryset (self, request):
        qs = Conversation.all_conversations
        ordering = self.get_ordering(request)
        if ordering:
            qs = qs.order_by(*ordering)
        return qs
7
Natan Yellin

受け入れられたソリューションはうまく機能しますが、もう少し柔軟性が必要だったため、変更リストビューを拡張してカスタムクエリセットパラメーターを追加することになりました。デフォルトのクエリセット/フィルターをそのように構成できるようになりましたが、別のフィルターを使用して変更することができます(パラメーターを取得)。

def changelist_view(self, request, extra_context=None):
    if len(request.GET) == 0 :
        q = request.GET.copy()
        q['status__gt'] = 4
        request.GET = q
        request.META['QUERY_STRING'] = request.GET.urlencode()

    return super(WorksheetAdmin,self).changelist_view(request, extra_context=extra_context)
2
radtek

次の何がそんなに間違っているのでしょうか:

_class Conversation(BaseModel):
    ...
    deleted = models.BooleanField(default=False)
    objects = models.Manager() # includes deleted conversations
    nondeleted_conversations = NondeletedManager()
_

したがって、独自のアプリ/プロジェクトでは、Conversation.nondeleted_conversations()を使用し、組み込みの管理アプリにそれをさせます。

2
Evan Porter

これを行うには、Django proxy model を使用します。

# models.py
class UnfilteredConversation(Conversation):
    class Meta:
        proxy = True

    # this will be the 'default manager' used in the Admin, and elsewhere
    objects = models.Manager() 

# admin.py
@admin.register(UnfilteredConversation)
class UnfilteredConversationAdmin(Conversation):
    # regular ModelAdmin stuff here
    ...

または、再利用したい既存のModelAdminクラスがある場合:

admin.site.register(UnfilteredConversation, ConversationAdmin)

このアプローチは、元の会話モデルでデフォルトマネージャーをオーバーライドすることで発生する可能性のある問題を回避します。これは、デフォルトマネージャーがManyToMany関係およびリバースForeignKey関係でも使用されるためです。

1
zlovelady

Natan Yellinは正しいですが、マネージャーの順序を変更できます。最初の順序がデフォルトになり、管理者によって使用されます。

_class Conversation(BaseModel):
    ...
    deleted = models.BooleanField(default=False)

    all_conversations = models.Manager() # includes deleted conversations
    objects = NondeletedManager()
_

get_queryset()の管理実装は、次に示すように_._default_manager_の代わりに_.objects_を使用します

_qs = self.model._default_manager.get_queryset()
_

ref Django github BaseModelAdmin implementation

これにより、YourModel.objectsを使用するたびに、削除されたオブジェクトは含まれなくなりますが、汎用ビューなどでは._default_managerも使用されます。次に、get_querysetをオーバーライドしない場合、解決策ではありません。 ListViewと管理者を確認しました。

0
AramirezMiori