Mimic remote API or extend existing django model - django

I am in a process of designing a client for a REST-ful web-service.
What is the best way to go about representing the remote resource locally in my django application?
For example if the API exposes resources such as:
List of Cars
Car Detail
Car Search
Dealership summary
So far I have thought of two different approaches to take:
Try to wrangle the django's models.Model to mimic the native feel of it. So I could try to get some class called Car to have methods like Car.objects.all() and such. This kind of breaks down on Car Search resources.
Implement a Data Access Layer class, with custom methods like:
Car.get_all()
Car.get(id)
CarSearch.search("blah")
So I will be creating some custom looking classes.
Has anyone encoutered a similar problem? Perhaps working with some external API's (i.e. twitter?)
Any advice is welcome.
PS: Please let me know if some part of question is confusing, as I had trouble putting it in precise terms.

This looks like the perfect place for a custom manager. Managers are the preferred method for "table-level" functionality, as opposed to "row-level" functionality that belongs in the model class. Basically, you'd define a manager like this:
class CarAPIManager(models.Manager):
def get_detail(self, id):
return self.get(id=id)
def search(self, term):
return self.filter(model_name__icontains=term)
This could be used either as the default manager -- e.g., in your model definition:
class Car(models.Model):
...
objects = CarAPIManager()
# usage
>>> Car.objects.search(...)
or you could just make it an additional manager, as a property of the class:
class Car(models.Model):
...
api = CarAPIManager()
# usage
>>> Car.api.search(...)

Related

How to Implement Non-endpoint API Functions?

This is a pretty high level question but I have been unable to find anything that explains it elsewhere:
I have a django class-based view with endpoints (GET, POST) but I have another method that's not an endpoint but I would like to include as it's used in the GET/POST methods. What would be the best practice for implementing this?
For example:
class users(APIView):
def get(self, request):
# get method
helperFunction()
def post(self, request):
# post method
helperFunction()
def helperFunction():
# not an endpoint
Would this be the right way to do something like this? Should helperFunction() be standalone function outside of a class? Or should non-endpoint methods be in a separate class?
Apologies for the lack of specificity.
pick the location based on the data the function uses.
If it should process data that is relevant only for the class
instance, then yes it belongs to the class
If it should process data that is class type specific, add it as a static method in the class, and feed it with the
concrete instance you need to be processed
If it should process data that is common for a set of
classes, they you can either create an abstract class, put it
there and inherit all classes that use the function from it, or make
it external(see last option)
If it has a general purpose- like time formatting for example, throw it in the global space. Now ideally you would like
to have a separate file where all shit piles, it makes the code base
easier to maintain. In reality however it may be better to keep it
in the file where your class is(provided the other classes that use
it are in the same file)

Implementing RPC in RESTful API using DRF

I am using the Django Rest Framework to present a RESTful API. I have a router/viewset/serializer creating an endpoint for a Person resource:
/api/People/<id>/
I would would like some way of triggering a non-idempotent action on this resource (for example send-email-to). One idea I had to do so without having to re-do a lot of the routing/serialization infrastructure was to add a write-only boolean field to the serializer:
class PersonSerializer(serializers.ModelSerializer):
send_email = serializers.BooleanField(write_only=True, required=False)
and then add a write-only property to the model:
class Person(models.Model):
...
def do_send_email(self, value):
# We also need to check the object is fully constructed here, I think
if do_send_email:
...
send_email = property(fset=do_send_email)
and then I can PATCH to the end point with the payload of send_email=True.
Is this the best way to accomplish an RPC like function using a REST API? Is this the best way to accomplish this in DRF? Ideally I would like to solve this problem having to-implement as little as possible (ie see how few lines of code the solution is). send-email-to is not the only action that I would like to handle.
You can use the extra actions drf provides. In your case especifically, I would use #detail_route.
Something like that:
#detail_route(methods=['post'])
def send_mail(self, request, pk=None):
send_mail_to(pk) # Write here your email function.
You have to define this function within the Person viewset so, in order to call this function, you will have to POST at /people/{person_id}/send_mail where {person_id} is the primary key for the person.
As a side note, since this function are synchronously called from the client and it may take a while to answer, I would recommend you the use of celery. This will allow you to call the send_mail_to function asynchronously without delaying the user response.

If you have external tasks that gather information about a model should it live in the model as a method?

For example we have a method that fetches additional information about a model from third party APIs. Is it okay to put this as a method on the model or should it live outside?
class Entity(models.Model):
name = ...
location = ...
def fetch_location(self):
# fetch the location from another server and store it.
self.location = "result"
If the data is related to the instance than it can be the right place to put it. Only if you get a lot of these you might want to wrap them in a different class for your own readability (i.e. knowing what is internal and what is external from the instance perspective).
The way I generally do it:
Manager: anything pertaining a group of Model instances
Model: anything pertaining a single Model Instance
Well, if you think in terms of Object Oriented Programming, the answer is "yes":
If "the object can do something", than it should be included as a member function (aka method).
But: If several different classes would need the same functionality (e.g. an "Entity Owner" would like to fetch the location by himself without calling my_entity.fetch_location), you should consider a (abstract) class above both classes which implements the behaviour.
If you have to call the method without an existing instance (which seems not to be the case in your example), you might consider writing the method outside of a class or you add the #staticmethod decorator which allows you to call Entity.fetch_location (remember to omit self in this case since there is no self if there is no instance.) I would prefer the staticmethod over a global method because the caller will always know, which class it relates to.
#staticmethod
def fetch_location():
# fetch the location from another server and store it.
self.location = "result"

