admin.py 10 KB
Newer Older
Alan Mitchell's avatar
Alan Mitchell committed
1 2 3 4
'''
This file configures the Admin interface, which allows for editing of the Models.
'''

Alan Mitchell's avatar
Alan Mitchell committed
5
from bmsapp.models import Building, Sensor, SensorGroup, BldgToSensor, DashboardItem, Unit
Ian Moore's avatar
Ian Moore committed
6
from bmsapp.models import MultiBuildingChart, ChartBuildingInfo, CustomReport
7
from bmsapp.models import Organization, BuildingGroup, BuildingMode
8
from bmsapp.models import AlertCondition, AlertRecipient, PeriodicScript
9
from bmsapp.models import FuelRate, ElectricRate
Alan Mitchell's avatar
Alan Mitchell committed
10 11 12
from django.contrib import admin
from django.forms import TextInput, Textarea
from django.db import models
13
from django.utils.html import format_html
Alan Mitchell's avatar
Alan Mitchell committed
14
from django.urls import reverse
15 16
from django.utils.translation import ugettext_lazy as _

Alan Mitchell's avatar
Alan Mitchell committed
17

Alan Mitchell's avatar
Alan Mitchell committed
18
class BldgToSensorInline(admin.TabularInline):
19 20 21 22 23 24 25 26
    '''Used in Building change form.
    '''
    model = BldgToSensor
    extra = 1
    fields = ('sensor', 'edit_sensor', 'sensor_group', 'sort_order')

    def edit_sensor(self, instance):
        url = reverse('admin:bmsapp_sensor_change', args=(instance.sensor.pk,))
27
        return format_html('<a href="{}">Edit this Sensor</a>', url)
28 29 30 31 32 33 34

    readonly_fields = ('edit_sensor',)


class BldgToSensorInline2(admin.TabularInline):
    '''Used in Sensor change form.
    '''
Alan Mitchell's avatar
Alan Mitchell committed
35 36
    model = BldgToSensor
    extra = 1
Alan Mitchell's avatar
Alan Mitchell committed
37

38

Alan Mitchell's avatar
Alan Mitchell committed
39 40 41 42
class DashboardItemInline(admin.StackedInline):
    model = DashboardItem
    extra = 1

43
    fieldsets = (
Alan Mitchell's avatar
Alan Mitchell committed
44 45
        (None, {'fields': ( ('widget_type', 'row_number', 'column_number'),
                            ('sensor', 'title'),
46 47 48 49 50 51
                            ('minimum_normal_value', 'maximum_normal_value', 'minimum_axis_value', 'maximum_axis_value'),
                          )}
        ),
    )
    formfield_overrides = {
        models.FloatField: {'widget': TextInput(attrs={'size':'10'})},
Alan Mitchell's avatar
Alan Mitchell committed
52
        models.IntegerField: {'widget': TextInput(attrs={'size':'5'})},
53
    }
