Search code examples
mysqldjangocachingadmindjango-queryset

django admin list_display from two tables, no relations like foreign key or manytomany relation available


i have two tables, one is MeasuredController and MeasuredGrid, and there is no relation like foreign key or manytoman etc , and in admin i have to show two fields of MeasuredGrid i.e power and status, where MeasuredController's senddate = MeasuredGrid's senddate, in two different column, i have wrote code like below, but in the current code , the database will be hit two time for each object, so is there a way like select related or use cache concept ?

list_display = ("grid_status", "grid_power")

def grid_status(self, obj):
    STATUS_CHOICES = {0:"Outage", 1:"No Outage" }
    mobj = MeasuredGrid.objects.filter(senddate=obj.senddate).latest("senddate")

    try:
        return STATUS_CHOICES[int(mobj.status)], 2
    except:
        pass
grid_status.short_description = 'Grid Status'

def grid_power(self, obj):
    mobj = MeasuredGrid.objects.filter(senddate=obj.senddate).latest("senddate")
    return mobj.power

grid_power.short_description = 'Grid Power[W]'

Solution

  • You can use Cache Framework. It is very easy:

    # coding: utf-8
    from django.core.cache import cache
    from django.contrib import admin
    
    from .models import MeasuredController, MeasuredGrid
    
    
    class MeasuredControllerAdmin(admin.ModelAdmin):
        list_display = ("grid_status", "grid_power")
    
        STATUS_CHOICES = {
            0: "Outage",
            1: "No Outage",
        }
    
        def grid_status(self, obj):
            mobj = self._get_mobj_data(obj)
            return mobj['status']
        grid_status.short_description = 'Grid Status'
    
        def grid_power(self, obj):
            mobj = self._get_mobj_data(obj)
            return mobj['power']
        grid_power.short_description = 'Grid Power[W]'
    
        def _get_mobj_data(self, obj):
            """Get a relevant MeasuredGrid object for a given MeasuredController"""
    
            data = cache.get('mobj_%s' % obj.pk)
            if data is not None:
                return data
    
            mobj = MeasuredGrid.objects.filter(senddate=obj.senddate).latest("senddate")
    
            status = None
            try:
                status = self.STATUS_CHOICES[int(mobj.status)], 2
            except: # <---------- Not the best decision. You probably need ValueError or KeyError
                pass
    
            data = {
                "id": mobj.pk,
                "power": mobj.power,
                "status": status,
            }
    
            cache.set('mobj_%s' % obj.pk, data) # the default timeout is 300 seconds
    
            return data
    

    NB: the default cache backend is django.core.cache.backends.locmem.LocMemCache, so the cache will work even in dev environment (ie. DEBUG = True).