Django ManyToMany with inheritance

I've checked a number of SO articles and I don't believe there is any way to accomplish what I want to do, but before I abandon Django I wanted to articulate the question itself and see if I missed something.
I'm implementing a graph (nodes, edges) which can contain subclasses of a base type. That is, an edge can connect a base class to a subclass, or a subclass to a subclass, etc . . . I want to be able to pull all the edges for a given object, find the objects these edges point to, and call some function on these terminal objects. I was hoping that I could call the function in a polymorphic way, but I can't figure out a way to make that happen.
class Node(models.Model):
...
def dosomething():
class SpecialNode(Node):
...
def dosomething():
class Edge(models.Model):
#yes, related_name is weird, but this seems to be what makes sense
source = models.ForeignKey(Node, related_name='targets')
target = models.ForeignKey(Node, related_name='sources')
With this structure I can do:
sourceedges = node.sources.all()
for sourceedge in sourceedges:
sourceedge.source.dosomething()
But the "dosomething" function is always called on the Node object, even if source is actually a SpecialNode object.
I've tried doing this with django_polymorphic but I don't believe this supports M2M inheritance through an Edge object (this is required for other reasons in my app).
I've tried to use contenttypes, but I think you're only allowed one generic relation per class. Edge, in other words, can't have 2 different generic relations in it.
I imagine I could establish an object called an Endpoint which would have just a single generic relation on it, then link the Edge object to it like so:
class Endpoint(models.Model)
...
content_object = generic.GenericForeignKey(...)
class Edge(models.Model)
source = models.ForeignKey(Endpoint, related_name='targets')
target = models.ForeignKey(Endpoint, related_name='sources')
But this introduces another level of indirection in my model and I start to feel like the framework is coding me rather than the other way around :)
Anyway, if someone has figured out a way to get this particular use case done, please let me know. A better way than what I suggested above would be welcome, as I currently like a lot of things I get out of the box with Django.
Thanks

Secure-by-default django ORM layer---how?

I'm running a Django shop where we serve each our clients an object graph which is completely separate from the graphs of all the other clients. The data is moderately sensitive, so I don't want any of it to leak from one client to another, nor for one client to delete or alter another client's data.
I would like to structure my code such that I by default write code which adheres to the security requirements (No hard guarantees necessary), but lets me override them when I know I need to.
My main fear is that in a Twig.objects.get(...), I forget to add client=request.client, and likewise for Leaf.objects.get where I have to check that twig__client=request.client. This quickly becomes error-prone and complicated.
What are some good ways to get around my own forgetfulness? How do I make this a thing I don't have to think about?
One candidate solution I have in mind is this:
Set the default object manager as DANGER = models.Manager() on my abstract base class(es).
Have a method ok(request) on said base classes which applies .filter(leaf__twig__branch__trunk__root__client=request.client) as applicable.
use MyModel.ok(request) instead of MyModel.objects wherever feasible.
Can this be improved upon? One not so nice issue is when a view calls a model method, e.g. branch.get_twigs_with_fruit, I now have to either pass a request for it to run through ok or I have to invoke DANGER. I like neither :-\
Is there some way of getting access to the current request? I think that might mitigate the situation...
Ill explain a different problem I had however I think the solution might be something to look into.
Once I was working on a project to visualize data where I needed to have a really big table which will store all the data for all visualizations. That turned out to be a big problem because I would have to do things like Model.objects.filter(visualization=5) which was just not very elegant and not efficient.
To make things simpler and more efficient I ended up creating dynamic models on the fly. Essentially I would create a separate table in the db on the fly and then store a data only for that one visualization in that. My code is something like:
def get_model_class(table_name):
class ModelBase(ModelBase):
def __new__(cls, name, bases, attrs):
name = '{}_{}'.format(name, table_name)
return super(ModelBase, cls).__new__(cls, name, bases, attrs)
class Data(models.Model):
# fields here
__metaclass__ = ModelBase
class Meta(object):
db_table = table_name
return Data
dynamic_model = get_model_class('foo')
This was useful for my purposes because it allowed queries to be much faster but getting back to your issue I think something like this can be useful because this will make sure that each client's data is separate not only via a foreign key, but is actually separated in the db.
Using this method is pretty straight forward except before using the model, you have to call the function to get it for each client. To make things more efficient you can cache/memoize the results of the function call so that it does not have to recompute the same thing more than once.