How to make Tastypie reject unrecognized input data - django

I am currently using Tastypie to provide a programmatic interface to my Django database. On problem that I've run into a couple of times is that when client code uploads data for a field that doesn't exist, Tastypie ignores it. This means that the client code has no idea that some of the data that it tried to upload was ignored. I'd like to tell the client that it tried to upload an unknown field, possible with a status code 406 (not acceptable).
I have two related questions:
Is it appropriate for RESTful design to reject this extra data?
If so, is there a tidy way to do this through Tastypie?
As an example of my concern, consider this toy Tastypie API:
from tastypie import resources, fields
class DemoResource(resources.ModelResource):
name = fields.CharField()
optional = fields.CharField(blank=True)
If client code uploaded the json data: {name: "new data", optioanl: "this field is misspelled"}, the misspelled optional field would be ignored. My current plan is to use a Tastypie validator to compare the bundle data against the bundle object, but this seems really non-DRY.

Related

Creating a Django Rest Api to Store Values

I have a python parser who creates two python lists, first one contains some IDs and the second one contains ip:port information which corresponds to those ID's. I need to create a django rest api to send these values and store them. I tried to read django documentation but I still don't know what to do, where to start. Can anyone help me? Thanks in advance.
The question is not easy to answer, although I can show you the right direction.
Django uses the Model object to interact with database. Therefore you should create one model with two fields. The first one is ID (although read the documentation carefully, Django can create the ID automatically for you) and the second one should be a String (or really object of your choice) to store IP/Port information. For information about models, visit the following page:
https://docs.djangoproject.com/en/2.1/topics/db/models/
To submit your information to Django back-end, POST request should be used. What is POST request is beyond the scope of this comment, so I will just expect that you know what it is. Open your urls.py file and make an endpoint for this particular request. More information can be found here: https://docs.djangoproject.com/en/2.1/topics/http/urls/.
To create a form for user, Django offers great object called Form. You need to create one in the forms.py file. To give you an example:
from yourapp.models import YourModelObject
class InformationForm(forms.ModelForm):
class Meta:
model = YourModelObject
fields = ('id', 'ipportField')
To read more about forms, check the following doc: https://docs.djangoproject.com/en/2.1/topics/forms/

How to lock a transaction in Django?

There is a case when request is sent multiple times to the server with same data. I want to insert that data in database using ORM of Django. In that data there is a field say 'field_imp' which can only be unique. Right now it gives me integrity error as both the request are trying to insert together. How do I avoid this condition?
How to send multiple request together?
Using terminator open multiple tabs, write the same curl request and send.
Model in Django:
class MyModel(models.Model)
field_imp = models.TextField(unique=True)
I am using Django rest Framework for the api generation and its serializers for data's validation.
The first Method is to lock table,but it is low efficiency;
The second Method is to add both two code points:
add exist check into the serializer.
add try...catch... for integrity error.
I used get_or_create() intead of serializer.save().

Django rest framework - thumbnail image serializer

My case is basic: I want to send urls of thumbnails to the client within responses to AJAX requests. I have custom image fields that deserialize base64 encoded images from the client and sorl_thumbnail as thumbnail engine. In my views I want to instantiate deserializer with arbitrary options for thumbnailer.
What is a common techniques for that in Django REST framework?
upd
The main problem is how to pass arguments about dimensions, format, quality, etc, to serializer? In one place I might need small thumbnail of the picture, in other bigger thumbnail.
Now I see two approaches:
- Make a factory which will produce serializer with given options for thumbnail-fields
- Send thumbnail options within AJAX requests and make serializer able to read and follow them.
There are lots of ways you could go about this, depending on a lot of information you don't give, but, perhaps look into using a SerializerMethodField in your serializer.
The basic idea would be to create a method that is able to return the appropriate URL for the thumbnail given the object instance and bind the SerializerMethodField to that.
By default DRF's GenericViews pass the request through to serializers via the context parameter. This enables you to access the request with such as request = self.context.get('request', None). From there you can read the thumbnail options as you suggest.
Hopefully that's enough to get you started.

More Blobstore upload woes with standard Django

