class GeoAreaAdmin(VersionAdmin): search_fields = ('title', ) list_display = ( 'title', linkify('admin_level'), linkify('parent'), 'code', ) autocomplete_fields = ( 'parent', 'admin_level', ) list_per_page = 10
class TemplateGroupAdminMixin(): search_fields = ('title', 'template__title') list_display = ( 'title', linkify('template'), ) list_filter = ('template', )
class FieldAdminMixin(): list_display = ( 'title', 'id', 'order', linkify('group'), )
class AssessmentAdmin(VersionAdmin): search_fields = ('lead__title', ) list_display = ( 'lead', linkify('project'), ) autocomplete_fields = ('lead', 'project', 'created_by', 'modified_by', 'lead_group')
class ProjectEntryStatsAdmin(admin.ModelAdmin): AF = linkify('project.analysis_framework', 'AF') search_fields = ('project__title',) list_filter = ('status',) list_display = ('project', 'modified_at', AF, 'status', 'file', 'confidential_file',) actions = [trigger_project_viz_stat_calc(generate_viz_stats)] autocomplete_fields = ('project',) readonly_fields = (AF, 'token') def get_queryset(self, request): return super().get_queryset(request).prefetch_related('project', 'project__analysis_framework')
class AdminLevelAdmin(VersionAdmin): search_fields = ( 'title', 'region__title', ) list_display = ( 'title', linkify('region'), ) autocomplete_fields = ('region', ) + AdminLevelInline.autocomplete_fields exclude = ('geo_area_titles', ) actions = [trigger_admin_level_cache_reset] list_per_page = 10
class AFRelatedAdmin(JFModelAdmin): search_fields = ( 'analysis_framework__title', 'title', ) list_display = ( '__str__', linkify('analysis_framework'), ) autocomplete_fields = ('analysis_framework', ) def get_queryset(self, request): return super().get_queryset(request).prefetch_related( 'analysis_framework') def has_add_permission(self, request, obj=None): return False
class OrganizationAdmin(admin.ModelAdmin): search_fields = ('title', 'short_name', 'long_name') list_display = ('title', 'short_name', linkify('organization_type'), 'get_relief_web_id', 'verified', 'modified_at') readonly_fields = ( document_preview('logo', label='Logo Preview', max_height='400px', max_width='300px'), 'relief_web_id' ) list_filter = ('organization_type', 'verified', IsFromReliefWeb,) actions = (merge_organizations,) exclude = ('parent',) inlines = [OrganizationInline] autocomplete_fields = ( 'created_by', 'modified_by', 'logo', 'organization_type', 'regions', 'parent', ) change_list_template = 'admin/organization_change_list.html' form = OrganizationModelForm def get_relief_web_id(self, obj): id = obj.relief_web_id if id: return format_html(f'<a target="_blank" href="https://api.reliefweb.int/v1/sources/{id}/">{id} </a>') get_relief_web_id.short_description = 'ReliefWeb' get_relief_web_id.admin_order_field = 'relief_web_id' def get_queryset(self, request): return super().get_queryset(request).prefetch_related('organization_type') def change_view(self, request, object_id, form_url='', extra_context=None): extra_context = extra_context or {} extra_context['has_merge_permission'] = self.has_merge_permission(request) return super().change_view(request, object_id, form_url=form_url, extra_context=extra_context) def has_merge_permission(self, request): return request.user.has_perm('organization.can_merge') def merge_view(self, request, object_id, extra_context=None): info = self.model._meta.app_label, self.model._meta.model_name org = Organization.objects.get(pk=object_id) org.parent = None org.save(update_fields=('parent',)) return HttpResponseRedirect( reverse('admin:%s_%s_change' % info, kwargs={'object_id': object_id}), ) def get_urls(self): info = self.model._meta.app_label, self.model._meta.model_name return [ path( '<path:object_id>/unmerge/', self.admin_site.admin_view(self.merge_view), name='%s_%s_unmerge' % info ), path( 'trigger-relief-web-sync/', self.admin_site.admin_view(self.trigger_relief_web_sync), name='organization_relief_web_sync' ), ] + super().get_urls() def trigger_relief_web_sync(self, request): sync_organization_with_relief_web.s().delay() messages.add_message(request, messages.INFO, mark_safe('Successfully triggered organizations re-sync')) return redirect('admin:organization_organization_changelist') def get_inline_instances(self, request, obj=None): if obj and obj.related_childs.exists(): return super().get_inline_instances(request, obj=obj) return [] def get_exclude(self, request, obj=None): if request.GET.get('show_parent', False): return return self.exclude def get_search_results(self, request, qs, term): qs, search_use_distinct = super().get_search_results(request, qs, term) # NOTE: Only show root organizations (Having no parents) qs = qs.filter(parent=None) return qs, search_use_distinct def log_merge(self, request, object, object_repr): """ Log that an object will be merged. Note that this method must be called before the merging. """ return LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=admin.options.get_content_type_for_model(object).pk, object_id=object.pk, object_repr=object_repr, action_flag=CHANGE, change_message='Merged organization', ) def get_merged_objects(self, objs, request): try: obj = objs[0] except IndexError: return [], [], False perms_needed = not self.has_merge_permission(request) to_merge = objs.all() count = ([obj._meta.verbose_name_plural, len(objs)],) return to_merge, count, perms_needed def merge_queryset(self, request, selected_parent_org_id, queryset): def update_children(related_childs): org_list = [] for child_org in related_childs.all(): if child_org.related_childs.exists(): org_list.extend( update_children( child_org.related_childs ) ) org_list.append(child_org) return org_list orgs = update_children(queryset) # Make others childern to selected_parent_organization Organization.objects.filter( id__in=[org.pk for org in orgs] ).update(parent=selected_parent_org_id) # Make selected_parent_organization a root entity Organization.objects.filter(pk=selected_parent_org_id).update(parent=None)
class ProjectAdmin(VersionAdmin): search_fields = ['title'] list_display = [ 'title', linkify('category_editor', 'Category Editor'), linkify('analysis_framework', 'Assessment Framework'), linkify('assessment_template', 'Assessment Template'), 'associated_regions', 'entries_count', 'assessment_count', 'members_count', ] autocomplete_fields = ( 'analysis_framework', 'assessment_template', 'category_editor', 'created_by', 'modified_by', 'regions', ) list_filter = ('assessment_template', 'is_private',) actions = [trigger_project_stat_cache_calc()] inlines = [ProjectMembershipInline, ProjectUserGroupMembershipInline, ProjectJoinRequestInline, ProjectOrganizationInline] def get_queryset(self, request): def _count_subquery(Model, count_field='id'): return models.functions.Coalesce( models.Subquery( Model.objects.filter( project=models.OuterRef('pk'), ).order_by().values('project') .annotate(c=models.Count('id', distinct=True)).values('c')[:1], output_field=models.IntegerField(), ), 0) return super().get_queryset(request).prefetch_related( 'category_editor', 'analysis_framework', 'assessment_template', ).annotate( leads_count=_count_subquery(Lead), entries_count=_count_subquery(Entry), assessment_count=_count_subquery(Assessment), members_count=_count_subquery(ProjectMembership, count_field='member'), associated_regions_count=models.Count('regions', distinct=True), associated_regions=StringAgg('regions__title', ',', distinct=True), ) def get_readonly_fields(self, request, obj=None): # editing an existing object if obj: return self.readonly_fields + ('is_private', ) return self.readonly_fields def entries_count(self, obj): return obj.entries_count def leads_count(self, obj): return obj.leads_count def assessment_count(self, obj): return obj.assessment_count def members_count(self, obj): return obj.members_count entries_count.admin_order_field = 'entries_count' leads_count.admin_order_field = 'leads_count' assessment_count.admin_order_field = 'assessment_count' members_count.admin_order_field = 'members_count' def associated_regions(self, obj): count = obj.associated_regions_count regions = obj.associated_regions if count == 0: return '' elif count == 1: return regions return f'{regions[:10]}.... ({count})'
class ScorePillarAdmin(ModelAdmin): inlines = [ScoreQuestionInline] list_display = ('title', linkify('template'), 'order', 'weight')
class AffectedGroupAdmin(ModelAdmin): list_display = ( 'title', 'order', linkify('template'), )
class ScoreQuestionnaireSubSectorAdmin(ModelAdmin): list_display = ('title', 'order', linkify('sector'), linkify('sector.template')) inlines = [ScoreQuestionnaireInline]
class ScoreQuestionnaireSectorAdmin(ModelAdmin): list_display = ('title', 'order', 'method', 'sub_method', linkify('template')) inlines = [ScoreQuestionnaireSubSectorInline]
class ScoreMatrixPillarAdmin(ModelAdmin): inlines = [ ScoreMatrixRowInline, ScoreMatrixColumnInline, ScoreMatrixScaleInline ] list_display = ('title', linkify('template'), 'order', 'weight')