use tastypie for non-crud operations - django

I'm starting with tasty pie and have a few questions, I'm a little lost.
As I could see, I can create a resource using ModelResource if I'm using a django model or use only Resource if I'm using a non-orm resource. But what I don't understand is if I always have to "map" a tastypie resource with some entity. What if I don't need to use CRUD operations? for example temperature conversions or math operations where I don't need to query any table? or for instance if I only want an api called /status where I query a few tables, make some calculations and return only an "up" string in json format or something like that when I do a GET request? Is tasty useful for this?
thanks!

Related

Django Graphene/GraphQL best design for model field-level permissions

I am using Django as back-end with graphene-django serving the front-end. I am new to both django and graphene so I am not sure what is the best approach to achieve field-level permissions with no code repetition in this set-up. For example, if my model is:
class MyModel(models.Model):
field1 = models.CharField()
field2 = models.CharField()
I want to be able to specify that user1 can read field1 but not field2; when the user1 queries GraphQL for all MyModels it would be only allow to retrieve field1 from rows (nodes) and not field2.
I did a bit of research and found 2 possible alternative solutions but I fear they may not be in the spirit of Django framework and/or conflicting with each other and there may be a better way to achieve this in Django. Ultimately I don't want to be repeating the permissions code in multiple parts of the Django and Graphene back-end so want this to be centralised at the lowest possible level, ideally at the Django model. I need to be able to control full CRUD per field depending on user_id and maybe even have some additional logic. The options I found were:
overriding get_node resolver in graphene-django DjangoObjectType to check for permissions there. Personally I see this as a very bad and last-resort solution as the checks are done only on graphql query/mutation layer and not elsewhere in Django. I could easily write a Django form or view that would not benefit from the permission check unless this is coded again in that form/view.
I could extend the Django model to perform arbitrary per-field checks and this seems the right level where to enforce permission checks but ideally I would prefer to use built-in features or a 'popular' library for this type of stuff. I tried searching for a library but I couldn't find anything that is even remotely production ready or gaining any traction - which leads me to the consider that there may be a better approach to address this problem. Django-field-permissions package seemed on the right path though.
I was wondering if anyone has a view on the best approach to solving this problem that fits Django and Graphene frameworks and without repeating the permissions code everywhere?
You're not going to find a stable/popular package for this, as it's not a design that a database can support well.
You cannot link (Foreign Key) a field and a table, you can only link two tables using a field. Therefore, any work to determine whether a row in a table has access to a field in another table, will be costly and error prone.
The best you could do, is to write a service layer that sits in between a resolver and a model that nullifies fields a user has no access to. You pass it the user (info.context.user) and a model, and it does a separate query to a field permissions model, fetches the record and nullifies each field according to permissions.
This inherently means each field needs to be nullable in order to support the permissions, complicating the frontend - it's a lot of work...
A better approach if your business logic allows it, is to group those fields into models, that can then be tied to "roles" or groups. So if this were medical data in a hospital:
- name ----- \
- address | -> Person model => all personnel, except custodial
- birth date -/
- medication -------\
- patient history | => PatientStatus model => all medically trained personnel
- current physician /
- ...
That way you use standard built-in permissions to deny access to entire tables (as illustrated above) and object level permissions (Guardian, Authority) to deny access to all but the current physician for the really classified things.
Hope this helps and good luck!

Django ElasticSearch DSL DRF aggregations

What is the correct approach to adding aggregations to Django ElasticSearch DSL DRF? The codebase contains some empty filter backends
https://github.com/barseghyanartur/django-elasticsearch-dsl-drf/tree/a2be5842e36a102ad66988f5c74dec984c31c89b/src/django_elasticsearch_dsl_drf/filter_backends/aggregations
Should I create a custom backend or is there a way to add them directly to my viewset?
In particular, I want to calculate the sum of an IntegerField across all results in a particular facet.
Elasticsearch has more than one type of aggregations. Simple aggregations in the django-elasticsearch-dsl-drf are implemented in the FacetedSearchFilterBackend. Read the docs or simply run the example project to run experiments.

Using an exisiting AppSync API w/ Amplify