Alan Mitchell's avatar
Alan Mitchell committed
54 55 56 57 58 59
    
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        # Filter sensor list down to just those for this building.
        if db_field.name == "sensor":
            kwargs["queryset"] = BldgToSensor.objects.filter(building__exact = request._obj_)
        return super(DashboardItemInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
60

61

62
@admin.register(Building)
Alan Mitchell's avatar
Alan Mitchell committed
63
class BuildingAdmin(admin.ModelAdmin):
Alan Mitchell's avatar
Alan Mitchell committed
64
    inlines = (BldgToSensorInline, DashboardItemInline)
65
    formfield_overrides = {
66
        models.TextField: {'widget': Textarea(attrs={'rows': 6, 'cols':80})},
67
    }
Alan Mitchell's avatar
Alan Mitchell committed
68 69 70 71
    def get_form(self, request, obj=None, **kwargs):
        # save the object reference for future processing in DashboardInline
        request._obj_ = obj
        return super(BuildingAdmin, self).get_form(request, obj, **kwargs)
Alan Mitchell's avatar
Alan Mitchell committed
72

73

74 75
@admin.register(BuildingMode)
class BuildingModeAdmin(admin.ModelAdmin):
76
    list_display = ('name',)
77
    list_editable = ('name',)
78
    list_display_links = None
79 80 81


@admin.register(BuildingGroup)
82 83 84
class BuildingGroupAdmin(admin.ModelAdmin):
    filter_horizontal = ('buildings',)

85 86
@admin.register(Organization)
class OrganizationAdmin(admin.ModelAdmin):
87
    filter_horizontal = ('buildings', 'building_groups', 'multi_charts', 'custom_reports')
88

89 90 91 92
class AlertAdminInline(admin.StackedInline):
    '''Used in the Sensor Admin to enter alerts.
    '''
    model = AlertCondition
AlaskaMapScience's avatar
AlaskaMapScience committed
93
    template = "admin/stacked_alerts.html"
94
    extra = 0
95
    filter_horizontal = ('recipients',)
96 97 98

    fieldsets = (
        (None, {'fields': ( ('active', 'sensor'),
99
                            ('condition', 'test_value', 'read_count'),
100
                            ('only_if_bldg', 'only_if_bldg_mode','only_if_bldg_status'),
101 102 103 104 105 106 107
                            ('alert_message',),
                            ('priority', 'wait_before_next'),
                            ('recipients',)
                          )}
        ),
    )

108 109 110 111
    formfield_overrides = {
        models.TextField: {'widget': Textarea(attrs={'rows':3, 'cols':80})},
    }

112

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
class BuildingSensorListFilter(admin.SimpleListFilter):
    '''List Filter used to select sensors belonging to a
    particular building when on the Sensor Admin page (below).
    See https://docs.djangoproject.com/en/1.7/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
    for info on how this built.
    '''

    # Human-readable title which will be displayed in the
    # right admin sidebar just above the filter options.
    # NOTE:  the underbar is a function imported from django.utils.translation
    title = _('Building')

    # Parameter for the filter that will be used in the URL query.
    parameter_name = 'bldg_id'

    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 [(str(b.pk), _(b.title)) for b in Building.objects.all()]

    def queryset(self, request, queryset):
        """
        Returns the filtered queryset based on the value
        provided in the query string and retrievable via
        `self.value()`.
        """
        # get the ID of the requested building and find the sensor IDs
        # associated with that building.
        bldg_pk = self.value()
        if bldg_pk is None:
            # This case occurs when 'All' buildings are selected
            return queryset
        else:
            sensor_ids = [b_to_s.sensor.pk for b_to_s in BldgToSensor.objects.filter(building_id=bldg_pk)]
            return queryset.filter(pk__in=sensor_ids)

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
class SensorAlertExistsListFilter(admin.SimpleListFilter):
    '''List Filter used to select sensors that have alerts present.
    See https://docs.djangoproject.com/en/2.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
    for info on how this built.
    '''

    # Human-readable title which will be displayed in the
    # right admin sidebar just above the filter options.
    # NOTE:  the underbar is a function imported from django.utils.translation
    title = _('Alerts Present')

    # Parameter for the filter that will be used in the URL query.
    parameter_name = 'alerts_present'

    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 (
            ('active', _('Have Active Alerts')),
            ('inactive', _('Have Inactive Alerts')),
            ('none', _('Have No Alerts')),
        )

    def queryset(self, request, queryset):
        """
        Returns the filtered queryset based on the value
        provided in the query string and retrievable via
        `self.value()`.
        """
        # get the requested alert presence.
        alert_presence = self.value()
        if alert_presence is None:
            # This case occurs when 'All' is selected
            return queryset
        elif alert_presence == 'none':
            sensor_ids = [alert.sensor.pk for alert in AlertCondition.objects.all()]
            sensor_ids = list(set(sensor_ids))
            return queryset.exclude(pk__in=sensor_ids)
        elif alert_presence == 'inactive':
            sensor_ids = [alert.sensor.pk for alert in AlertCondition.objects.filter(active=False)]
            sensor_ids = list(set(sensor_ids))
            return queryset.filter(pk__in=sensor_ids)
        elif alert_presence == 'active':
            sensor_ids = [alert.sensor.pk for alert in AlertCondition.objects.filter(active=True)]
            sensor_ids = list(set(sensor_ids))
            return queryset.filter(pk__in=sensor_ids)
        else:
            return queryset
207

208
@admin.register(Sensor)
Alan Mitchell's avatar
Alan Mitchell committed
209
class SensorAdmin(admin.ModelAdmin):
210
    inlines = (BldgToSensorInline2, AlertAdminInline)
211
    search_fields = ['sensor_id', 'title', 'tran_calc_function']
212
    list_filter = [BuildingSensorListFilter, SensorAlertExistsListFilter, 'is_calculated']
213 214 215
    formfield_overrides = {
        models.TextField: {'widget': Textarea(attrs={'rows':6, 'cols':80})},
    }
216

Alan Mitchell's avatar
Alan Mitchell committed
217

218
@admin.register(SensorGroup)
Alan Mitchell's avatar
Alan Mitchell committed
219 220 221 222
class SensorGroupAdmin(admin.ModelAdmin):
    list_display = ('id', 'title', 'sort_order')
    list_editable = ('title', 'sort_order')

223

224
@admin.register(Unit)
Alan Mitchell's avatar
Alan Mitchell committed
225 226 227 228
class UnitAdmin(admin.ModelAdmin):
    list_display = ('id', 'label', 'measure_type')
    list_editable = ('label', 'measure_type')

229

Alan Mitchell's avatar
Alan Mitchell committed
230 231 232
class ChartBuildingInfoInline(admin.TabularInline):
    model = ChartBuildingInfo
    formfield_overrides = {
233
        models.TextField: {'widget': Textarea(attrs={'rows':5, 'cols':40})},
Alan Mitchell's avatar
Alan Mitchell committed
234 235 236
    }
    extra = 1

237

238
@admin.register(MultiBuildingChart)
Alan Mitchell's avatar
Alan Mitchell committed
239 240 241
class MultiBuildingChartAdmin(admin.ModelAdmin):
    inlines = (ChartBuildingInfoInline,)
    formfield_overrides = {
242
        models.TextField: {'widget': Textarea(attrs={'rows':6, 'cols':40})},
Alan Mitchell's avatar
Alan Mitchell committed
243 244
    }

245 246
@admin.register(AlertRecipient)
class AlertRecipientAdmin(admin.ModelAdmin):
AlaskaMapScience's avatar
AlaskaMapScience committed
247
    change_form_template = 'admin/AlertRecipient_change_form.html'
248
    list_display = ('name', 'active' )
249 250 251 252 253 254 255
    list_editable= ('active',)
    fields = (
        ('active', 'name'), 
        ('notify_email', 'email_address'), 
        ('notify_cell', 'cell_number', 'cell_sms_gateway'),
        ('notify_pushover', 'pushover_id')
    )
256 257 258

@admin.register(PeriodicScript)
class SensorAdmin(admin.ModelAdmin):
259
    exclude = ('hidden_script_results', )
260
    list_display =  ('script_file_name', 'description', 'period', 'script_parameters')
261
    search_fields = ['script_file_name', 'description', 'script_parameters']
262 263 264 265
    readonly_fields = ('script_results',)
    formfield_overrides = {
        models.TextField: {'widget': Textarea(attrs={'rows': 8, 'cols': 80})},
    }
Ian Moore's avatar
Ian Moore committed
266 267 268

@admin.register(CustomReport)
class CustomReportAdmin(admin.ModelAdmin):
269
    list_display = ('title', 'group')
270 271 272 273 274 275 276 277 278
    formfield_overrides = {models.TextField: {'widget': Textarea(attrs={'rows':20, 'cols':80})}}

@admin.register(FuelRate)
class FuelRateAdmin(admin.ModelAdmin):
    list_display = ('title',)

@admin.register(ElectricRate)
class ElectricRateAdmin(admin.ModelAdmin):
    list_display = ('title',)