Skip to main content

django Fake ORM model that query an RestAPI instead of a database —

Project description

Allow to query a django RestAPI with same interface as the django ORM. (the targeted API must use django-rest-framework + dynamic-rest libraries) In fact, it works like any other database engine. You add the rest_models engine in an alternate database and the rest_models databe router. Then add APIMeta class to the models querying the API, voilà !

Stable branch

https://img.shields.io/travis/Yupeek/django-rest-models/master.svg https://readthedocs.org/projects/django-rest-models/badge/?version=latest https://coveralls.io/repos/github/Yupeek/django-rest-models/badge.svg?branch=master Latest PyPI version Requirements Status

Development status

https://img.shields.io/travis/Yupeek/django-rest-models/develop.svg https://coveralls.io/repos/github/Yupeek/django-rest-models/badge.svg?branch=develop Requirements Status

Installation

  1. Install using pip:

    pip install django-rest-models

  2. Alternatively, you can download or clone this repo and install with :

    pip install -e ..

Requirements

This database wrapper work with

  • python 3.6, 3.7

  • django 2.0, 2.1, 2.2, 3.0, 3.1, 3.2

On the api, this is tested against

  • django-rest-framework 3.11, 3.12, 3.13

  • dynamic-rest 2.1

Examples

settings.py:

DATABASES = {
    'default': {
        ...
    },
    'api': {
        'ENGINE': 'rest_models.backend',
        'NAME': 'https://requestb.in/',
        'USER': 'userapi',
        'PASSWORD': 'passwordapi',
        'AUTH': 'rest_models.backend.auth.BasicAuth',
    },
}

DATABASE_ROUTERS = [
    'rest_models.router.RestModelRouter',
]

models.py:

class MyModel(models.Model):
    field = models.IntegerField()
    ...

    class Meta:
        # basic django meta Stuff
        verbose_name = 'my model'

    # the only customisation that make this model special
    class APIMeta:
        pass


class MyOtherModel(models.Model):
    other_field = models.IntegerField()
    first_model = models.ForeignKey(MyModel, db_column='mymodel')
    ...

    class Meta:
        # basic django meta Stuff
        verbose_name = 'my other model'

    # the only customisation that make this model special
    class APIMeta:
        pass

Targeted API requirements

To allow this database adapter to work like a relational one, the targeted API must respect some requirements :

  • dynamic-rest installed and all serializers/views must respectively inherit from Dynamic* (DynamicModelSerializer, etc…)

Each API serializer must :

  • Provide the id field

  • Provide the related field (ManyToMany and ForeignKey on Models) as DynamicRelationField

  • Provide the reverse related field. We must, for each ForeignKey and ManyToMany, add a field on the related model’s serializer.

class MenuSerializer(DynamicModelSerializer):
    pizzas = DynamicRelationField('PizzaSerializer', many=True)     # Menu.pizza = ManyToMany

    class Meta:
        model = Menu
        name = 'menu'
        fields = ('id', 'code', 'name', 'pizzas')
        deferred_fields = ('pizza_set', )


class PizzaSerializer(DynamicModelSerializer):

    toppings = DynamicRelationField(ToppingSerializer, many=True)
    menu = DynamicRelationField(MenuSerializer)                     # Add this because Menu.pizza = ManyToMany

    class Meta:
        model = Pizza
        name = 'pizza'
        fields = ('id', 'name', 'price', 'from_date', 'to_date', 'toppings', 'menu')

django-rest-models provide a way to check the consistency of the api with the local models via the django check framework. At each startup, it will query the api with OPTIONS to check if the local models match the remote serializers.

Caveats

