What I would like to do is
1) Allow the user select an image 2) get the image and add it to a canvas 3) allow manipulation (re-sizing) inside of the canavs 4) Push "Upload" 5) Take the canvas and generate a data URI off of it
This all works dandy in JS leaving me with three hidden fields:
<input type="hidden" id="imageData" name="imageData" />
<input type="hidden" id="imageName" name="imageName" />
<input type="hidden" id="imageCaption" name="imageCaption" />
Here is the Python code
class Image(models.Model):
filePath = models.CharField(max_length=200)
imageCaption = models.CharField(max_length=200)
imageName = models.CharField(max_length=200)
class ImageSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Image
fields = ('filePath', 'imageCaption','imageName')
class ImageViewSet(viewsets.ModelViewSet):
queryset = Image.objects.all()
serializer_class = ImageSerializer
I am missing some key points here.
1) Where / how do I intercept the rest request to parse / handle the incoming REST post to be able to pull apart the Data URI and store the image on disk?
2) I probably don't understand a bunch of this - so if there is something else I am missing, please let me know
I think the trick is in overriding the serializer restore fields method. When it looks for the "file" field, which is built off of the model.FileField, i need to redirect the framework to look for the dataUri field which is the field getting passed, but I need to instantiate a new field,with no limits on the max length. Pull the dataUri apart, store the file, and add the file field to the dictionary of parsed resources and let the framework continue as planned. Overriding the pre_save was not necessary in this case, as this code needed to execute prior to the validation.
JS:
// angularJs controller submit method, using RESTAngular
$scope.submit = function() { //function(event) {
var someImg = {
file: ''
, dataUri: $scope.fileUrl
, caption: $scope.caption
}
ImagesResource.post(someImg )
}
Python:
class ImageSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Image
fields = ('file', 'caption','id')
def saveImage(self, imgFileUri):
#parse dataUri and save locally, return local path
return 'somewhereOverTheBlah'
def restore_fields(self, data, files):
"""
Core of deserialization, together with `restore_object`.
Converts a dictionary of data into a dictionary of deserialized fields.
"""
reverted_data = {}
if data is not None and not isinstance(data, dict):
self._errors['non_field_errors'] = ['Invalid data']
return None
for field_name, field in self.fields.items():
print('a: ' + field_name)
if(field_name == 'file'):
field_name = 'dataUri'
field = fields.CharField()
try:
# restore using the built in mechanism
field.field_from_native(data, files, field_name, reverted_data)
# take the dataUri, save it to disk and return the Path
value = reverted_data[field_name]
path = self.saveImage(value)
# set the file <Path> property on the model, remove the old dataUri
reverted_data['file'] = path
del reverted_data[field_name]
except ValidationError as err:
self._errors[field_name] = list(err.messages)
else:
field.initialize(parent=self, field_name=field_name)
try:
field.field_from_native(data, files, field_name, reverted_data)
except ValidationError as err:
self._errors[field_name] = list(err.messages)
return reverted_data