blob: 89a2b1801d506ae61e393c3a76969dcfee0bc9ca [file] [log] [blame]
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -05001from rest_framework.decorators import api_view
2from rest_framework.response import Response
3from rest_framework.reverse import reverse
4from rest_framework import serializers
Sapan Bhatiadf2b49e2014-01-28 19:41:07 -05005from rest_framework import generics
Scott Baker89a7b7c2014-10-07 00:10:17 -07006from rest_framework import status
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -05007from core.models import *
8from django.forms import widgets
Scott Baker46b58542014-08-11 17:26:12 -07009from rest_framework import filters
Scott Bakerf556b922014-11-10 15:58:58 -080010from django.conf.urls import patterns, url
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -050011
12"""
Sapan Bhatiaf69dd5c2014-10-08 11:34:23 -040013 Schema of the generator object:
14 all: Set of all Model objects
15 all_if(regex): Set of Model objects that match regex
16
17 Model object:
18 plural: English plural of object name
19 camel: CamelCase version of object name
20 refs: list of references to other Model objects
21 props: list of properties minus refs
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -050022
Sapan Bhatiaf69dd5c2014-10-08 11:34:23 -040023 TODO: Deal with subnets
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -050024"""
25
Scott Bakerf556b922014-11-10 15:58:58 -080026def get_REST_patterns():
27 return patterns('',
28 url(r'^plstackapi/$', api_root),
29 {% for object in generator.all %}
30 url(r'plstackapi/{{ object.rest_name }}/$', {{ object.camel }}List.as_view(), name='{{ object.singular }}-list'),
31 url(r'plstackapi/{{ object.rest_name }}/(?P<pk>[a-zA-Z0-9\-]+)/$', {{ object.camel }}Detail.as_view(), name ='{{ object.singular }}-detail'),
32 {% endfor %}
33 )
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -050034
35@api_view(['GET'])
36def api_root(request, format=None):
37 return Response({
Sapan Bhatiaf69dd5c2014-10-08 11:34:23 -040038 {% for object in generator.all %}'{{ object.plural }}': reverse('{{ object }}-list', request=request, format=format),
39 {% endfor %}
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -050040 })
41
42# Based on serializers.py
43
44{% for object in generator.all %}
45
46class {{ object.camel }}Serializer(serializers.HyperlinkedModelSerializer):
Sapan Bhatiaf69dd5c2014-10-08 11:34:23 -040047 id = serializers.Field()
48 {% for ref in object.refs %}
49 {% if ref.multi %}
50 {{ ref.plural }} = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='{{ ref }}-detail')
51 {% else %}
52 {{ ref }} = serializers.HyperlinkedRelatedField(read_only=True, view_name='{{ ref }}-detail')
53 {% endif %}
54 {% endfor %}
55 class Meta:
56 model = {{ object.camel }}
57 fields = ({% for prop in object.props %}'{{ prop }}',{% endfor %}{% for ref in object.refs %}{%if ref.multi %}'{{ ref.plural }}'{% else %}'{{ ref }}'{% endif %},{% endfor %})
Scott Baker9a270922014-07-03 18:01:30 -070058
59class {{ object.camel }}IdSerializer(serializers.ModelSerializer):
Sapan Bhatiaf69dd5c2014-10-08 11:34:23 -040060 id = serializers.Field()
61 {% for ref in object.refs %}
62 {% if ref.multi %}
63 {{ ref.plural }} = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='{{ ref }}-detail')
64 {% else %}
65 {{ ref }} = serializers.HyperlinkedRelatedField(read_only=True, view_name='{{ ref }}-detail')
66 {% endif %}
67 {% endfor %}
68 class Meta:
69 model = {{ object.camel }}
70 fields = ({% for prop in object.props %}'{{ prop }}',{% endfor %}{% for ref in object.refs %}{%if ref.multi %}'{{ ref.plural }}'{% else %}'{{ ref }}'{% endif %},{% endfor %})
Scott Baker9a270922014-07-03 18:01:30 -070071
72
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -050073{% endfor %}
74
75serializerLookUp = {
76{% for object in generator.all %}
77 {{ object.camel }}: {{ object.camel }}Serializer,
78{% endfor %}
79 None: None,
80 }
81
Scott Baker89a7b7c2014-10-07 00:10:17 -070082class PlanetStackRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
83
84 # To handle fine-grained field permissions, we have to check can_update
85 # the object has been updated but before it has been saved.
86
87 def update(self, request, *args, **kwargs):
88 partial = kwargs.pop('partial', False)
89 self.object = self.get_object_or_none()
90
91 serializer = self.get_serializer(self.object, data=request.DATA,
92 files=request.FILES, partial=partial)
93
94 if not serializer.is_valid():
95 print "UpdateModelMixin: not serializer.is_valid"
96 print serializer.errors
97 return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
98
99 try:
100 self.pre_save(serializer.object)
101 except ValidationError as err:
102 # full_clean on model instance may be called in pre_save,
103 # so we have to handle eventual errors.
104 return Response(err.message_dict, status=status.HTTP_400_BAD_REQUEST)
105
106 if serializer.object is not None:
107 if not serializer.object.can_update(request.user):
108 return Response(status=status.HTTP_400_BAD_REQUEST)
109
110 if self.object is None:
111 self.object = serializer.save(force_insert=True)
112 self.post_save(self.object, created=True)
113 return Response(serializer.data, status=status.HTTP_201_CREATED)
114
115 self.object = serializer.save(force_update=True)
116 self.post_save(self.object, created=False)
117 return Response(serializer.data, status=status.HTTP_200_OK)
118
119 def destroy(self, request, *args, **kwargs):
120 obj = self.get_object()
121 if obj.can_update(request.user):
Scott Bakeradcbf7a2014-10-09 11:09:15 -0700122 return super(generics.RetrieveUpdateDestroyAPIView, self).destroy(request, *args, **kwargs)
Scott Baker89a7b7c2014-10-07 00:10:17 -0700123 else:
124 return Response(status=status.HTTP_400_BAD_REQUEST)
125
126
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -0500127# Based on core/views/*.py
128{% for object in generator.all %}
129
130class {{ object.camel }}List(generics.ListCreateAPIView):
Sapan Bhatiadf2b49e2014-01-28 19:41:07 -0500131 queryset = {{ object.camel }}.objects.select_related().all()
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -0500132 serializer_class = {{ object.camel }}Serializer
Scott Baker9a270922014-07-03 18:01:30 -0700133 id_serializer_class = {{ object.camel }}IdSerializer
Scott Baker46b58542014-08-11 17:26:12 -0700134 filter_backends = (filters.DjangoFilterBackend,)
135 filter_fields = ({% for prop in object.props %}'{{ prop }}',{% endfor %}{% for ref in object.refs %}{%if ref.multi %}'{{ ref.plural }}'{% else %}'{{ ref }}'{% endif %},{% endfor %})
Scott Baker9a270922014-07-03 18:01:30 -0700136
137 def get_serializer_class(self):
138 no_hyperlinks = self.request.QUERY_PARAMS.get('no_hyperlinks', False)
139 if (no_hyperlinks):
140 return self.id_serializer_class
141 else:
142 return self.serializer_class
143
Tony Mackeb8eb312014-02-04 20:50:39 -0500144 def get_queryset(self):
Tony Mack8f04ee32014-02-05 10:27:39 -0500145 return {{ object.camel }}.select_by_user(self.request.user)
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -0500146
Tony Mack9525eba2014-02-05 10:57:21 -0500147 def create(self, request, *args, **kwargs):
Scott Bakeradcbf7a2014-10-09 11:09:15 -0700148 obj = {{ object.camel }}(**request.DATA)
149 obj.caller = request.user
150 if obj.can_update(request.user):
151 return super({{ object.camel }}List, self).create(request, *args, **kwargs)
152 else:
153 raise Exception("failed obj.can_update")
154
Sapan Bhatiaf69dd5c2014-10-08 11:34:23 -0400155 ret = super({{ object.camel }}List, self).create(request, *args, **kwargs)
156 if (ret.status_code%100 != 200):
157 raise Exception(ret.data)
Scott Bakeradcbf7a2014-10-09 11:09:15 -0700158
159 return ret
160
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -0500161
Scott Baker89a7b7c2014-10-07 00:10:17 -0700162class {{ object.camel }}Detail(PlanetStackRetrieveUpdateDestroyAPIView):
Sapan Bhatiadf2b49e2014-01-28 19:41:07 -0500163 queryset = {{ object.camel }}.objects.select_related().all()
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -0500164 serializer_class = {{ object.camel }}Serializer
Scott Baker46b58542014-08-11 17:26:12 -0700165 id_serializer_class = {{ object.camel }}IdSerializer
166
167 def get_serializer_class(self):
168 no_hyperlinks = self.request.QUERY_PARAMS.get('no_hyperlinks', False)
169 if (no_hyperlinks):
170 return self.id_serializer_class
171 else:
172 return self.serializer_class
Tony Mackeb8eb312014-02-04 20:50:39 -0500173
174 def get_queryset(self):
Tony Mack9525eba2014-02-05 10:57:21 -0500175 return {{ object.camel }}.select_by_user(self.request.user)
176
Scott Baker89a7b7c2014-10-07 00:10:17 -0700177 # update() is handled by PlanetStackRetrieveUpdateDestroyAPIView
Tony Mack9525eba2014-02-05 10:57:21 -0500178
Scott Baker89a7b7c2014-10-07 00:10:17 -0700179 # destroy() is handled by PlanetStackRetrieveUpdateDestroyAPIView
Sapan Bhatia3bbf5ed2014-01-13 13:29:12 -0500180
181{% endfor %}