web-dev-qa-db-de.com

Standardabfrage in Django-Admin überschreiben

Eines meiner Modelle verfügt über ein gelöschtes Flag, mit dem Objekte global ausgeblendet werden:

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

Wie kann ich das vom Django-Admin-Modul verwendete Standard-Abfrageset überschreiben, um gelöschte Unterhaltungen aufzunehmen?

56
Natan Yellin

Sie können die Methode overrideget_queryset in Ihrer Modellverwaltungsklasse verwenden.

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)

Beachten Sie, dass in Django <= 1.5 die Methode nur queryset genannt wurde. 

102
Konrad Hałas

Konrad ist richtig, aber das ist schwieriger als das in der Dokumentation angegebene Beispiel.

Gelöschte Unterhaltungen können nicht in ein Abfrageset eingeschlossen werden, das sie bereits ausschließt. Ich sehe also keine andere Option als admin.ModelAdmin.queryset vollständig neu zu implementieren.

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

Was wäre so falsch an folgendem:

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

In Ihren eigenen Apps/Projekten verwenden Sie Conversation.nondeleted_conversations() und lassen die integrierte Admin-App ihre Sache erledigen.

2
Evan Porter

Die akzeptierte Lösung funktioniert gut für mich, aber ich brauchte ein bisschen mehr Flexibilität. Daher erweiterte ich die Änderungslistenansicht um einen benutzerdefinierten Parameter für das Queryset. Ich kann jetzt mein Standard-Queryset/Filter als solches konfigurieren und es kann immer noch geändert werden, indem ein anderer Filter verwendet wird (Parameter abrufen):

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)
1
radtek

Sie können dies mit einem Django Proxy-Modell tun.

# 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
    ...

Wenn Sie über eine vorhandene ModelAdmin-Klasse verfügen, die Sie erneut verwenden möchten:

admin.site.register(UnfilteredConversation, ConversationAdmin)

Dieser Ansatz vermeidet Probleme, die beim Überschreiben des Standardmanagers im ursprünglichen Konversationsmodell auftreten können, da der Standardmanager auch in ManyToMany-Beziehungen und umgekehrten ForeignKey-Beziehungen verwendet wird.

0
zlovelady

Natan Yellin ist korrekt, aber Sie können die Managerreihenfolge ändern und der erste wird der Standard sein, dann wird er vom Administrator verwendet:

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

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

Die Admin-Implementierung von get_queryset() verwendet ._default_manager statt .objects, wie im Folgenden gezeigt

qs = self.model._default_manager.get_queryset()

ref Implementierung von Django Github BaseModelAdmin

Dies stellt nur sicher, dass Sie bei jeder Verwendung von YourModel.objects keine gelöschten Objekte einschließen, sondern dass in den generischen Ansichten und anderen auch ._default_manager verwendet wird. Wenn Sie get_queryset nicht überschreiben, ist dies keine Lösung. Ich habe gerade eine ListView und Admin überprüft.

0
AramirezMiori