user's can't set/unset is_admin, is_active and is_readonly values in Login Details...
[plstackapi.git] / planetstack / apigen / api.template.py
index 2cfb54a..9edaaa2 100644 (file)
@@ -10,6 +10,13 @@ from django.forms import widgets
 from rest_framework import filters
 from django.conf.urls import patterns, url
 
+if hasattr(serializers, "ReadOnlyField"):
+    # rest_framework 3.x
+    IdField = serializers.ReadOnlyField
+else:
+    # rest_framework 2.x
+    IdField = serializers.Field
+
 """
     Schema of the generator object:
         all: Set of all Model objects
@@ -42,10 +49,62 @@ def api_root(request, format=None):
 
 # Based on serializers.py
 
+class XOSModelSerializer(serializers.ModelSerializer):
+    def save_object(self, obj, **kwargs):
+
+        """ rest_framework can't deal with ManyToMany relations that have a
+            through table. In plstackapi, most of the through tables we have
+            use defaults or blank fields, so there's no reason why we shouldn't
+            be able to save these objects.
+
+            So, let's strip out these m2m relations, and deal with them ourself.
+        """
+        obj._complex_m2m_data={};\r
+        if getattr(obj, '_m2m_data', None):\r
+            for relatedObject in obj._meta.get_all_related_many_to_many_objects():\r
+                if (relatedObject.field.rel.through._meta.auto_created):\r
+                    # These are non-trough ManyToMany relations and\r
+                    # can be updated just fine\r
+                    continue\r
+                fieldName = relatedObject.get_accessor_name()\r
+                if fieldName in obj._m2m_data.keys():\r
+                    obj._complex_m2m_data[fieldName] = (relatedObject, obj._m2m_data[fieldName])\r
+                    del obj._m2m_data[fieldName]\r
+\r
+        serializers.ModelSerializer.save_object(self, obj, **kwargs);
+
+        for (accessor, stuff) in obj._complex_m2m_data.items():
+            (relatedObject, data) = stuff
+            through = relatedObject.field.rel.through
+            local_fieldName = relatedObject.field.m2m_reverse_field_name()
+            remote_fieldName = relatedObject.field.m2m_field_name()
+
+            # get the current set of existing relations
+            existing = through.objects.filter(**{local_fieldName: obj});
+
+            data_ids = [item.id for item in data]
+            existing_ids = [getattr(item,remote_fieldName).id for item in existing]
+
+            #print "data_ids", data_ids
+            #print "existing_ids", existing_ids
+
+            # remove relations that are in 'existing' but not in 'data'
+            for item in list(existing):
+               if (getattr(item,remote_fieldName).id not in data_ids):
+                   print "delete", getattr(item,remote_fieldName)
+                   item.delete() #(purge=True)
+
+            # add relations that are in 'data' but not in 'existing'
+            for item in data:
+               if (item.id not in existing_ids):
+                   #print "add", item
+                   newModel = through(**{local_fieldName: obj, remote_fieldName: item})
+                   newModel.save()
+
 {% for object in generator.all %}
 
 class {{ object.camel }}Serializer(serializers.HyperlinkedModelSerializer):
-    id = serializers.Field()
+    id = IdField()
     {% for ref in object.refs %}
     {% if ref.multi %}
     {{ ref.plural }} = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='{{ ref }}-detail')
@@ -66,13 +125,13 @@ class {{ object.camel }}Serializer(serializers.HyperlinkedModelSerializer):
         model = {{ object.camel }}
         fields = ('humanReadableName', 'validators', {% for prop in object.props %}'{{ prop }}',{% endfor %}{% for ref in object.refs %}{%if ref.multi %}'{{ ref.plural }}'{% else %}'{{ ref }}'{% endif %},{% endfor %})
 
-class {{ object.camel }}IdSerializer(serializers.ModelSerializer):
-    id = serializers.Field()
+class {{ object.camel }}IdSerializer(XOSModelSerializer):
+    id = IdField()
     {% for ref in object.refs %}
     {% if ref.multi %}
-    {{ ref.plural }} = serializers.PrimaryKeyRelatedField(many=True, read_only=True) #, view_name='{{ ref }}-detail')
+    {{ ref.plural }} = serializers.PrimaryKeyRelatedField(many=True,  queryset = {{ ref.camel }}.objects.all())
     {% else %}
-    {{ ref }} = serializers.PrimaryKeyRelatedField(read_only=True) #, view_name='{{ ref }}-detail')
+    {{ ref }} = serializers.PrimaryKeyRelatedField( queryset = {{ ref.camel }}.objects.all())
     {% endif %}
     {% endfor %}
     humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
@@ -84,7 +143,7 @@ class {{ object.camel }}IdSerializer(serializers.ModelSerializer):
             return obj.getValidators()
         except:
             return None\r
-    class Meta:
+    class Meta:\r
         model = {{ object.camel }}
         fields = ('humanReadableName', 'validators', {% for prop in object.props %}'{{ prop }}',{% endfor %}{% for ref in object.refs %}{%if ref.multi %}'{{ ref.plural }}'{% else %}'{{ ref }}'{% endif %},{% endfor %})