Skip to content

Commit

Permalink
Merged develop into feature/dynamiccharts
Browse files Browse the repository at this point in the history
  • Loading branch information
pbellon committed Feb 20, 2014
2 parents b7483ca + 405e438 commit a6c2ec9
Show file tree
Hide file tree
Showing 42 changed files with 1,184 additions and 158 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ before_install:
- xargs -a npm_requirements.txt npm install -g
- export DJANGO_SETTINGS_MODULE="app.settings_tests"
install:
- pip install --use-mirrors -r tests_requirements.txt
- pip install --use-mirrors -r requirements.txt
- pip install --use-mirrors coveralls
- python ./manage.py syncdb --pythonpath=. --noinput
matrix:
Expand Down
74 changes: 40 additions & 34 deletions app/api/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,36 @@
from rest_framework import status
from rest_framework import serializers

from django.contrib.contenttypes.models import ContentType

class InheritedModelCreateMixin(mixins.CreateModelMixin):
# If you want to have only one serializer for a BaseClass and all its inherithed
# classes then you should use this mixin
#
# This mixin is heavily inspired from rest_framework.mixins.CreateModelMixin
def create(self, request, *args, **kwargs):
# only variation: we don't use directly self.get_serializer but we want
# the final serializer: i.e. the appropriated serializer for the given
# request DATA.
serializer = self.get_final_serializer(data=request.DATA, files=request.FILES)
if serializer.is_valid():
self.pre_save(serializer.object)
self.object = serializer.save(force_insert=True)
self.post_save(self.object, created=True)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED,
headers=headers)

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

def get_final_serializer(self, data, files):
base_serializer = self.get_serializer(data=data, files=files)
assert isinstance(base_serializer, InheritedModelMixin)
return base_serializer.as_final_serializer(data=data, files=files)


class InheritedModelMixin(serializers.ModelSerializer):

def __init__(self, *args, **kwargs):
error_msg = "{klass} subclasses must implement model_mapping attribute".format(
klass=self.__class__.__name__)
Expand All @@ -13,14 +42,10 @@ def __init__(self, *args, **kwargs):
def to_native(self, value):
if not value:
return None
try:
base_data = super(InheritedModelMixin, self).to_native(value)
except Exception as e:
import pdb; pdb.set_trace()

base_data = super(InheritedModelMixin, self).to_native(value)
serializer = self.get_final_serializer(value)
if serializer:
base_data.update(serializer(value).data)
base_data.update(serializer(value, context=self.context).data)
return base_data

def get_final_serializer(self, value):
Expand All @@ -36,31 +61,8 @@ def get_final_serializer(self, value):
if match:
return self.model_mapping[model_klass]


class InheritedModelCreateMixin(mixins.CreateModelMixin):
# took from rest_framework.mixins.CreateModelMixin.create() base method
def create(self, request, *args, **kwargs):
# only variation: we don't use directly self.get_serializer but we want
# the final serializer: i.e. the appropriated serializer for the given
# request DATA.
serializer = self.get_final_serializer(data=request.DATA, files=request.FILES)
if serializer.is_valid():
self.pre_save(serializer.object)
self.object = serializer.save(force_insert=True)
self.post_save(self.object, created=True)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED,
headers=headers)

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

def get_final_serializer(self, data, files):
base_serializer = self.get_serializer(data=data, files=files)
assert isinstance(base_serializer, InheritedModelMixin)
return base_serializer.as_final_serializer(data=data, files=files)

class ContentTypeMixin(serializers.ModelSerializer):

class GenericModelMixin(serializers.ModelSerializer):

def get_ctype_serializer(self, value):
ctype, cobject = self.get_generic(value)
ctype_mapping = self.get_mapping()
Expand All @@ -71,10 +73,12 @@ def get_ctype_serializer(self, value):

def get_generic(self, value):
ctype = getattr(value, 'content_type', None)
if not ctype:
ctype = ContentType.objects.get_for_model(value)

obj_id = getattr(value, 'object_id', None)
# first try to resolve content object
cobject = getattr(value, 'content_object', None)
assert ctype != None
# if doesn't have a local content_object then we assign it here
if cobject is None:
cobject = ctype.model_class().objects.get(pk=obj_id or value.pk)
Expand All @@ -85,8 +89,10 @@ def get_mapping(self):

def to_native(self, value):
ctype, cobject = self.get_generic(value)
base_data = super(ContentTypeMixin, self).to_native(value)
base_data = super(GenericModelMixin, self).to_native(value)
ctype_serializer = self.get_ctype_serializer(value)
if ctype_serializer:
base_data.update(ctype_serializer(cobject).data)
base_data.update(ctype_serializer(cobject, context=self.context).data)
return base_data


35 changes: 27 additions & 8 deletions app/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@
from app.core.models import *
from app.api import mixins


class ResultsSerializer(serializers.Serializer):
def to_native(self, value):
return value.as_dict()

class MediaChoiceFieldSerializer(serializers.ModelSerializer):
class Meta:
model = MediaChoiceField
fields = ('picture',)

class ChoiceField(mixins.ContentTypeMixin):
class ChoiceField(mixins.GenericModelMixin):
ctype_mapping = {
MediaChoiceField: MediaChoiceFieldSerializer
}
Expand Down Expand Up @@ -79,23 +84,35 @@ class Meta:
exclude = ('content_type',)


class QuestionResultsSerializer(QuestionSerializer):
model_mapping = question_mapping
results = serializers.Field()
class QuestionResultsSerializer(mixins.InheritedModelMixin):
model_mapping = question_mapping
typology = serializers.Field()
results = serializers.SerializerMethodField('get_results')

class Meta:
model = BaseQuestion
exclude = ('content_type',)
depth = 1



def get_results(self, question):
request = self.context['request']
params = request.QUERY_PARAMS
filters = {}
filters['age_min'] = params.get('age_min', None)
filters['age_max'] = params.get('age_max', None)
filters['gender'] = params.get('gender', None)
serializer = ResultsSerializer(question.results(**filters))
return serializer.data



# -----------------------------------------------------------------------------
#
# Generic thematic elements
#
# -----------------------------------------------------------------------------
class ThematicElementSerializer(mixins.ContentTypeMixin):
class ThematicElementSerializer(mixins.GenericModelMixin):
type = serializers.Field()
ctype_mapping = {
BaseFeedback: FeedbackSerializer,
Expand All @@ -109,9 +126,11 @@ class Meta:
depth = 0

class ThematicElementResultsSerializer(ThematicElementSerializer):
# same as ThematicElementSerializer but instead of using a QuestionSerializer
# we use a QuestionResultsSerializer
ctype_mapping = {
BaseFeedback: FeedbackSerializer,
BaseQuestion: QuestionResultsSerializer
BaseQuestion: QuestionResultsSerializer
}

# -----------------------------------------------------------------------------
Expand All @@ -124,7 +143,7 @@ class ThematicSerializer(serializers.ModelSerializer):
class Meta:
model = Thematic
fields = ('id', 'title', 'intro_description', 'intro_button_label',
'elements')
'elements', 'slug')
depth = 1

class NestedThematicSerializer(ThematicSerializer):
Expand Down

0 comments on commit a6c2ec9

Please sign in to comment.