Commit a0323329 authored by James Pic's avatar James Pic

Merge pull request #64 from political-memory/scores-api

Add scores, scoredvotes, recommendations to api
parents 7d05cdc8 ffaeb858
......@@ -13,12 +13,24 @@ from representatives_votes.api import (
VoteViewSet,
)
from representatives_recommendations.api import (
DossierScoreViewSet,
RecommendationViewSet,
RepresentativeScoreViewSet,
ScoredVoteViewSet
)
router = routers.DefaultRouter()
router.register(r'constituencies', ConstituencyViewSet)
router.register(r'dossiers', DossierViewSet)
router.register(r'dossier_scores', DossierScoreViewSet)
router.register(r'groups', GroupViewSet)
router.register(r'mandates', MandateViewSet)
router.register(r'proposals', ProposalViewSet)
router.register(r'recommendations', RecommendationViewSet)
router.register(r'representatives', RepresentativeViewSet)
router.register(r'scores', RepresentativeScoreViewSet)
router.register(r'scored_votes', ScoredVoteViewSet)
router.register(r'votes', VoteViewSet)
......@@ -1166,13 +1166,13 @@
"app_label": "representatives_positions"
},
"model": "contenttypes.contenttype",
"pk": 26
"pk": 27
},
{
"fields": {
"tag": 1,
"object_id": 1,
"content_type": 26
"content_type": 27
},
"model": "taggit.taggeditem",
"pk": 1
......@@ -1181,7 +1181,7 @@
"fields": {
"tag": 2,
"object_id": 1,
"content_type": 26
"content_type": 27
},
"model": "taggit.taggeditem",
"pk": 2
......@@ -1190,7 +1190,7 @@
"fields": {
"tag": 1,
"object_id": 3,
"content_type": 26
"content_type": 27
},
"model": "taggit.taggeditem",
"pk": 5
......@@ -1199,7 +1199,7 @@
"fields": {
"tag": 1,
"object_id": 2,
"content_type": 26
"content_type": 27
},
"model": "taggit.taggeditem",
"pk": 6
......@@ -1208,7 +1208,7 @@
"fields": {
"tag": 3,
"object_id": 2,
"content_type": 26
"content_type": 27
},
"model": "taggit.taggeditem",
"pk": 7
......
from rest_framework import (
filters,
viewsets,
)
from representatives.api import DefaultWebPagination
from .models import (
DossierScore,
Recommendation,
RepresentativeScore,
ScoredVote
)
from .serializers import (
DossierScoreSerializer,
RecommendationSerializer,
RepresentativeScoreSerializer,
ScoredVoteSerializer
)
class DossierScoreViewSet(viewsets.ReadOnlyModelViewSet):
"""
API endpoint to view representative score contribution for each dossier
"""
queryset = DossierScore.objects.all()
filter_backends = (
filters.DjangoFilterBackend,
filters.SearchFilter,
filters.OrderingFilter
)
filter_fields = {
'id': ['exact'],
'dossier': ['exact'],
'representative': ['exact'],
'score': ['exact', 'gte', 'lte']
}
search_fields = ('dossier', 'representative')
ordering_fields = ('representative', 'dossier')
pagination_class = DefaultWebPagination
serializer_class = DossierScoreSerializer
class RecommendationViewSet(viewsets.ReadOnlyModelViewSet):
"""
API endpoint that allows recommendations to be viewed.
"""
queryset = Recommendation.objects.select_related('proposal')
filter_backends = (
filters.DjangoFilterBackend,
filters.SearchFilter,
filters.OrderingFilter
)
filter_fields = {
'id': ['exact'],
'recommendation': ['exact'],
'title': ['exact', 'icontains'],
'description': ['exact', 'icontains'],
'weight': ['exact', 'gte', 'lte']
}
search_fields = ('title', 'description')
ordering_fields = ('id', 'weight', 'title')
pagination_class = DefaultWebPagination
serializer_class = RecommendationSerializer
class RepresentativeScoreViewSet(viewsets.ReadOnlyModelViewSet):
"""
API endpoint to view representative scores
"""
queryset = RepresentativeScore.objects.select_related('representative')
filter_backends = (
filters.DjangoFilterBackend,
filters.SearchFilter,
filters.OrderingFilter
)
filter_fields = {
'representative': ['exact'],
'score': ['exact', 'gte', 'lte']
}
search_fields = ('representative', 'score')
ordering_fields = ('representative', 'score')
pagination_class = DefaultWebPagination
serializer_class = RepresentativeScoreSerializer
class ScoredVoteViewSet(viewsets.ReadOnlyModelViewSet):
"""
API endpoint to view votes with their score impact.
This endpoint only shows votes that have a matching recommendation.
"""
queryset = ScoredVote.objects.select_related(
'representative',
'proposal',
'proposal__dossier',
'proposal__recommendation'
).filter(
proposal__recommendation__isnull=False
)
filter_backends = (
filters.DjangoFilterBackend,
filters.SearchFilter,
filters.OrderingFilter
)
filter_fields = {
'representative': ['exact'],
'proposal': ['exact'],
'proposal__dossier': ['exact']
}
pagination_class = DefaultWebPagination
serializer_class = ScoredVoteSerializer
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('representatives_recommendations', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='DossierScore',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('score', models.IntegerField(default=0)),
],
options={
'db_table': 'representatives_recommendations_dossierscores',
'managed': False,
},
),
migrations.RunSQL(
"""
CREATE VIEW "representatives_recommendations_dossierscores"
AS SELECT
"representatives_votes_vote"."representative_id" || ':' || "representatives_votes_proposal"."dossier_id" AS "id",
"representatives_votes_vote"."representative_id",
"representatives_votes_proposal"."dossier_id",
SUM(CASE WHEN "representatives_votes_vote"."position" = ("representatives_recommendations_recommendation"."recommendation")
THEN "representatives_recommendations_recommendation"."weight"
ELSE (0 - "representatives_recommendations_recommendation"."weight")
END) AS "score"
FROM "representatives_votes_vote"
INNER JOIN "representatives_votes_proposal"
ON ( "representatives_votes_vote"."proposal_id" = "representatives_votes_proposal"."id" )
LEFT OUTER JOIN "representatives_recommendations_recommendation"
ON ( "representatives_votes_proposal"."id" = "representatives_recommendations_recommendation"."proposal_id" )
WHERE "representatives_recommendations_recommendation"."id" IS NOT NULL
GROUP BY
"representatives_votes_vote"."representative_id",
"representatives_votes_proposal"."dossier_id"
"""
),
]
......@@ -11,6 +11,18 @@ from representatives_votes.models import Dossier, Proposal, Vote
from representatives.models import Representative
class DossierScore(models.Model):
id = models.CharField(max_length=255, primary_key=True)
representative = models.ForeignKey(Representative,
on_delete=models.DO_NOTHING)
dossier = models.ForeignKey(Dossier, on_delete=models.DO_NOTHING)
score = models.IntegerField(default=0)
class Meta:
managed = False
db_table = 'representatives_recommendations_dossierscores'
class RepresentativeScore(models.Model):
representative = models.OneToOneField('representatives.representative',
primary_key=True, related_name='score')
......
from rest_framework import serializers
from .models import (
DossierScore,
Recommendation,
RepresentativeScore,
ScoredVote
)
class DossierScoreSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = DossierScore
fields = ('representative', 'dossier', 'score')
class RecommendationSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Recommendation
fields = ('recommendation', 'title', 'description', 'weight',
'proposal')
class RepresentativeScoreSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = RepresentativeScore
fields = ('representative', 'score')
class ScoredVoteSerializer(serializers.HyperlinkedModelSerializer):
"""
Scored Vote serializer
"""
class Meta:
model = ScoredVote
fields = (
'proposal',
'representative',
'position',
'absolute_score'
)
......@@ -27,6 +27,7 @@ setup(name='political-memory',
'unicodecsv==0.14.1',
'pytz==2015.7',
'django-suit>=0.2.16,<0.3.0',
'sqlparse>=0.1',
],
extras_require={
# Full version hardcode for testing dependencies so that
......
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