Since this is not a real relational database, all feature cannot be implemented. Some limitations are inherited by dynamic-rest filtering system too.

  • Aggregations : is not implemented on the api endpoint, maybe in future releases

  • Complex filtering using OR : all filter passed to dynamic-rest is ANDed together, so no OR is possible

  • Negated AND in filtering: a negated AND give a OR, so previous limitation apply

  • Negated OR in filtering: since the compitation of nested filter is complexe and error prone, we disable all OR. in fact, only some nested of AND is accepted. only the final value of the Q() object can be negated

    for short, you CANNOT :

    Pizza.objects.aggregate()
    Pizza.objects.annotate()
    Pizza.objects.filter(Q(..) | Q(..))
    Pizza.objects.exclude(Q(..) & Q(..))
    Pizza.objects.exclude(Q(..) | Q(..))

but you can :
Pizza.objects.create
Pizza.objects.bulk_create
Pizza.objects.update
Pizza.objects.bulk_update
Pizza.objects.select_related
Pizza.objects.prefetch_related
Pizza.objects.values
Pizza.objects.values_list
Pizza.objects.delete
Pizza.objects.count()
Pizza.objects.filter(..., ..., ...)
Pizza.objects.filter(...).filter(...).exclude(...)
Pizza.objects.exclude(..., ...).exclude(...)
Pizza.objects.filter(Q(..) & Q(..))
Pizza.objects.none()
pizza.toppings.add(...)
pizza.toppings.remove(...)
pizza.toppings.set(...)
pizza.toppings.clear(...)

Specific behaviour

Some specific behaviour has been implemented to use the extra feature of a Rest API :

  • When inserting, the resulting model is returned by the API. the inserted model is updated with the resulting values. This imply 2 things:

    • If you provided default values for fields in the api, these data will be populated into your created instance if it was ommited.

    • If the serializer have some computed data, its data will always be used as a replacement of the one you gave to your models. (cf example: Pizza.cost which is the sum of the cost of the toppling. after each save, its value will be updated)

Support

This database api support :

  • select_related

  • order_by

  • only

  • defer

  • filter

  • exclude

  • delete

  • update

  • create

  • bulk create (with retrive of pk)

  • ManyToManyField

  • ForeignKey*

Documentation

The full documentation is at http://django-rest-models.readthedocs.org/en/latest/.

Requirements

  • Python 2.7, 3.5

  • Django >= 1.8

Contributions and pull requests are welcome.

Bugs and requests

If you found a bug or if you have a request for additional feature, please use the issue tracker on GitHub.

https://github.com/Yupeek/django-rest-models/issues

known limitations

JSONField from postgresql and mysql is supported by django-rest-models, but not by the current dynamic-rest (1.8.1) so you can do MyModel.objects.filter(myjson__mydata__contains=’aaa’) but it will work if drest support it

same for DateField’s year,month,day lookup.

License

You can use this under GPLv3.

Author

Original author: Darius BERNARD. Contributor: PaulWay.

Thanks

Thanks to django for this amazing framework.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-rest-models-2.1.1.tar.gz (42.5 kB view details)

Uploaded Source

Built Distribution

django_rest_models-2.1.1-py2.py3-none-any.whl (48.2 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file django-rest-models-2.1.1.tar.gz.

File metadata

  • Download URL: django-rest-models-2.1.1.tar.gz
  • Upload date:
  • Size: 42.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.7.9

File hashes

Hashes for django-rest-models-2.1.1.tar.gz
Algorithm Hash digest
SHA256 15d95efd26d687bb899ed772ce251d297fc04d12d8c008e0b6afd993d1b12980
MD5 cc7e04a347971006a764b0ac9f205f57
BLAKE2b-256 8cddce3a1df990a57c9417faf0083cc288261d53ddf5626a8a47b7fbb740ba93

See more details on using hashes here.

File details

Details for the file django_rest_models-2.1.1-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for django_rest_models-2.1.1-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 52934a5c547f1a6b841850211ec2c4f74080160f8aa8030eaaf6d41f5b2b0ca7
MD5 3c984cb60884416ff2430710ce613d4f
BLAKE2b-256 5d20b215de4004d042f383a4bf45f4793e709eb56384fd2a6d0e201b2d3c0125

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page