I'm implementing an image upload feature for my Django app (plain Django 1.4 , NOT the non-rel version) running on Google App Engine. The uploaded image is wrapped in a Django model which allows the user to add attributes like a caption and search tags.
The upload is performed by creating a Blobstore upload url through the function call blobstore.create_upload_url(url). The function argument is the url to which the Bobstore redirects when the upload is complete. I want this to be the url of the default Django form handler that performs the save/update of the model that wraps the image so I don't have to duplicate default Django behaviour for form validation, error reporting and database update.
I tried supplying reverse('admin:module_images_add') to create_upload_url() but this doesn't work as it throws an [Errno 30] Read-only file system exception. I presume this originates from the default Django form handler again trying to upload the file the standard Django way but then hits the brick wall of Google App Engine not allowing access to the file system.
At the moment, the only way I can see to get this working without duplicating code is by strictly separating processes: one for defining an image model instance and the second for uploading the actual image. Not very intuitive.
See also this question and answer which I posted earlier.
Any suggestions on how to get this working using one form and reusing Django default form handlers?
EDIT:
I've been reading up on decorators (I'm relatively new to Python) and from what I read, decorators appear to able to modify the behaviour of existing Python code. Would it be possible to change the runtime behaviour of the existing form handler to solve the above using a decorator? I obviously have to (1) develop the decorator and (2) attach it to the default handler. I'm not sure if (2) is possible as it has to be done runtime. I cannot patch the Django code running on GAE...
Well, I finally managed to get this working. Here's what I did in case anyone runs into this as well:
(1) I removed the ImageFile attribute from my model. It ended up causing Django to try and do a file upload from the file system which is not allowed in GAE.
(2) I added a Blobstore key to my model which is basically the key to the GAE BlobStore blob and is required to be able to serve the image at a later stage. On a side note: this attribute has limited length using the GAE SDK but is considerably longer in GAE production. I ended up defining a TextField for it.
(3) Use storage.py with Daniel Roseman's adaption from this question and add the BlobstoreFileUploadHandler to the file handlers in your SETTINGS.PY. It will ensure that the Blobstore key is there in the request for you to save with your model.
(4) I created a custom admin form which contains an ImageField named "image". This is required as it allows you to pick a file. The ImageField is actually "virtual" as its only purpose on the form is to allow me to pick a file for uploading. This is crucial as per (1).
(5) I overwrote render_change_form() method of my ModelAdmin class which will prepare a Blobstore upload url. The upload url has two versions: one for adding new images and one saving changes to existing. Upload urls are passed to the template via the context object.
(6) I modified the change_form.html to include the Blobstore upload url from (5) as the form's action.
(7) I overwrote the save_model() method of my ModelAdmin:
def save_model(self, request, obj, form, change):
if request.FILES.has_key("blobkey"):
blob_key = request.FILES["blobkey"].blobstore_info._BlobInfo__key
obj.blobstore_key = blob_key
super(PhotoFeatureAdmin, self).save_model(request, obj, form, change)
This allows me to retrieve the blob key as set by the upload handler and set it as a property of my model.
For deletion of image models, I added a special function which is triggered by the delete signal of the model. This will keep the Blobstore in sync with the image models in the app.
That's it. The above allows to upload images to the blob store of GAE where each blob is neatly wrapped in a Django model object which admin users can maintain. The good thing is that there's no need to duplicate standard Django behaviour and the model object of the image can easily be extended with attributes in the future.
Final word: in my opinion the support for blobs in plain Django on GAE is currently very poor considering the above. It should be much easier to achieve this, without having to rely on Django non-rel code and a rather long list of modifications; alternatively Google should state something about this in their developer documents. Unless I missed something, this is undocumented territory.

Django REST API to receive images

I have a Django project using Tastypie as its main API and it works ok. But now I want to be able to receive images through the API (coming from phones and such). It looks like Tastypie is not quite ready yet in that field. I'm ready to try something else just for that matter, or even write a custom view. How can I do that?
A standard Django view can technically serve as an API endpoint, too, so why not just write a view that handles a POST payload?
You could even make a form which you use to validate the input, even if your client device isn't using that form to capture content - as long as the fields and their criteria match up, it'll still fit.