Use Django's ORM to model remote API resources.
Fork of original David Larlet Django ROA lib. Now ROA works directly with an API like Django Rest Framework
How does it works: Each time a request is passed to the database, the request is intercepted and transformed to an HTTP request to the remote server with the right method (GET, POST, PUT or DELETE) given the get_resource_url_* methods specified in the model's definition.
Initial documentation:
- Django 1.9, 1.10
- Python 3.2, 3.3, 3.4, 3.5
$ pip install -e git+https://github.com/bjarnoldus/django-roa.git@master#egg=django_roa
If you have an API output like this (typical DRF output):
# GET http://api.example.com/articles/
# HTTP 200 OK
# Content-Type: application/json
# Vary: Accept
# Allow: GET, POST, HEAD, OPTIONS
{
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"headline": "John's first story",
"pub_date": "2013-01-04",
"reporter": {
"id": 1,
"account": {
"id": 1,
"email": "john@example.com"
},
"first_name": "John",
"last_name": "Smith"
}
},
...
]
}
Your code will look like this:
from django.db import models
from django_roa import Model as ROAModel
class Article(ROAModel):
id = models.IntegerField(primary_key=True) # don't forget it !
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter, related_name='articles')
api_base_name = 'articles'
@classmethod
def serializer(cls):
from .serializers import ArticleSerializer
return ArticleSerializer
@classmethod
def get_resource_url_list(cls):
return u'http://api.example.com/{base_name}/'.format(
base_name=cls.api_base_name,
)
def get_resource_url_count(self):
return self.get_resource_url_list()
from rest_framework import serializers
from .models import Article
class ArticleSerializer(serializers.ModelSerializer):
reporter = ReporterSerializer()
class Meta:
model = Article
fields = ('id', 'headline', 'pub_date', 'reporter')
Refer to tests for full example.
- Initial tests: read documentation
- Fork tests: read README
For the moment, the library doesn't work in this case:
class Reporter(CommonROAModel):
account = models.OneToOneField(Account)
...
with fixtures:
{
"model": "api.reporter",
"pk": 1,
"fields": {
"first_name": "John",
"last_name": "Smith",
"account": 1
}
},
{
"model": "api.account",
"pk": 1,
"fields": {
"email": "john@example.com"
}
},
This works:
reporter = Reporter.objects.get(id=1)
assertEqual(reporter.account.id, 1)
assertEqual(reporter.account.email, 'john@example.com')
But not this way:
account = Account.objects.get(id=1)
assertEqual(account.reporter.id, 1)
assertEqual(account.reporter.first_name, "John")
You can pass ssl args (see ssl.wrap_socket()) via the ROA_SSL_ARGS of your
settings.py
.
To pin the server certificate, save the public certificate(s) you want to pin in pinned-ca.pem and add the following to your settings.py :
from os.path import dirname, join
ROA_SSL_ARGS = {
'ca_certs': join(dirname(dirname(__file__)), 'pinned-ca.pem'),
'cert_reqs': True
}