From c886360c48d62b00c3d90f541f09425126a6b09e Mon Sep 17 00:00:00 2001 From: Yaron Dinur Date: Mon, 20 Jul 2015 22:06:08 +0300 Subject: [PATCH 1/6] added rest framework --- committeeVotes/serializers.py | 14 ++++++++++++++ committeeVotes/views.py | 10 ++++++++++ openCommittee/settings.py | 9 +++++++++ openCommittee/urls.py | 11 +++++++++++ 4 files changed, 44 insertions(+) create mode 100644 committeeVotes/serializers.py diff --git a/committeeVotes/serializers.py b/committeeVotes/serializers.py new file mode 100644 index 0000000..af6bcb2 --- /dev/null +++ b/committeeVotes/serializers.py @@ -0,0 +1,14 @@ +from committeeVotes.models import Bill, Meeting, Minister +from rest_framework import serializers + + +class BillSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Bill + fields = ('name', 'oknesset_url', 'passed') + + +class MinisterSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Minister + fields = ('name', 'title') \ No newline at end of file diff --git a/committeeVotes/views.py b/committeeVotes/views.py index 97aeed7..0d84e78 100644 --- a/committeeVotes/views.py +++ b/committeeVotes/views.py @@ -6,6 +6,8 @@ from committeeVotes.models import Bill, Minister, Vote, VoteType, Meeting from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.shortcuts import render +from committeeVotes.serializers import BillSerializer, MinisterSerializer +from rest_framework import viewsets import json @@ -88,11 +90,19 @@ def bills(request): context = {'bills': bills} return render(request, 'committeeVotes/bills.html', context) +class BillViewSet(viewsets.ModelViewSet): + queryset = Bill.objects.all() + serializer_class = BillSerializer + def ministers(request): ministers = Minister.objects.all() context = {'ministers': ministers} return render(request, 'committeeVotes/ministers.html', context) +class MinisterViewSet(viewsets.ModelViewSet): + queryset = Minister.objects.all() + serializer_class = MinisterSerializer + def meetings(request): meetings = Meeting.objects.all().order_by('-id') context = {'meetings': meetings} diff --git a/openCommittee/settings.py b/openCommittee/settings.py index 85d74c8..e454cbf 100644 --- a/openCommittee/settings.py +++ b/openCommittee/settings.py @@ -38,8 +38,17 @@ 'django.contrib.staticfiles', 'committeeVotes', 'south', + 'rest_framework', ) +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' + ], + 'PAGE_SIZE': 10 +} + + MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', diff --git a/openCommittee/urls.py b/openCommittee/urls.py index f169441..268e3c4 100644 --- a/openCommittee/urls.py +++ b/openCommittee/urls.py @@ -1,11 +1,18 @@ from django.conf import settings from django.conf.urls import patterns, include, url from django.conf.urls.static import static + +from rest_framework import routers + from committeeVotes import views from django.contrib import admin admin.autodiscover() +router = routers.DefaultRouter() +router.register(r'bills', views.BillViewSet) +router.register(r'ministers', views.MinisterViewSet) + urlpatterns = patterns('', # Examples: # url(r'^$', 'openCommittee.views.home', name='home'), @@ -29,4 +36,8 @@ url(r'^search.json', views.search, name='search'), url(r'^bills.json', views.searchBills, name='searchBills'), url(r'^ministers.json', views.searchMinisters, name='searchMinisters'), + + url(r'^api/', include(router.urls)), + url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), + ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) From 6848dca0a21af7f713d311a77cf2741846dfd44e Mon Sep 17 00:00:00 2001 From: Kobi Grossman Date: Mon, 17 Aug 2015 21:03:29 +0300 Subject: [PATCH 2/6] API endpoints for bills,meetings & mininsters --- committeeVotes/models.py | 14 ++-- committeeVotes/serializers.py | 67 +++++++++++++++++-- .../committeeVotes/minister_detail.html | 8 +-- committeeVotes/views.py | 45 +++++++++++-- openCommittee/urls.py | 4 +- 5 files changed, 111 insertions(+), 27 deletions(-) diff --git a/committeeVotes/models.py b/committeeVotes/models.py index 4815d1a..fa354fa 100644 --- a/committeeVotes/models.py +++ b/committeeVotes/models.py @@ -1,5 +1,5 @@ from django.db import models - +from django.conf import settings # Create your models here. class Bill(models.Model): name = models.CharField(max_length=500) @@ -23,6 +23,12 @@ class Minister(models.Model): phone = models.CharField(max_length=20, null=True, blank=True) oknesset = models.CharField(max_length=100, null=True, blank=True) coop = models.NullBooleanField(blank=True) + @property + def photo_url(self): + url_prefix="" + if 'http' not in self.photo: + url_prefix=settings.MEDIA_URL + return "{prefix}{photo}.jpg".format(prefix=url_prefix,photo=self.photo) def __unicode__(self): return self.name @@ -44,8 +50,4 @@ class Meta: unique_together = ("bill","minister") def __unicode__(self): - return self.minister.name + " voted " + self.vote.typeName - - - - + return self.minister.name + " voted " + self.vote.typeName \ No newline at end of file diff --git a/committeeVotes/serializers.py b/committeeVotes/serializers.py index af6bcb2..4e7e048 100644 --- a/committeeVotes/serializers.py +++ b/committeeVotes/serializers.py @@ -2,13 +2,70 @@ from rest_framework import serializers -class BillSerializer(serializers.HyperlinkedModelSerializer): +class DynamicFieldsMixin(object): + + """ + A serializer mixin that takes an additional `fields` argument that controls + which fields should be displayed. + Usage:: + class MySerializer(DynamicFieldsMixin, serializers.HyperlinkedModelSerializer): + class Meta: + model = MyModel + Copied from https://gist.github.com/dbrgn/4e6fc1fe5922598592d6 + """ + + def __init__(self, *args, **kwargs): + super(DynamicFieldsMixin, self).__init__(*args, **kwargs) + if 'request' in self.context: + fields = self.context['request'].QUERY_PARAMS.get('fields') + if fields: + fields = fields.split(',') + # Drop any fields that are not specified in the `fields` + # argument. + allowed = set(fields) + existing = set(self.fields.keys()) + for field_name in existing - allowed: + self.fields.pop(field_name) + + +class BillSerializer(DynamicFieldsMixin, serializers.HyperlinkedModelSerializer): + class Meta: model = Bill - fields = ('name', 'oknesset_url', 'passed') - + fields = ('id', 'name', 'oknesset_url', 'passed') -class MinisterSerializer(serializers.HyperlinkedModelSerializer): +class MinisterListSerializer(serializers.ModelSerializer): class Meta: model = Minister - fields = ('name', 'title') \ No newline at end of file + fields = ('id', 'name', 'photo_url', 'coop') + +class MinisterSerializer(MinisterListSerializer): + + class Meta(MinisterListSerializer.Meta): + fields = MinisterListSerializer.Meta.fields + ('title', + 'facebook', 'twitter', 'mail', 'phone', 'oknesset') + + +class MeetingListSerializer(serializers.ModelSerializer): + bill_count = serializers.IntegerField( + source='proposed_bill_count', + read_only=True + ) + + class Meta: + model = Meeting + fields = ('id', 'took_place', 'bill_count') + + +class BillInMeetingSerializer(serializers.ModelSerializer): + + class Meta: + model = Bill + fields = ('id', 'name') + + +class MeetingSerializer(serializers.ModelSerializer): + proposed_bills = BillInMeetingSerializer(many=True, read_only=True) + + class Meta: + model = Meeting diff --git a/committeeVotes/templates/committeeVotes/minister_detail.html b/committeeVotes/templates/committeeVotes/minister_detail.html index 75048b9..ed06384 100644 --- a/committeeVotes/templates/committeeVotes/minister_detail.html +++ b/committeeVotes/templates/committeeVotes/minister_detail.html @@ -136,15 +136,9 @@

- - {% endblock %} \ No newline at end of file diff --git a/committeeVotes/views.py b/committeeVotes/views.py index 0d84e78..396f403 100644 --- a/committeeVotes/views.py +++ b/committeeVotes/views.py @@ -4,10 +4,13 @@ from django.http import HttpResponse from django.core.urlresolvers import reverse from committeeVotes.models import Bill, Minister, Vote, VoteType, Meeting +from committeeVotes.serializers import BillSerializer, MinisterSerializer,MinisterListSerializer, MeetingSerializer,MeetingListSerializer +from django.db.models import Count from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.shortcuts import render from committeeVotes.serializers import BillSerializer, MinisterSerializer from rest_framework import viewsets +from rest_framework.response import Response import json @@ -26,29 +29,32 @@ def index(request): 'nonVotingMinisters': nonVotingMinisters} return render(request, 'committeeVotes/index.html', context) + def search(request): ministerSearch = [dict([("url", reverse('minister', args=(minister.id,))), ("name", minister.name), ("type", "שר"), - ("tokens",[minister.name])]) for minister in Minister.objects.all()] + ("tokens", [minister.name])]) for minister in Minister.objects.all()] billsSearch = [dict([("url", reverse('detail', args=(bill.id,))), ("name", bill.name), ("type", "הצעת חוק"), - ("tokens",[bill.name])]) for bill in Bill.objects.all()] + ("tokens", [bill.name])]) for bill in Bill.objects.all()] searchResults = ministerSearch + billsSearch return HttpResponse(json.dumps(searchResults), content_type="application/json") def searchBills(request): billsSearch = {'objects': [dict([("url", reverse('bill', args=(bill.id,))), - ("name",bill.name)]) for bill in Bill.objects.all()]} + ("name", bill.name)]) for bill in Bill.objects.all()]} return HttpResponse(json.dumps(billsSearch), content_type="application/json") + def searchMinisters(request): ministerSearch = {'objects': [dict([("url", reverse('minister', args=(minister.id,))), - ("name",minister.name)]) for minister in Minister.objects.all()]} + ("name", minister.name)]) for minister in Minister.objects.all()]} return HttpResponse(json.dumps(ministerSearch), content_type="application/json") + def bill(request, bill_id): bill = get_object_or_404(Bill, pk=bill_id) votes = Vote.objects.select_related('minister').filter(bill=bill) @@ -67,6 +73,7 @@ def bill(request, bill_id): 'meeting': meeting} return render(request, 'committeeVotes/bill.html', context) + def minister_details(request, minister_id): minister = get_object_or_404(Minister,pk=minister_id) all_votes = Vote.objects.filter(minister=minister).order_by('-id') @@ -85,34 +92,59 @@ def minister_details(request, minister_id): 'votes': votes} return render(request, 'committeeVotes/minister_detail.html', context) + def bills(request): bills = Bill.objects.all().order_by('-id') context = {'bills': bills} return render(request, 'committeeVotes/bills.html', context) + class BillViewSet(viewsets.ModelViewSet): queryset = Bill.objects.all() serializer_class = BillSerializer + def ministers(request): ministers = Minister.objects.all() context = {'ministers': ministers} return render(request, 'committeeVotes/ministers.html', context) + class MinisterViewSet(viewsets.ModelViewSet): queryset = Minister.objects.all() - serializer_class = MinisterSerializer + def get_serializer_class(self): + print "serializer_class" + if self.action == 'list': + print "MinisterList" + return MinisterListSerializer + if self.action == 'retrieve': + return MinisterSerializer + return None def meetings(request): meetings = Meeting.objects.all().order_by('-id') context = {'meetings': meetings} return render(request, 'committeeVotes/meetings.html', context) + +class MeetingsViewSet(viewsets.ModelViewSet): + queryset = Meeting.objects.annotate( + proposed_bill_count=Count('proposed_bills')).all() + + def get_serializer_class(self): + if self.action == 'list': + return MeetingListSerializer + if self.action == 'retrieve': + return MeetingSerializer + return None + + def about(request): return render(request, 'committeeVotes/about.html') + def meeting_details(request, meeting_id): - meeting = get_object_or_404(Meeting,pk=meeting_id) + meeting = get_object_or_404(Meeting, pk=meeting_id) bills = meeting.proposed_bills.all() votingMinisters = meeting.voting_ministers.all() votingIds = votingMinisters.values_list('id', flat=True) @@ -125,4 +157,3 @@ def meeting_details(request, meeting_id): 'missingMinisters': missingMinisters, 'nonVotingMinisters': nonVotingMinisters} return render(request, 'committeeVotes/meeting_detail.html', context) - diff --git a/openCommittee/urls.py b/openCommittee/urls.py index 268e3c4..00dac53 100644 --- a/openCommittee/urls.py +++ b/openCommittee/urls.py @@ -12,7 +12,7 @@ router = routers.DefaultRouter() router.register(r'bills', views.BillViewSet) router.register(r'ministers', views.MinisterViewSet) - +router.register(r'meetings',views.MeetingsViewSet) urlpatterns = patterns('', # Examples: # url(r'^$', 'openCommittee.views.home', name='home'), @@ -28,7 +28,7 @@ url(r'^minister/$', views.ministers, name='ministers'), url(r'^minister/(?P\d+)/$', views.minister_details, name='minister'), - url(r'meetings/$',views.meetings, name='meetings'), + url(r'^meetings/$',views.meetings, name='meetings'), url(r'^meetings/(?P\d+)/$', views.meeting_details, name='meeting'), url(r'about/$',views.about, name='about'), From 8b77bb540ad90a875ed86afae01f6feecb2e2618 Mon Sep 17 00:00:00 2001 From: Yaron Dinur Date: Mon, 8 Aug 2016 21:46:30 +0300 Subject: [PATCH 3/6] added last_meeting.json endpoint using serializers --- committeeVotes/models.py | 2 +- committeeVotes/serializers.py | 33 +++++++++++++++++++++++++++++---- committeeVotes/views.py | 9 ++++++--- openCommittee/settings.py | 2 +- openCommittee/urls.py | 1 + 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/committeeVotes/models.py b/committeeVotes/models.py index fa354fa..c141d07 100644 --- a/committeeVotes/models.py +++ b/committeeVotes/models.py @@ -43,7 +43,7 @@ def __unicode__(self): class Vote(models.Model): vote = models.ForeignKey(VoteType) meeting = models.ForeignKey(Meeting) - bill = models.ForeignKey(Bill) + bill = models.ForeignKey(Bill, related_name="votes") minister = models.ForeignKey(Minister, related_name="votes") class Meta: diff --git a/committeeVotes/serializers.py b/committeeVotes/serializers.py index 4e7e048..9ca5e91 100644 --- a/committeeVotes/serializers.py +++ b/committeeVotes/serializers.py @@ -1,4 +1,4 @@ -from committeeVotes.models import Bill, Meeting, Minister +from committeeVotes.models import Bill, Meeting, Minister, Vote from rest_framework import serializers @@ -28,12 +28,29 @@ def __init__(self, *args, **kwargs): self.fields.pop(field_name) +class VoteSerializer(serializers.ModelSerializer): + vote = serializers.StringRelatedField() + minister = serializers.StringRelatedField() + + class Meta: + model = Vote + fields = ('vote', 'minister') + + class BillSerializer(DynamicFieldsMixin, serializers.HyperlinkedModelSerializer): class Meta: model = Bill fields = ('id', 'name', 'oknesset_url', 'passed') + +class BillVoteSerializer(DynamicFieldsMixin, serializers.HyperlinkedModelSerializer): + votes = VoteSerializer(many=True, read_only=True) + + class Meta: + model = Bill + fields = ('id', 'name', 'oknesset_url', 'passed', 'votes') + class MinisterListSerializer(serializers.ModelSerializer): class Meta: model = Minister @@ -57,15 +74,23 @@ class Meta: fields = ('id', 'took_place', 'bill_count') -class BillInMeetingSerializer(serializers.ModelSerializer): +class MinisterInMeetingSerializer(serializers.ModelSerializer): class Meta: - model = Bill + model = Minister fields = ('id', 'name') class MeetingSerializer(serializers.ModelSerializer): - proposed_bills = BillInMeetingSerializer(many=True, read_only=True) + proposed_bills = BillSerializer(many=True, read_only=True) + + class Meta: + model = Meeting + + +class MeetingDetailSerializer(serializers.ModelSerializer): + proposed_bills = BillVoteSerializer(many=True, read_only=True) + voting_ministers = MinisterInMeetingSerializer(many=True, read_only=True) class Meta: model = Meeting diff --git a/committeeVotes/views.py b/committeeVotes/views.py index 396f403..6a75a4f 100644 --- a/committeeVotes/views.py +++ b/committeeVotes/views.py @@ -4,16 +4,14 @@ from django.http import HttpResponse from django.core.urlresolvers import reverse from committeeVotes.models import Bill, Minister, Vote, VoteType, Meeting -from committeeVotes.serializers import BillSerializer, MinisterSerializer,MinisterListSerializer, MeetingSerializer,MeetingListSerializer +from committeeVotes.serializers import BillSerializer, MinisterSerializer,MinisterListSerializer, MeetingSerializer, MeetingListSerializer, MeetingDetailSerializer from django.db.models import Count from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.shortcuts import render from committeeVotes.serializers import BillSerializer, MinisterSerializer from rest_framework import viewsets -from rest_framework.response import Response import json - def index(request): bills = Bill.objects.all().order_by('-id')[:10] last_meeting = Meeting.objects.all().order_by('-id')[0] @@ -42,6 +40,11 @@ def search(request): searchResults = ministerSearch + billsSearch return HttpResponse(json.dumps(searchResults), content_type="application/json") +def last_meeting(request): + last_meeting = Meeting.objects.latest('took_place') + serializer = MeetingDetailSerializer(last_meeting, context={'request': request}) + return HttpResponse(json.dumps(serializer.data), content_type="application/json") + def searchBills(request): billsSearch = {'objects': [dict([("url", reverse('bill', args=(bill.id,))), diff --git a/openCommittee/settings.py b/openCommittee/settings.py index e454cbf..fa0d5e5 100644 --- a/openCommittee/settings.py +++ b/openCommittee/settings.py @@ -38,7 +38,7 @@ 'django.contrib.staticfiles', 'committeeVotes', 'south', - 'rest_framework', + 'rest_framework', ) REST_FRAMEWORK = { diff --git a/openCommittee/urls.py b/openCommittee/urls.py index 00dac53..9fc153e 100644 --- a/openCommittee/urls.py +++ b/openCommittee/urls.py @@ -30,6 +30,7 @@ url(r'^meetings/$',views.meetings, name='meetings'), url(r'^meetings/(?P\d+)/$', views.meeting_details, name='meeting'), + url(r'^last_meeting.json', views.last_meeting, name='last_meeting'), url(r'about/$',views.about, name='about'), From f9e941ec57457f5145ca4a9fcc274d8ff304ba83 Mon Sep 17 00:00:00 2001 From: Yaron Dinur Date: Mon, 10 Oct 2016 20:24:39 +0300 Subject: [PATCH 4/6] changed api to read only --- openCommittee/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openCommittee/settings.py b/openCommittee/settings.py index fa0d5e5..afad3f0 100644 --- a/openCommittee/settings.py +++ b/openCommittee/settings.py @@ -43,7 +43,7 @@ REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ - 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' + 'rest_framework.permissions.IsAuthenticatedOrReadOnly' ], 'PAGE_SIZE': 10 } From 0eedd6143170cb0cf1c664dd0a4878d0114034b3 Mon Sep 17 00:00:00 2001 From: Yaron Dinur Date: Mon, 10 Oct 2016 22:18:14 +0300 Subject: [PATCH 5/6] added minister lists for votes --- committeeVotes/models.py | 2 ++ committeeVotes/serializers.py | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/committeeVotes/models.py b/committeeVotes/models.py index c141d07..97ce8f0 100644 --- a/committeeVotes/models.py +++ b/committeeVotes/models.py @@ -1,3 +1,5 @@ +# coding: utf-8 + from django.db import models from django.conf import settings # Create your models here. diff --git a/committeeVotes/serializers.py b/committeeVotes/serializers.py index 9ca5e91..b736096 100644 --- a/committeeVotes/serializers.py +++ b/committeeVotes/serializers.py @@ -1,4 +1,6 @@ -from committeeVotes.models import Bill, Meeting, Minister, Vote +# coding: utf-8 + +from committeeVotes.models import Bill, Meeting, Minister, Vote, VoteType from rest_framework import serializers @@ -37,6 +39,11 @@ class Meta: fields = ('vote', 'minister') +class VoteListSerializer(serializers.BaseSerializer): + def to_representation(self, obj): + return obj.minister.name + + class BillSerializer(DynamicFieldsMixin, serializers.HyperlinkedModelSerializer): class Meta: @@ -45,17 +52,36 @@ class Meta: class BillVoteSerializer(DynamicFieldsMixin, serializers.HyperlinkedModelSerializer): - votes = VoteSerializer(many=True, read_only=True) + yay = serializers.SerializerMethodField() + nay = serializers.SerializerMethodField() + sustained = serializers.SerializerMethodField() + + def get_votes(self, bill, voteTypeName): + voteType = VoteType.objects.get(typeName=voteTypeName) + qs = Vote.objects.filter(vote=voteType, bill=bill) + serializer = VoteListSerializer(instance=qs, many=True) + return serializer.data + + def get_yay(self, bill): + return self.get_votes(bill, u'בעד') + + def get_nay(self, bill): + return self.get_votes(bill, u'נגד') + + def get_sustained(self, bill): + return self.get_votes(bill, u'נמנע') class Meta: model = Bill - fields = ('id', 'name', 'oknesset_url', 'passed', 'votes') + fields = ('id', 'name', 'oknesset_url', 'passed', 'yay', 'nay', 'sustained') + class MinisterListSerializer(serializers.ModelSerializer): class Meta: model = Minister fields = ('id', 'name', 'photo_url', 'coop') + class MinisterSerializer(MinisterListSerializer): class Meta(MinisterListSerializer.Meta): @@ -78,7 +104,7 @@ class MinisterInMeetingSerializer(serializers.ModelSerializer): class Meta: model = Minister - fields = ('id', 'name') + fields = ('id', 'name', 'url') class MeetingSerializer(serializers.ModelSerializer): From 358a575e8a4ba6f145054a2df4758e37ede1345b Mon Sep 17 00:00:00 2001 From: Yaron Dinur Date: Mon, 26 Dec 2016 22:34:39 +0200 Subject: [PATCH 6/6] is this it?! --- committeeVotes/models.py | 18 +++++-- committeeVotes/serializers.py | 97 ++++++++++++++++++++++++++++++----- committeeVotes/views.py | 33 +++++++++--- openCommittee/urls.py | 2 +- 4 files changed, 126 insertions(+), 24 deletions(-) diff --git a/committeeVotes/models.py b/committeeVotes/models.py index 97ce8f0..8b73bc4 100644 --- a/committeeVotes/models.py +++ b/committeeVotes/models.py @@ -2,19 +2,24 @@ from django.db import models from django.conf import settings -# Create your models here. + + class Bill(models.Model): name = models.CharField(max_length=500) oknesset_url = models.CharField(max_length=100, blank=True, null=True) passed = models.NullBooleanField() + def __unicode__(self): return self.name + class VoteType(models.Model): typeName = models.CharField(max_length=10) + def __unicode__(self): return self.typeName + class Minister(models.Model): name = models.CharField(max_length=30) title = models.CharField(max_length=100, null=True, blank=True) @@ -25,23 +30,28 @@ class Minister(models.Model): phone = models.CharField(max_length=20, null=True, blank=True) oknesset = models.CharField(max_length=100, null=True, blank=True) coop = models.NullBooleanField(blank=True) + @property def photo_url(self): url_prefix="" if 'http' not in self.photo: url_prefix=settings.MEDIA_URL - return "{prefix}{photo}.jpg".format(prefix=url_prefix,photo=self.photo) + return "{prefix}{photo}.jpg".format(prefix=url_prefix, photo=self.photo) + def __unicode__(self): return self.name + class Meeting(models.Model): took_place = models.DateField(unique=True) - proposed_bills = models.ManyToManyField(Bill, blank=True) + proposed_bills = models.ManyToManyField(Bill, blank=True, related_name="meeting") voting_ministers = models.ManyToManyField(Minister, blank=True, related_name='meeting_voting_minister') missing_ministers = models.ManyToManyField(Minister, blank=True, related_name='meeting_missing_minister') + def __unicode__(self): return "Meeting #" + str(self.id) + u" - %s" % self.took_place + class Vote(models.Model): vote = models.ForeignKey(VoteType) meeting = models.ForeignKey(Meeting) @@ -49,7 +59,7 @@ class Vote(models.Model): minister = models.ForeignKey(Minister, related_name="votes") class Meta: - unique_together = ("bill","minister") + unique_together = ("bill", "minister") def __unicode__(self): return self.minister.name + " voted " + self.vote.typeName \ No newline at end of file diff --git a/committeeVotes/serializers.py b/committeeVotes/serializers.py index b736096..5e6c0dc 100644 --- a/committeeVotes/serializers.py +++ b/committeeVotes/serializers.py @@ -41,7 +41,20 @@ class Meta: class VoteListSerializer(serializers.BaseSerializer): def to_representation(self, obj): - return obj.minister.name + return obj.minister + + +class MinisterListSerializer(serializers.ModelSerializer): + class Meta: + model = Minister + fields = ('id', 'name', 'photo_url', 'coop') + + +class VoteBillSerializer(serializers.ModelSerializer): + + class Meta: + model = Bill + fields = ('id', 'name') class BillSerializer(DynamicFieldsMixin, serializers.HyperlinkedModelSerializer): @@ -55,11 +68,25 @@ class BillVoteSerializer(DynamicFieldsMixin, serializers.HyperlinkedModelSeriali yay = serializers.SerializerMethodField() nay = serializers.SerializerMethodField() sustained = serializers.SerializerMethodField() + others = serializers.SerializerMethodField() def get_votes(self, bill, voteTypeName): voteType = VoteType.objects.get(typeName=voteTypeName) - qs = Vote.objects.filter(vote=voteType, bill=bill) - serializer = VoteListSerializer(instance=qs, many=True) + votes = Vote.objects.select_related('minister').filter(vote=voteType, bill=bill) + voted_ministers = [] + for v in votes: + voted_ministers.append(v.minister.id) + qs = Minister.objects.filter(id__in=voted_ministers) + serializer = MinisterListSerializer(instance=qs, many=True) + return serializer.data + + def get_other_ministers(self, bill): + votes = Vote.objects.select_related('minister').filter(bill=bill) + voted_ministers = [] + for v in votes: + voted_ministers.append(v.minister.id) + qs = Minister.objects.exclude(id__in=voted_ministers) + serializer = MinisterListSerializer(instance=qs, many=True) return serializer.data def get_yay(self, bill): @@ -71,15 +98,12 @@ def get_nay(self, bill): def get_sustained(self, bill): return self.get_votes(bill, u'נמנע') - class Meta: - model = Bill - fields = ('id', 'name', 'oknesset_url', 'passed', 'yay', 'nay', 'sustained') - + def get_others(self, bill): + return self.get_other_ministers(bill) -class MinisterListSerializer(serializers.ModelSerializer): class Meta: - model = Minister - fields = ('id', 'name', 'photo_url', 'coop') + model = Bill + fields = ('id', 'name', 'oknesset_url', 'passed', 'yay', 'nay', 'sustained', 'others') class MinisterSerializer(MinisterListSerializer): @@ -89,6 +113,17 @@ class Meta(MinisterListSerializer.Meta): 'facebook', 'twitter', 'mail', 'phone', 'oknesset') +class MinisterVoteSerializer(serializers.ModelSerializer): + bill = VoteBillSerializer() + vote = serializers.StringRelatedField() + + class Meta: + model = Vote + fields = ('bill', 'vote') + + + + class MeetingListSerializer(serializers.ModelSerializer): bill_count = serializers.IntegerField( source='proposed_bill_count', @@ -109,14 +144,52 @@ class Meta: class MeetingSerializer(serializers.ModelSerializer): proposed_bills = BillSerializer(many=True, read_only=True) + voting_ministers = MinisterListSerializer(many=True, read_only=True) + missing_ministers = MinisterListSerializer(many=True, read_only=True) + non_voting_ministers = serializers.SerializerMethodField() + + def get_non_voting_ministers(self, meeting): + voting_ministers = meeting.voting_ministers.all() + voting_ids = voting_ministers.values_list('id', flat=True) + missing_ministers = meeting.missing_ministers.all() + missing_ids = missing_ministers.values_list('id', flat=True) + qs = Minister.objects.exclude(id__in=voting_ids).exclude(id__in=missing_ids) + serializer = MinisterListSerializer(instance=qs, many=True) + return serializer.data + + class Meta: + model = Meeting + + +class MeetingBillSerializer(serializers.ModelSerializer): class Meta: model = Meeting + fields = ('id', 'took_place') + +class BillDetailSerializer(serializers.ModelSerializer): + votes = VoteSerializer(many=True, read_only=True) + meeting = MeetingBillSerializer(many=True, read_only=True) -class MeetingDetailSerializer(serializers.ModelSerializer): + class Meta: + model = Bill + + +class MeetingDetailSerializer(serializers.HyperlinkedModelSerializer): proposed_bills = BillVoteSerializer(many=True, read_only=True) - voting_ministers = MinisterInMeetingSerializer(many=True, read_only=True) + voting_ministers = MinisterListSerializer(many=True, read_only=True) + missing_ministers = MinisterListSerializer(many=True, read_only=True) + non_voting_ministers = serializers.SerializerMethodField() + + def get_non_voting_ministers(self, meeting): + voting_ministers = meeting.voting_ministers.all() + voting_ids = voting_ministers.values_list('id', flat=True) + missing_ministers = meeting.missing_ministers.all() + missing_ids = missing_ministers.values_list('id', flat=True) + qs = Minister.objects.exclude(id__in=voting_ids).exclude(id__in=missing_ids) + serializer = MinisterListSerializer(instance=qs, many=True) + return serializer.data class Meta: model = Meeting diff --git a/committeeVotes/views.py b/committeeVotes/views.py index 6a75a4f..d0df8e3 100644 --- a/committeeVotes/views.py +++ b/committeeVotes/views.py @@ -4,12 +4,14 @@ from django.http import HttpResponse from django.core.urlresolvers import reverse from committeeVotes.models import Bill, Minister, Vote, VoteType, Meeting -from committeeVotes.serializers import BillSerializer, MinisterSerializer,MinisterListSerializer, MeetingSerializer, MeetingListSerializer, MeetingDetailSerializer +from committeeVotes.serializers import MinisterVoteSerializer, BillSerializer, BillVoteSerializer, BillDetailSerializer, MinisterSerializer, MinisterListSerializer, MeetingSerializer, MeetingDetailSerializer, MeetingListSerializer, MeetingDetailSerializer from django.db.models import Count from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.shortcuts import render from committeeVotes.serializers import BillSerializer, MinisterSerializer from rest_framework import viewsets +from rest_framework.response import Response +from rest_framework.decorators import detail_route import json def index(request): @@ -102,9 +104,14 @@ def bills(request): return render(request, 'committeeVotes/bills.html', context) -class BillViewSet(viewsets.ModelViewSet): +class BillViewSet(viewsets.ReadOnlyModelViewSet): queryset = Bill.objects.all() - serializer_class = BillSerializer + def get_serializer_class(self): + if self.action == 'list': + return BillSerializer + if self.action == 'retrieve': + return BillVoteSerializer + return None def ministers(request): @@ -113,24 +120,36 @@ def ministers(request): return render(request, 'committeeVotes/ministers.html', context) -class MinisterViewSet(viewsets.ModelViewSet): +class MinisterViewSet(viewsets.ReadOnlyModelViewSet): queryset = Minister.objects.all() def get_serializer_class(self): - print "serializer_class" if self.action == 'list': - print "MinisterList" return MinisterListSerializer if self.action == 'retrieve': return MinisterSerializer return None + @detail_route() + def votes(self, request, pk): + minister = self.get_object() + votes = minister.votes.all() + page = self.paginate_queryset(votes) + if page is not None: + serializer = MinisterVoteSerializer(page, many=True, context={'request': request}) + return self.get_paginated_response(serializer.data) + serializer = MinisterVoteSerializer(votes, many=True, context={'request': request}) + return Response(serializer.data) + + + + def meetings(request): meetings = Meeting.objects.all().order_by('-id') context = {'meetings': meetings} return render(request, 'committeeVotes/meetings.html', context) -class MeetingsViewSet(viewsets.ModelViewSet): +class MeetingsViewSet(viewsets.ReadOnlyModelViewSet): queryset = Meeting.objects.annotate( proposed_bill_count=Count('proposed_bills')).all() diff --git a/openCommittee/urls.py b/openCommittee/urls.py index 9fc153e..4a7b218 100644 --- a/openCommittee/urls.py +++ b/openCommittee/urls.py @@ -12,7 +12,7 @@ router = routers.DefaultRouter() router.register(r'bills', views.BillViewSet) router.register(r'ministers', views.MinisterViewSet) -router.register(r'meetings',views.MeetingsViewSet) +router.register(r'meetings', views.MeetingsViewSet) urlpatterns = patterns('', # Examples: # url(r'^$', 'openCommittee.views.home', name='home'),