Using:
AppSync, DynamoDB, and Lambda
So I am a bit stuck on how to integrate AppSync within Amplify in React Native. I have an existing API within AWS AppSync that I created on the console. This API has several different models like: Users, Videos, VideoComments, etc. Some of the objects within these models have custom mapping templates and resolvers that are really important for the application.
For Example, this is a quick look at what we have schema wise.
type User {
userId: Id!
name: String
uploadedVideos(limit: Int, nextToken: String): VideoConnection
etc etc
}
type Video {
videoID: Id!
object: S3Object
userId: Id!
uploadedBy: User
}
We have a resolver that runs with a simple getVideo query that will retrieve the uploadedBy attribute by using the userId, and retrieves all the necessary information of that user.
Additionally, the data sources (dynamoDb tables) we created for the models have primary keys, and some have sort keys. Like a VideoLikes table keeps track of who liked a video and to avoid duplicates the primary key is the VideoID and the sort key is UserID. This is just a minor example, we have other places where we do this to also have access to LSIs.
When I started using Amplify, I tried recreating the AppSync API because I liked how powerful the CloudFormation capabilities were with the different staging environments. However, I noticed the DynamoDB for models were automatically defined and were automatically set to an id as a primary key. We use the LSIs to help sort by certain values, like for a video if we wanted to sort by the number of likes, or comments, so unfortunately this would not work for us. So when I noticed this, I used the "Codegen" command from my original AppSync API and ran into the issue where my resolvers and mapping templates were not copied down with the schema, queries, mutations, and subscriptions making most of the queries fail because those data sources were missing.
So my question is:
Is there a way to integrate/use EVERYTHING from my exiting AppSync API within my React Native application? This includes the custom resolvers and mapping templates.
IF NOT
Is there a way to set a primary and sort key for the DynamoDB of the Models when creating an API directly within the Amplify CLI?
IF NOT
Is there another way to have data sorted efficiently within DynamoDB without using LSIs and GSIs? If the models automatically generate tables with GSIs, this can be problematic because I know GSIs are a bit more expensive so I would like to avoid those as much as possible. Is there another service that will sort the data that can be used within AppSync from DynamoDB?
Any help will be appreciated, thank you.
Is there a way to integrate/use EVERYTHING from my exiting AppSync API within my React Native application?
Yes, you can deploy your API however you want and then use it using amplify client tools. You can always use the Ampify CLI's codegen features without deploying the API via the amplify api category. You can use custom stacks to define custom resolvers that are not generated by #model but this will deploy a new API with the same structure as your existing API.
Is there a way to set a primary and sort key for the DynamoDB of the Models when creating an API directly within the Amplify CLI?
Soon. There is an RFC here https://github.com/aws-amplify/amplify-cli/issues/1062 and implementation is in PR here https://github.com/aws-amplify/amplify-cli/pull/1463.
Is there another way to have data sorted efficiently within DynamoDB without using LSIs and GSIs?
No but you can use index overloading to make 1 index store and sort multiple different conceptual object types. TBH this is a complex subject but here is a good place to start https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-gsi-overloading.html.

Django+Tastypie: Deleting only a couple of objects

I'm using Django-Tastypie to provide a REST-API for my web application.
In this case I have a PhotoGallery object, which references to a couple of Photos using a intermediate table (using through on the ManyToMany field).
Unfortunately I have some trouble saving the PhotoGallery object through the REST interface, as it would require me to create the respective links in the intermediate table (which contain a bit of additional information like a sort index, etc.).
To simplify the API, I decided to expose the intermediate table as well, and now users can create and modify the relation between photos and the galleries.
To prevent the user of the REST-API having to delete each link with a single HTTP request, I'm wondering if it is possible to use a single HTTP DELETE request to delete a selected number of objects. Filtering does not seem to be respected with DELETE requests.
Have you considered the PATCH method? Take a look the Bulk Operations section in the docs.
Pay attention to the "deleted_objects": ... part.

No CRUD operations with Django/Tastypie

I am a newbie with Tastypie and it is wonderful the way you can achieve CRUD operations with it so quickly. But I would like to implement other kind of web services where the return value is other than a model. For example, if I had a simple model like this
class User(models.Model):
name = models.CharField(max_length=20)
age = models.PositiveSmallIntegerField()
and wanted to get the average age of all users via /api/v1/user/avg_age, how should I do it? Perhaps it is something related to Django URLs more than Tastypie but I am lost at this moment. So, the question is where/how should I define my custom REST web services?
Thanks in advance
You can add the method to the model itself or put it in a service layer. After doing so you can easily add the value to the resource with a dehydration cycle.
Another option, which will allow filtering on the value, is to implement a model holding this data, e.g. a UserStatistics model. You can then add a foreign key relationship or create a stand-alone resource.
Because data won't likely change a whole lot and these calculations are more expensive I would encourage you to create a cronjob or task for such a model, only executing database writes periodically