Django admin docs count in display and in filter

 Real time counter in admin you can implement with one small function

class TransactionAdmin(admin.ModelAdmin):

    search_fields = ('name', 'explanation', )

    list_filter = ('transaction_type', 'paymentmethod', 'accounting_period__full_name', 'transaction_date', DocsCountFilter)

    list_display = ('name', 'explanation', 'transaction_date', 'docs_count', 'docs_count_current')

    inlines = [

        DocumentInline,

    ]


    def docs_count_current(self, obj: Transaction) -> str:

        return str(Document.objects.filter(transaction=obj).count())


But if you need something more than display, you have to filter with this count in admin then you could implement List Filter

class DocsCountFilter(admin.SimpleListFilter):

    title = 'Docs count'

    parameter_name = 'docs_count'

    def lookups(self, request, model_admin):

        """

        Returns a list of tuples. The first element in each

        tuple is the coded value for the option that will

        appear in the URL query. The second element is the

        human-readable name for the option that will appear

        in the right sidebar.

        """

        return (

            ('0', 'No Invoics'),

            ('1', 'More then null'),

        )


    def queryset(self, request, queryset):

        """

        Returns the filtered queryset based on the value

        provided in the query string and retrievable via

        `self.value()`.

        """

        if self.value() == '0':

            return queryset.filter(docs_count=0)

        if self.value() == '1':

            return queryset.filter(docs_count__gt=0)

 



So in this way you can filter transactions if a doc is filled in or not. 

Then you are sure that you did not miss any transactions.

When you save one object or delete it.  You have to update your counter in related model. 

So, use Django signals for this action. 

@receiver(models.signals.post_save, sender=Document)

def auto_update_docs_count_on_save(sender, instance, **kwargs):

    instance.transaction.docs_count = Document.objects.filter(transaction=instance.transaction).count()

    instance.transaction.save()



@receiver(models.signals.post_delete, sender=Document)

def auto_delete_file_on_delete(sender, instance, **kwargs):

    """

    Deletes file from filesystem

    when corresponding `Document` object is deleted.

    """

    if instance.invoice:

        if os.path.isfile(instance.invoice.path):

            os.remove(instance.invoice.path)

            instance.transaction.docs_count = Document.objects.filter(transaction=instance.transaction).count()

            instance.transaction.save()


This post is related on topic about.  Django models - how to filter number of ForeignKey objects

 

Comments