Commit c4bbf2af authored by okhin's avatar okhin 🚴

Merge branch '18-improve-the-usability-of-admin-interface-and-models' into 'master'

Resolve "Improve the usability of admin interface and models"

Closes #18

See merge request !7
parents c721b074 bc71115f
Pipeline #1162 passed with stage
in 53 seconds
from django.contrib import admin from django.contrib import admin
from modeltranslation.admin import TranslationAdmin, TranslationTabularInline from modeltranslation.admin import TranslationAdmin, TranslationStackedInline
from picampaign.campaign.models import Campaign, CampaignContact, Argumentary from picampaign.campaign.models import Campaign, CampaignContact, Argumentary
from picampaign.organization.models import Organization from picampaign.organization.models import Organization
...@@ -13,11 +13,15 @@ class InlineContact(admin.TabularInline): ...@@ -13,11 +13,15 @@ class InlineContact(admin.TabularInline):
class InlineImporter(admin.TabularInline): class InlineImporter(admin.TabularInline):
model = Importer model = Importer
class InlineTranslationArgumentary(TranslationTabularInline): class InlineTranslationArgumentary(TranslationStackedInline):
model = Argumentary model = Argumentary
class CampaignAdmin(TranslationAdmin): class CampaignAdmin(TranslationAdmin):
inlines = [InlineTranslationArgumentary, InlineContact, InlineImporter] inlines = [InlineTranslationArgumentary, InlineContact, InlineImporter]
list_display = ('title', 'organization', 'start_date', 'end_date', 'phone_filter',)
list_filter = ('organization', 'start_date', 'end_date',)
list_select_related = ('organization',)
search_fields = ['title', 'organization__name']
def get_queryset(self, request): def get_queryset(self, request):
qs = super(CampaignAdmin, self).get_queryset(request) qs = super(CampaignAdmin, self).get_queryset(request)
...@@ -35,6 +39,11 @@ class CampaignAdmin(TranslationAdmin): ...@@ -35,6 +39,11 @@ class CampaignAdmin(TranslationAdmin):
request, request,
**kwargs) **kwargs)
class CampaignContactAdmin(admin.ModelAdmin): class CampaignContactAdmin(admin.ModelAdmin):
list_display = ('contact', 'campaign', 'weight')
list_select_related = ('contact', 'campaign',)
list_filter = ('campaign',)
search_fields = ['campaign__title', 'contact__first_name', 'contact__last_name']
def get_queryset(self, request): def get_queryset(self, request):
qs = super(CampaignContactAdmin, self).get_queryset(request) qs = super(CampaignContactAdmin, self).get_queryset(request)
if request.user.is_superuser: if request.user.is_superuser:
...@@ -44,6 +53,10 @@ class CampaignContactAdmin(admin.ModelAdmin): ...@@ -44,6 +53,10 @@ class CampaignContactAdmin(admin.ModelAdmin):
class ArgumentaryAdmin(TranslationAdmin): class ArgumentaryAdmin(TranslationAdmin):
list_display = ('title', 'campaign',)
list_select_related = ('campaign',)
list_filter = ('campaign',)
def get_queryset(self, request): def get_queryset(self, request):
qs = super(ArgumentaryAdmin, self).get_queryset(request) qs = super(ArgumentaryAdmin, self).get_queryset(request)
if request.user.is_superuser: if request.user.is_superuser:
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-06-14 10:04
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('campaign', '0010_auto_20170613_2015'),
]
operations = [
migrations.AlterModelOptions(
name='argumentary',
options={'verbose_name': 'Argument', 'verbose_name_plural': 'Arguments'},
),
]
...@@ -27,6 +27,10 @@ class Argumentary(models.Model): ...@@ -27,6 +27,10 @@ class Argumentary(models.Model):
title = models.CharField(max_length=255, verbose_name=_('title'), null=True, blank=True) title = models.CharField(max_length=255, verbose_name=_('title'), null=True, blank=True)
text = RichTextField(null=True) text = RichTextField(null=True)
class Meta:
verbose_name = _("Argument")
verbose_name_plural = _("Arguments")
def __str__(self): def __str__(self):
args = {'title': self.campaign.title} args = {'title': self.campaign.title}
return _('Argumentary for %(title)s') % args return _('Argumentary for %(title)s') % args
......
from django.contrib import admin from django.contrib import admin
from django.contrib.contenttypes.models import ContentType
from django.http import HttpResponseRedirect
from picampaign.organization.models import FeedbackCategory from picampaign.organization.models import FeedbackCategory
from picampaign.feedback.models import Feedback from picampaign.feedback.models import Feedback
...@@ -9,10 +11,15 @@ class FeedbackFilterByCategory(admin.SimpleListFilter): ...@@ -9,10 +11,15 @@ class FeedbackFilterByCategory(admin.SimpleListFilter):
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
if request.user.is_superuser: if request.user.is_superuser:
feedbacks = Feedback.objects.all().values_list('category__id', 'category__name') feedbacks = Feedback.objects.all().values_list(
'category__id',
'category__name')
else: else:
user_orgs = [x.id for x in request.user.organizations.all()] user_orgs = [x.id for x in request.user.organizations.all()]
feedbacks = Feedback.objects.filter(category__organisation__in=user_orgs).values_list('category_id', 'category_name') feedbacks = Feedback.objects.filter(
category__organisation__in=user_orgs).values_list(
'category_id',
'category_name')
return ((f[0], f[1],) for f in sorted(set(feedbacks), key=lambda f: f[1])) return ((f[0], f[1],) for f in sorted(set(feedbacks), key=lambda f: f[1]))
...@@ -21,8 +28,65 @@ class FeedbackFilterByCategory(admin.SimpleListFilter): ...@@ -21,8 +28,65 @@ class FeedbackFilterByCategory(admin.SimpleListFilter):
return queryset.filter(category__id=self.value()) return queryset.filter(category__id=self.value())
return queryset return queryset
class FeedbackFilterByOrganization(admin.SimpleListFilter):
title = 'organization'
parameter_name = 'organization'
def lookups(self, request, model_admin):
if request.user.is_superuser:
feedbacks = Feedback.objects.all().values_list(
'category__organization__id',
'category__organization__name')
else:
user_orgs = [x.id for x in request.user.organizations.all()]
feedbacks = Feedback.objects.filter(
category__organization__in=user_orgs).values_list(
'category__organization__id',
'category__organization__name')
return ((f[0], f[1],) for f in sorted(set(feedbacks), key=lambda f: f[1]))
def queryset(self, request, queryset):
if self.value():
return queryset.filter(category__organization__id=self.value())
return queryset
class FeedbackFilterByCampaign(admin.SimpleListFilter):
title = 'campaign'
parameter_name = 'campaign'
def lookups(self, request, model_admin):
if request.user.is_superuser:
feedbacks = Feedback.objects.all().values_list(
'callee__campaign__id',
'callee__campaign__title')
else:
user_orgs = [x.id for x in request.user.organizations.all()]
feedbacks = Feedback.objects.filter(
category__organization__in=user_orgs).values_list(
'callee__campaign__id',
'callee__campaign__title')
return ((f[0], f[1],) for f in sorted(set(feedbacks), key=lambda f: f[1]))
def queryset(self, request, queryset):
if self.value():
return queryset.filter(callee__campaign__id=self.value())
return queryset
class FeedbackAdmin(admin.ModelAdmin): class FeedbackAdmin(admin.ModelAdmin):
list_filter = (FeedbackFilterByCategory,) date_hierarchy = 'date'
list_display = ('callee', 'category',
'date', 'organization',)
list_filter = (FeedbackFilterByCategory,
FeedbackFilterByOrganization,
FeedbackFilterByCampaign)
search_fields = ['category__organization__name', 'category__name',
'callee__contact__first_name',
'callee__contact__last_name',
'callee__campaign__title']
actions = ['export_csv']
def get_queryset(self, request): def get_queryset(self, request):
qs = super(FeedbackAdmin, self).get_queryset(request) qs = super(FeedbackAdmin, self).get_queryset(request)
...@@ -31,4 +95,11 @@ class FeedbackAdmin(admin.ModelAdmin): ...@@ -31,4 +95,11 @@ class FeedbackAdmin(admin.ModelAdmin):
user_orgs = [x.id for x in request.user.organizations.all()] user_orgs = [x.id for x in request.user.organizations.all()]
return qs.filter(category__organization__in=user_orgs) return qs.filter(category__organization__in=user_orgs)
def export_csv(self, request, queryset):
selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME)
ct = ContentType.objects.get_for_model(queryset.model)
return HttpResponseRedirect("/export/?ct={}&ids={}".format(ct.pk, ",".join(selected)))
export_csv.short_description = "Export feedbacks as CSV"
admin.site.register(Feedback, FeedbackAdmin) admin.site.register(Feedback, FeedbackAdmin)
...@@ -11,6 +11,9 @@ class Feedback(models.Model): ...@@ -11,6 +11,9 @@ class Feedback(models.Model):
comment = models.CharField(max_length=512, blank=True) comment = models.CharField(max_length=512, blank=True)
date = models.DateTimeField(auto_now_add=True) date = models.DateTimeField(auto_now_add=True)
def organization(self):
return self.category.organization
def __str__(self): def __str__(self):
return _('feedback for %(callee contact)s on %(campaign title)s') % \ return _('feedback for %(callee contact)s on %(campaign title)s') % \
{'callee contact': self.callee.contact, {'callee contact': self.callee.contact,
......
import json import json
import csv
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.contrib.contenttypes.models import ContentType
from rest_framework import viewsets from rest_framework import viewsets
from rest_framework.response import Response from rest_framework.response import Response
...@@ -23,3 +26,25 @@ class FeedbackViewSet(viewsets.ViewSet): ...@@ -23,3 +26,25 @@ class FeedbackViewSet(viewsets.ViewSet):
return Response(feedback.id) return Response(feedback.id)
except Exception as e: except Exception as e:
raise e raise e
def FeedbackExportCSVView(request):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="feedbacks.csv"'
model = ContentType.objects.get_for_id(int(request.GET['ct']))
feedbacks = model.model_class().objects.filter(
pk__in=[int(pk) for pk in request.GET['ids'].split(',')]).select_related(
'callee', 'callee__contact', 'callee__campaign', 'category')
writer = csv.writer(response)
# A Header is nice
writer.writerow(['Date', 'Contact', 'Campaign', 'Category', 'Comment'])
for feedback in feedbacks:
writer.writerow([feedback.date,
feedback.callee.contact.full_name,
feedback.callee.campaign,
feedback.category,
feedback.comment])
return response
...@@ -17,6 +17,8 @@ class GroupInline(admin.TabularInline): ...@@ -17,6 +17,8 @@ class GroupInline(admin.TabularInline):
class GroupTypeAdmin(admin.ModelAdmin): class GroupTypeAdmin(admin.ModelAdmin):
list_display = ('name', 'organization',)
list_filter = ('organization',)
inlines = [GroupInline] inlines = [GroupInline]
def get_queryset(self, request): def get_queryset(self, request):
...@@ -37,6 +39,10 @@ class GroupTypeAdmin(admin.ModelAdmin): ...@@ -37,6 +39,10 @@ class GroupTypeAdmin(admin.ModelAdmin):
class GroupAdmin(admin.ModelAdmin): class GroupAdmin(admin.ModelAdmin):
list_display = ('name', 'type', 'organization',)
list_filter = ('type',)
search_fields = ['name',]
def get_queryset(self, request): def get_queryset(self, request):
qs = super(GroupAdmin, self).get_queryset(request) qs = super(GroupAdmin, self).get_queryset(request)
if request.user.is_superuser: if request.user.is_superuser:
......
...@@ -38,6 +38,9 @@ class Group(models.Model): ...@@ -38,6 +38,9 @@ class Group(models.Model):
contacts = models.ManyToManyField(Contact, blank=True, contacts = models.ManyToManyField(Contact, blank=True,
related_name='groups') related_name='groups')
def organization(self):
return self.type.organization
def __str__(self): def __str__(self):
return self.name return self.name
......
...@@ -6,7 +6,7 @@ from rest_framework_nested import routers ...@@ -6,7 +6,7 @@ from rest_framework_nested import routers
from picampaign.campaign.views import (CampaignViewSet, CampaignContactViewSet, from picampaign.campaign.views import (CampaignViewSet, CampaignContactViewSet,
ArgumentaryViewSet) ArgumentaryViewSet)
from picampaign.feedback.views import FeedbackViewSet from picampaign.feedback.views import FeedbackViewSet, FeedbackExportCSVView
from picampaign.organization.views import (CategoryViewSet, GroupTypeViewSet, from picampaign.organization.views import (CategoryViewSet, GroupTypeViewSet,
GroupViewSet, OrganizationViewSet) GroupViewSet, OrganizationViewSet)
...@@ -29,5 +29,6 @@ urlpatterns = [ ...@@ -29,5 +29,6 @@ urlpatterns = [
url(r'^', include(router.urls)), url(r'^', include(router.urls)),
url(r'^', include(campaign_router.urls)), url(r'^', include(campaign_router.urls)),
url(r'^i18n/', include('django.conf.urls.i18n')), url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^docs/', include('rest_framework_docs.urls')) url(r'^docs/', include('rest_framework_docs.urls')),
url(r'^export/', FeedbackExportCSVView),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment