DRF-extensions is a collection of custom extensions for Django REST Framework

Overview

Django REST Framework extensions

DRF-extensions is a collection of custom extensions for Django REST Framework

Full documentation for project is available at http://chibisov.github.io/drf-extensions/docs

Build Status Backers on Open Collective Sponsors on Open Collective PyPI

Sponsor

Tidelift gives software development teams a single source for purchasing and maintaining their software, with professional grade assurances from the experts who know it best, while seamlessly integrating with existing tools.

Requirements

  • Tested for Python 3.6, 3.7 and 3.8
  • Tested for Django Rest Framework 3.12
  • Tested for Django 2.2 to 3.2
  • Tested for django-filter 2.1.0

Installation:

pip3 install drf-extensions

or from github

pip3 install https://github.com/chibisov/drf-extensions/archive/master.zip

Some features

  • DetailSerializerMixin
  • Caching
  • Conditional requests
  • Customizable key construction for caching and conditional requests
  • Nested routes
  • Bulk operations

Read more in documentation

Development

Running the tests:

$ pip3 install tox
$ tox -- tests_app

Running test for exact environment:

$ tox -e py38 -- tests_app

Recreate envs before running tests:

$ tox --recreate -- tests_app

Pass custom arguments:

$ tox -- tests_app --verbosity=3

Run with pdb support:

$ tox -- tests_app --processes=0 --nocapture

Run exact TestCase:

$ tox -- tests_app.tests.unit.mixins.tests:DetailSerializerMixinTest_serializer_detail_class

Run tests from exact module:

$ tox -- tests_app.tests.unit.mixins.tests

Build docs:

$ make build_docs

Automatically build docs by watching changes:

$ pip install watchdog
$ make watch_docs

Developing new features

Every new feature should be:

  • Documented
  • Tested
  • Implemented
  • Pushed to main repository

How to write documentation

When new feature implementation starts you should place it into development version pull. Add Development version section to Release notes and describe every new feature in it. Use #anchors to facilitate navigation.

Every feature should have title and information that it was implemented in current development version.

For example if we've just implemented Usage of the specific cache:

...

#### Usage of the specific cache

*New in DRF-extensions development version*

`@cache_response` can also take...

...

### Release notes

...

#### Development version

* Added ability to [use a specific cache](#usage-of-the-specific-cache) for `@cache_response` decorator

Publishing new releases

Increment version in rest_framework_extensions/__init__.py. For example:

__version__ = '0.2.2'  # from 0.2.1

Move to new version section all release notes in documentation.

Add date for release note section.

Replace in documentation all New in DRF-extensions development version notes to New in DRF-extensions 0.2.2.

Rebuild documentation.

Run tests.

Commit changes with message "Version 0.2.2"

Add new tag version for commit:

$ git tag 0.2.2

Push to master with tags:

$ git push origin master --tags

Don't forget to merge master to gh-pages branch and push to origin:

$ git co gh-pages
$ git merge --no-ff master
$ git push origin gh-pages

Publish to pypi:

$ python setup.py publish

Contributors

This project exists thanks to all the people who contribute.

Backers

Thank you to all our backers! 🙏 [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

Comments
  • EmptyResultSet removed in Django 3.1

    EmptyResultSet removed in Django 3.1

    Version: drf-extensions 0.6.0 Django 3.1 (python 3.8, but doesn't matter for issue)

    Description: Django has removed EmptyResultSet backward compatibility. django 3.1 commit breaking drf-extensions: https://github.com/django/django/commit/129583a0d3cf69b08d058cd751d777588801b7ad

    Error: from rest_framework_extensions.key_constructor import bits File "/usr/local/lib/python3.8/site-packages/rest_framework_extensions/key_constructor/bits.py", line 3, in <module> from django.db.models.sql.datastructures import EmptyResultSet ImportError: cannot import name 'EmptyResultSet' from 'django.db.models.sql.datastructures' (/usr/local/lib/python3.8/site-packages/django/db/models/sql/datastructures.py)

    Workaround: Stay on Django 3.0.8

    opened by henriklindgren 31
  • NestedViewSetMixin suport for saving

    NestedViewSetMixin suport for saving

    Is looks like using the NestedViewSetMixin auto generates the filter code for nested routers, but does nothing for saving.

    I would recommend something like the following for a URL like companies/company_pk/locations/location_pk:

        def pre_save(self, obj):
            obj.location = Location.objects.get(pk=self.kwargs['location_slug'],
                                        company__pk=self.kwargs['company_pk']
                                        )
    

    to be auto generated so that a user posting to the above URL can omit those fields which are determined by the URL itself.

    Docs Design decision needed 
    opened by cancan101 24
  • Optimistic concurrency control using ETags

    Optimistic concurrency control using ETags

    API resources: Optimistic concurrency control using ETags

    The Problem

    As @mbox already mentioned, the default implementation in drf-extensions does not allow a correct optimistic locking using ETags and conditional requests. The ETag ties each request to a particular HTTP method, view, and response. While this works as expected for server-side caching (correctly returns status 304, and 200), it does not work to identify the requested resources when retrieving an object, altering it and putting it back to the server:

    # Retrieve Request
    GET /books/1/ HTTP/1.1
    Accept: "application/json"
    
    # Response
    HTTP/1.1 200 OK
    Content-Type: "application/json"
    ETag: "591fa57af468db45942e5bf8ebe59378"
    
    {'issn': '9780345531988', 'name': 'The Summons', 'id': 1, 'author': 'Stephen King'}
    
    
    # Update Request
    PUT /books/1/ HTTP/1.1
    Accept: "application/json"
    If-Match: "591fa57af468db45942e5bf8ebe59378"
    
    {'issn': '9780345531988', 'name': 'The Summons', 'id': 1, 'author': 'John Grisham'}
    
    # Response
    HTTP/1.1 412 PRECONDITION FAILED 			# <- THIS SHOULD BE '200 OK'!
    Content-Type: "application/json"
    ETag: "<another_value_that_hashed_the_PUT_view>"
    

    Related discussion in the DRF issues: https://github.com/tomchristie/django-rest-framework/issues/32

    Proposed Changes

    I have implemented the following changes/additions to enable optimistic locking using conditional requests using ETag, If-Match, If-None-Match HTTP headers in DRF-extensions. It is based on the requirement that we need an ETag value to represent the current semantic version of individual model instances rather than using it as caching function for a dynamic page.

    • New KeyBits for retrieving and listing model instances: decoupled from the views and methods, the entries in the QuerySet are tuples represented by their mere field values.
    • New KeyConstructors for API views that use the new KeyBits.
    • New default functions to compute ETags for API views (in settings and utils)
    • New API{method}ETAGMixins: List, Retrieve, Update, Destroy, as well as combined mixins for ReadOnly and APIETAGMixin.

    The new features have been tested in unit tests where applicable and there exists a new functional test app in tests_app/tests/functional/concurrency. It tests a standard APIClient from the rest_framework to query Book models.

    Additional Changes

    Some other changes have been performed to ensure that all tests pass in django 1.10 and 1.9, DRF 3.5.3:

    • added missing fields = '__all__' to serializers (ensures DRF>3.3 compatibility)
    • removed double entry in DRF features dict rest_framework_extensions/utils.py

    I documented the source code. The usage of the new mixins and decorators is identical to the current implementation that exists for @etag.

    opened by pkainz 17
  • version 0.3.1 is not compatible with DRF 3.8 and produces ImportError

    version 0.3.1 is not compatible with DRF 3.8 and produces ImportError

    The version 0.3.1 is not compatible with DRF 3.8. It seems that the master is, but the latest provided release to PyPI apparently not.

    It produces an import error in the 0.3.1 code

    Error:

      ...
      File ".../site-packages/rest_framework_extensions/routers.py", line 7, in <module>
        from rest_framework.routers import (
    ImportError: cannot import name 'replace_methodname'
    

    Culprit code of 0.3.1

    # -*- coding: utf-8 -*-
    from distutils.version import StrictVersion
    from django.core.exceptions import ImproperlyConfigured
    from django.core.urlresolvers import NoReverseMatch
    
    import rest_framework
    from rest_framework.routers import (
        DefaultRouter,
        SimpleRouter,
        Route,
        replace_methodname,
        ^^^^^^^^^^^^^^^^^^^
    )
    
    opened by jberends 15
  • Made compatible with DRF 3.2.2 and django 1.8

    Made compatible with DRF 3.2.2 and django 1.8

    Hi Gennady,

    I have made a few changes to make drf-extensions compatible with the latest Django Rest Framework. The new versions of Django Rest Framework, since 3.1.0, have introduced some breaking changes, such as the new Pagination classes. The tests pass with these recent versions only.

    How about considering to drop the support for earlier versions? We can add some note like:

    For Django Rest Framework 2.4 support check drf-extensions 0.2.7

    Thanks for creating and sharing the extensions.

    opened by pratyushmittal 15
  • Respect parent lookup regex value (sending parent viewset to NestedRegistryItem)

    Respect parent lookup regex value (sending parent viewset to NestedRegistryItem)

    A try for this was made in #63 but it did not lead anywhere and this is really starting to become a problem for me so hopefully this is good enough :)

    Problem

    Say that you have a user route (/users) and you do not want to expose the id value of the user, so you use the users email instead. Making a detailed route look like /users/[email protected]. You test the route and notice that you get a 404 page. This is because the default lookup regex is [^/.]+, and this works fine for most routes, but not when there is a dot (.) in the route. And since dots are valid in a url we this is a shame. The solution to this is to set your lookup_filed to 'email' and write your own lookup_value_regex in your view. In this case we could set it to something fancy such as [^@]+@[^@]+\.[^@/]+. And voilà, the route now works.

    The problem is that this regex value is not respected in the nested routers that are included in drf-extensions, instead the hard coded value of [^/.]+ is used.

    Solution

    By default we do not have access to the parents regex value as it is stored in the parents viewset, which we don't have access to either. This pull requests lets the viewset of the parent be passed to the ´NestedRegistryItem´ class, exposing all viewset functions and variables, including the regex. The regex is then used when creating the get_parent_prefix(), and falls back on the default value of [^/.]+ if no regex is set.

    Caveat

    There is a second thing here to keep in mind. If using custom lookup_field values in the view, one also needs to set the lookup_url_kwarg value when using nested router, in the example above it would be lookup_url_kwarg = 'parent_lookup_email'. This has to do with the way the NestedViewSetMixin is built, and can probably be fixes as well (just not in this pull request).

    opened by frwickst 12
  • Generated etags stay the same after updating contents

    Generated etags stay the same after updating contents

    I'm having a trouble to get etag decorator working. Generated etags don't change after updating the corresponding contents (responses from drf views are updated too).

    By looking at the code in drf-extensions, the default behaviour of the default_etag_func seems to be calculating etags based on requests. Wouldn't it supposed to be based on responses?

    Before attempting to write a custom etag_func, I would like to make sure that I'm not missing anything.

    I'm testing with following versions.

    • drf-extensions==0.2.2
    • djangorestframework==2.3.13
    opened by ysugiura 12
  • Import error - Django 3.0.1 - ImportError: cannot import name 'available_attrs' from 'django.utils.decorators'

    Import error - Django 3.0.1 - ImportError: cannot import name 'available_attrs' from 'django.utils.decorators'

    Hi, I am using drf-extensions 0.5.0 with Django 3.0.1 and Python 3.7. However, when I try to use the package, I get this error. I believe this has something to do with compatibility if Django 3.0.

    Is this an easy fix?

    File "/sam/Service/venv/lib/python3.7/site-packages/rest_framework_extensions/cache/decorators.py", line 4, in <module>
        from django.utils.decorators import available_attrs
    ImportError: cannot import name 'available_attrs' from 'django.utils.decorators' (/sam/Service/venv/lib/python3.7/site-packages/django/utils/decorators.py)
    
    
    
    opened by SulanthaM 11
  • ExtendedDefaultRouter root view is polluted

    ExtendedDefaultRouter root view is polluted

    I am using ExtendedDefaultRouter with nested routes. Right now my root view is being polluted by the sub items:

    GET /api/
    
    {
        "people": "http://127.0.0.1:8000/api/people/", 
        "people/(?P<parent_lookup_person__uuid>[^/.]+)/tests": "http://127.0.0.1:8000/api/tests/",
        "tests": "http://127.0.0.1:8000/api/tests/"
    }
    
    opened by cancan101 11
  • DetailSerializerMixin returns detail serializer repr. on list URL

    DetailSerializerMixin returns detail serializer repr. on list URL

    We ran into a minor snag with using DetailSerializerMixin. When POST'ing to a list URL, you are returned the detail serializer representation, and therefore you see a weird thing like this: 2014-10-31 16 12 59 So as you see, we are still on the /posts/URL, but we see a post instance and the form on the bottom is also for the post instance. Even more, pressing the POST button would not work, because some fields would obviously be missing from the detail form that are required for list form.

    If you also consider this a bug, then I can probably provide a PR for a more robust solution, because we used an in-house implementation of the same thing, and didn't have this problem, but decided to switch to a packaged solution, but are now kind of holding back because of this.

    Bug 
    opened by maryokhin 11
  • HttpResponse has no 'data' on 0.4.0

    HttpResponse has no 'data' on 0.4.0

    Hey guys, just tried updating to 0.4.0 and it broke all my tests.

    Whenever I do a GET to a filtered cached list, I run the following test to check wether the amount of objects returned is ok:

    self.assertEqual(
        response.data['count'],
        3
    )
    

    But now I get the following error:

    AttributeError: 'HttpResponse' object has no attribute 'data'

    Django is 1.11.15, DRF is 3.8.2 and Python is 3.6 (haven't changed their versions, just drf-extensions).

    Thanks in advance!

    EDIT: Forgot to mention this is a cached list.

    opened by mbaragiola 10
  • [WIP] feat: add parent permission check.

    [WIP] feat: add parent permission check.

    FIX: #271 FIX: #142 FIX: #98

    Notice

    This PR hasn't been completed yet, it already meets what I need so I just mark it as draft.

    It needs to think more about some special cases(i mentioned several in code comments.) and make some tests.

    It's welcome for everyone to update based on those codes.

    you can fork my repo and start a PR to https://github.com/sobadgirl/drf-extensions

    OR

    just copy those codes to your repo and start a PR to https://github.com/chibisov/drf-extensions directly.

    Feature

    Add permission chain check to check parent permissions.

    Think you have those URLs:

    /api/users/1/
    /api/users/1/houses/
    /api/users/1/houses/1/
    /api/users/1/houses/1/tables/
    /api/users/1/houses/1/tables/1
    

    Before

    If you didn't have permission on /api/users/1, then you can't visit it. but you still can visit /api/users/1/houses and other subpaths of /api/users/1/.

    because when we visit /api/users/1/houses/, the request was sent to HouseViewSet directly, so DRF skipped checking the permission of UserViewSet.

    After

    when you visit /api/users/1/houses/ will check permission of UserViewSet.check_object_permissions. when you visit /api/users/1/houses/1/tables/ will check permissions of UserViewSet.check_object_permissions and HouseViewSet.check_object_permissions.

    so if you don't have permission to visit /api/users/1/, then you will be refuse to visit any subpath of /api/users/1/

    opened by sobadgirl 1
  • We are getting AttributeError: 'Response' object has no attribute '_headers'

    We are getting AttributeError: 'Response' object has no attribute '_headers'

    Line: rest_framework_extensions/cache/decorators.py

    We are using Cache Response Decorator, in our APIs _headers are not present since we are using custom Response Class

    opened by ownerni 2
  • distutils has been deprecated in Python 3.10 in favour of setuptools

    distutils has been deprecated in Python 3.10 in favour of setuptools

    https://github.com/chibisov/drf-extensions/blob/2a0bd3b66245a05a58e8e1d3bb62bf900520517e/rest_framework_extensions/utils.py#L2

    Ref : https://www.python.org/dev/peps/pep-0632/#migration-advice

    opened by tirkarthi 1
  • My Cron Job runs twice

    My Cron Job runs twice

    i develop a financial app that gives the customers their monthly income according to the percentages , but when i set up the cron job using the following package , the function runs twice and thats bad ,, is there any solution to this

    opened by macbotxxx 0
Releases(0.7.1)
Django queries

Djaq Djaq - pronounced “Jack” - provides an instant remote API to your Django models data with a powerful query language. No server-side code beyond t

Paul Wolf 53 Dec 12, 2022
Embrace the APIs of the future. Hug aims to make developing APIs as simple as possible, but no simpler.

Read Latest Documentation - Browse GitHub Code Repository hug aims to make developing Python driven APIs as simple as possible, but no simpler. As a r

Hug API Framework 6.7k Dec 27, 2022
One package to access multiple different data sources through their respective API platforms.

BESTLab Platform One package to access multiple different data sources through their respective API platforms. Usage HOBO Platform See hobo_example.py

Wei 1 Nov 16, 2021
The Web API toolkit. 🛠

🛠 The Web API toolkit. 🛠 Community: https://discuss.apistar.org 🤔 💭 🤓 💬 😎 Documentation: https://docs.apistar.com 📘 Requirements: Python 3.6+

Encode 5.6k Dec 27, 2022
Build a Backend REST API with Python & Django

Build a Backend REST API with Python & Django Skills Python Django djangorestframework Aws Git Use the below Git commands in the Windows Command Promp

JeonSoohyun a.k.a Edoc.. 1 Jan 25, 2022
A small project in Python + Flask to demonstrate how to create a REST API

SmartBed-RESTApi-Example This application is an example of how to build a REST API. The application os a mock IoT device, simulating a Smart Bed. Impl

Rares Cristea 6 Jan 28, 2022
Key-Value база данных на Tarantool и REST API к ней.

KVmail Key-Value база данных на Tarantool и REST API к ней. Документация к API доступна здесь. Requiremrnts ubuntu 16.04+ python3.6+ supervisord nginx

1 Jun 16, 2021
Built on Django Rest Framework, to provide with command execution on linux terminal

Built on Django Rest Framework, to provide with command execution on linux terminal

1 Oct 31, 2021
a web-remote minecraft server wrapper with some unique features

Canceled here, continued as Semoxy MCWeb - a Minecraft Server Web Interface MCWeb is a web-remote Minecraft Server Wrapper for controlling your Minecr

Anton Vogelsang 1 Jul 12, 2021
The no-nonsense, minimalist REST and app backend framework for Python developers, with a focus on reliability, correctness, and performance at scale.

The Falcon Web Framework Falcon is a reliable, high-performance Python web framework for building large-scale app backends and microservices. It encou

Falconry 9k Jan 03, 2023
Document Web APIs made with Django Rest Framework

DRF Docs Document Web APIs made with Django Rest Framework. View Demo Contributors Wanted: Do you like this project? Using it? Let's make it better! S

Manos Konstantinidis 626 Nov 20, 2022
Sanic-RESTPlus is an extension for Sanic that adds support for quickly building REST APIs.

Sanic RestPlus Sanic-RESTPlus is an extension for Sanic that adds support for quickly building REST APIs. Sanic-RESTPlus encourages best practices wit

Ashley Sommer 106 Oct 14, 2022
Generate Views, Serializers, and Urls for your Django Rest Framework application

DRF Generators Writing APIs can be boring and repetitive work. Don't write another CRUDdy view in Django Rest Framework. With DRF Generators, one simp

Tobin Brown 332 Dec 17, 2022
Web APIs for Django. 🎸

Django REST framework Awesome web-browsable Web APIs. Full documentation for the project is available at https://www.django-rest-framework.org/. Fundi

Encode 24.7k Jan 04, 2023
Eureka is a Rest-API framework scraper based on FastAPI for cleaning and organizing data, designed for the Eureka by Turing project of the National University of Colombia

Eureka is a Rest-API framework scraper based on FastAPI for cleaning and organizing data, designed for the Eureka by Turing project of the National University of Colombia

Julian Camilo Velandia 3 May 04, 2022
REST implementation of Django authentication system.

djoser REST implementation of Django authentication system. djoser library provides a set of Django Rest Framework views to handle basic actions such

Sunscrapers 2.2k Jan 01, 2023
RESTful Todolist API

RESTful Todolist API GET todolist/ POST todolist/ {"desc" : "Description of task to do"} DELETE todolist/int:id PUT todolist/int:id Requirements D

Gabriel Tavares 5 Dec 20, 2021
A RESTful way to use your Notion tables as a database.

rest-notion-db A RESTful way to use your Notion tables as a database. Use-cases Form submissions or frontend websites, use one database that

Oorjit Chowdhary 42 Dec 27, 2022
A lightweight REST miniframework for Python.

restless A lightweight REST miniframework for Python. Documentation is at https://restless.readthedocs.io/. Works great with Django, Flask, Pyramid, T

Daniel Lindsley 824 Nov 20, 2022