Code Monkey home page Code Monkey logo

drf-extensions's People

Contributors

akx avatar alexander-akhmetov avatar artragis avatar asherf avatar auvipy avatar chibisov avatar codingjoe avatar dhui avatar imomaliev avatar jcugat avatar joehybird avatar maryokhin avatar mightyscollins avatar neildutoit13 avatar omidraha avatar oskarpersson avatar pdvorchik avatar pkainz avatar pratyushmittal avatar samims avatar santialbo avatar serhiyromanov avatar stianjensen avatar tevinjoseph avatar thedrow avatar ticosax avatar tuky avatar tume avatar vovanbo avatar vshih avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

drf-extensions's Issues

list_route isn't working using the ExtendedSimpleRouter.

When using the ExtendedSimpleRouter, list_route won't route the traffic correctly. Instead of using /viewSet/methods it uses /viewSet/pk/methods.

The list_route and detail_route decorators where added in DRF 2.4 to replace the @action and @link decorators. There much more flexible and allow routing requests to list views or detailed views. There are extremely helpful when requesting the current user or a list of all users.
If anyone knows a workaround until this issue is fixed, I'd highly appreciate it.

ListETAGMixin + filter_fields + invalid data produces an EmptyQuerySet exception

class InspectionItemViewSet(ListETAGMixin, viewsets.ModelViewSet):
model = InspectionItem
filter_fields = ('property', )

If you access the API with e.g. /api/v1/inspectionitems/?property=(null) ... this throws an EmptyQuerySet exception here:

class ListSqlQueryKeyBit(KeyBitBase):
    def get_data(self, params, view_instance, view_method, request, args, kwargs):
        return force_text(
            view_instance.filter_queryset(view_instance.get_queryset()).query.__str__()

Nested Relations get_url patch

Привет, перепробовал кучу вещей в инете для nested drf routing, остановился на твоем пакете.
У тебя отсутствует генератор полей-ссылок на nested-urls (у базового не хватает kwargs для reverse).

class HyperlinkedNestedIdentityField(HyperlinkedIdentityField):

    def __init__(self, view_name=None, additional_reverse_kwargs={}, **kwargs):
        self.additional_reverse_kwargs = additional_reverse_kwargs
        super(HyperlinkedNestedIdentityField, self).__init__(view_name, **kwargs)

    def get_url(self, obj, view_name, request, format):
        """
        Given an object, return the URL that hyperlinks to the object.

        May raise a `NoReverseMatch` if the `view_name` and `lookup_field`
        attributes are not configured to correctly match the URL conf.
        """
        # Unsaved objects will not yet have a valid URL.
        if obj.pk is None:
            return None

        kwargs = {}
        for k, v in self.additional_reverse_kwargs.iteritems():
            kwargs[k] = getattr(obj, v, v)
        kwargs.update({self.lookup_url_kwarg: getattr(obj, self.lookup_field)})
        return self.reverse(view_name, kwargs=kwargs, request=request, format=format)

Пример использования:

class MealRecordSerializer(serializers.HyperlinkedModelSerializer):
    url = HyperlinkedNestedIdentityField(view_name='mealrecord-detail', read_only=True,
                                         additional_reverse_kwargs={"parent_lookup_user_id": "user_id"})

    class Meta:
        model = MealRecord
        fields = ('id', 'url', 'user', 'date', 'time', 'title', 'calories_count')

NestedViewSetMixin does not support GenericForeignKey

My use case is as followed, I have a Comment model that can attach to any resource

class Comment(models.Model):
    """
    """
    content_type = models.ForeignKey(ContentType,
            verbose_name=_('content type'),
            related_name="content_type_set_for_%(class)s")
    object_pk = models.TextField('object ID')
    content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk")
    comment = models.TextField('comment')

My router then looks like:

router = ExtendedSimpleRouter()
tasks_router = router.register(r'tasks', views.TaskViewSet)
tasks_router.register(r'comments', views.CommentModelViewSet, base_name='tasks-comment', parents_query_lookups=['content_object'])

This of course fails because it expects one of content_type, object_pk, comment...

I made an attempt to fix it, but getting the parent's model is not straight forward, any thoughts or ideas?

from rest_framework_extensions.mixins import NestedViewSetMixin as DRFNestedViewSetMixin
from rest_framework_extensions.settings import extensions_api_settings

class NestedViewSetMixin(DRFNestedViewSetMixin):
    """
    Small extension of DRFNestedViewSetMixin to support GenericForeignKey
    """
    def get_parents_query_contenttype(self):
        #TODO: there must be a better way to get the parent viewset????
        path = '/'.join(self.request._request.path.split('/')[:-3])+'/'
        parent_viewset = resolve(path).func.cls
        ct = ContentType.objects.get_for_model(parent_viewset.queryset.model)
        return ct
    def get_parents_query_dict(self):
        qs = super(DRFNestedViewSetMixin, self).get_queryset()
        result1 = super(NestedViewSetMixin, self).get_parents_query_dict()
        result= {}
        for query_lookup, query_value in result1.items():
            field = getattr(qs.model, query_lookup)
            if field.__class__.__name__ == 'GenericForeignKey':
                result[field.fk_field] = query_value
                result[field.ct_field] = self.get_parents_query_contenttype()
            else:
                result[query_lookup] = query_value
        return result

Review supported versions

I wanted to update Travis/tox configs, but saw that drf-extensions supports a bunch of old versions. Based on discussion here and here and also here, proposal is to change supported versions to:

  • Python (2.7, 3.3, 3.4)
  • Django (1.6, 1.7)
  • Django REST framework (2.4.3, 2.4.4, 3.0)

This would allow to greatly streamline the build matrix, and make the supported versions more clear and concise.

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.

Dict filter get fields

for filter_expr, value in filters.items():
    # example: author__id__in=1,2,3
    filter_bits = filter_expr.split(LOOKUP_SEP)  # => ['author', 'id', 'in']
    field_name = filter_bits.pop(0)  # => 'author'
    filter_type = 'exact'
    if not field_name in serializer_class.Meta.fields:  # should use get_fields
        # It's not a field we know about. Move along citizen.
        continue
    if filter_bits and filter_bits[-1] in query_terms:
        filter_type = filter_bits.pop()  # => 'in'

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/"
}

Nested routers do not return 404 error for non-existing resources

Let we have the following models

class Book(models.Model): 
       id = models.CharField()

class Page(models.Model):
      book = models.ForeignKey('Book')

and there is no books and no pages in the db. The URL to list pages related to certain book is /books/<BookID>/pages/.

How to reproduce:
perform GET request to /books/999/pages/

Expected result
404 code is returned because there is no book with id 999

Actual result
Empty list is returned.

Extend ResourceUriField to point to nested list resources

As far as I understand the default functionality allows to use ResourceUriField to point only to a detail view. In my use-case I want something like this:

class PostDetailSerializer(ModelSerializer):
    url = ResourceUriField(view_name='post-detail')
    comments_url = ResourceUriField(view_name='post-comments-list')

Of course, I could just implement my own field, but wouldn't this be useful functionality in drf-extensions?

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

Why are KeyConstructor bits class variables

Hi - great package, thanks!

I am wondering why the KeyConstructor bits are class variables not instance? It means that it is hard to reuse KeyContructors across different viewsets when only only perhaps the GET param needs changing.

It would ease reuse to be able to specify params when the instance is constructed, as something like

class CityView(views.APIView):
    @cache_response(key_func=CityGetKeyConstructor(params={'request_meta': ['GEOIP_CITY']}))
    def get(self, request, *args, **kwargs):

class CountryView(views.APIView):
    @cache_response(key_func=CityGetKeyConstructor(params={'request_meta': ['GEOIP_COUNTRY']}))
    def get(self, request, *args, **kwargs):

SerializerAPI - Mixin for using different Serializer for browsable API

Along the lines of DetailSerializerMixin:

class SerializerAPI(object):
    """
    Mixin for using different Serializer for browsable API.
    """
    def get_serializer_class(self, *args, **kwargs):
        parent = super(SerializerAPI, self).get_serializer_class(*args, **kwargs)
        # We use the API serializer when not HEAD/OPTIONS and the render is set to API
        if (self.request.method not in ['HEAD', 'OPTIONS']
            and hasattr(self.request, 'accepted_renderer')
                and self.request.accepted_renderer.format == 'api'):
            return self.serializer_class_api
        else:
            return parent

@cache_response doesn't seem to be working with DRF 2.4

I'm getting following exception while using DRF 2.4 and Django 1.7:

Traceback (most recent call last):
  File "/usr/lib/python3.3/wsgiref/handlers.py", line 137, in run
    self.result = application(self.environ, self.start_response)
  File "/home/vagrant/.virtualenvs/project/lib/python3.3/site-packages/django/core/handlers/wsgi.py", line 187, in __call__
    response = self.get_response(request)
  File "/home/vagrant/.virtualenvs/project/lib/python3.3/site-packages/django/core/handlers/base.py", line 210, in get_response
    response._closable_objects.append(request)
AttributeError: 'Response' object has no attribute '_closable_objects'

It works alright if I downgrade to DRF 2.3 or remove @cache_response from given view.

Cache key 'api_updated_at_timestamp' copy error in docs

Hi,
There's a small typo (easily overlooked) in the docs, which causes the cache invalidation sample code not to work.

class UpdatedAtKeyBit(KeyBitBase):
    def get_data(self, **kwargs):
        key = 'api_update_at_timestamp'
        value = cache.get('api_updated_at_timestamp', None)
        if not value:
            value = datetime.datetime.utcnow()
            cache.set(key, value=value)
        return force_text(value)

Should be:

class UpdatedAtKeyBit(KeyBitBase):
    def get_data(self, **kwargs):
        key = 'api_updated_at_timestamp'
        value = cache.get(key, None)
        if not value:
            value = datetime.datetime.utcnow()
            cache.set(key, value=value)
        return force_text(value)

Caching is working nicely now. Thanks for the package.

nested viewset and router on the same level

so i want to do

item/1/collections/
item/1/colors/

when i do this

router.register(
    r'institutes', InstituteViewSet
    ).register(
    r'collections', CollectionViewSet, 'institute-collections', parents_query_lookups='owner_id'
    ).register(
    r'items', ItemViewSet, 'collection-items', parents_query_lookups='owner_id'
   )

it gives me this urls

/item/1/collection/3/colors/

which is not what i want .. how do i get it consume two endpoints at the same level

Allow optional regex changes for parents query lookups in nested routers

Hi!
I noticed that when using a ExtendedSimpleRouter and registering routes that might have a dot "." in their lookup regex will cause the lookup to fail. I presume that the prefix creation here here was made with pk lookups in mind. However, there might be (as in my case) times where dots are a part of the API endpoint. As an example an email address.

I noticed that there is a function here that indicates if dots are to be used in the regex or not. And after DRF 2.4 it seems that dots are not to be matched in URLs (according to that file). However, the way the code is set up right now there is no way of changing the default behavior or the regex lookup. I propose that a optional parameter, parents_query_lookups_regex, be implemented in the register() function, which would give the caller more flexibility when it comes to matching routes.

I'm quite new with the code base so please excuse me if I have overlooked some part of the router setup or if I'm making a complete ass out of myself asking for such implementations :)

Smarter parents_query_lookups

If the lookup_field of the ViewSet pointed to by a nested route is not set to pk then the parents_query_lookups should end with __<lookup_field>:

router.register('people', views.PersonViewSet)
      .register(r'tests', views.TestUnderPersonViewSet, base_name="test", 
                parents_query_lookups=["person__uuid"])

where TestUnderPersonViewSet has its lookup_field = 'uuid'.

Include license text

It would be nice if you could include the license text of the BSD license variant that you prefer. This would make it possible to distribute your package as a Debian package.

`ExtendedActionLinkRouterMixin` doesn't play well with `drf-nested-routers`

As suggested in another issue comment I tried:

from rest_framework.routers import DefaultRouter as _DefaultRouter
from rest_framework_extensions.routers import ExtendedActionLinkRouterMixin
from rest_framework_nested import nested_routers

class DefaultRouter(ExtendedActionLinkRouterMixin, _DefaultRouter):
    pass

class NestedSimpleRouter(ExtendedActionLinkRouterMixin, nested_routers.NestedSimpleRouter):
    pass

apirouter = DefaultRouter(trailing_slash=False)
apirouter.register(r'parentresource', ParentResourceViewSet, 'parentresource')

parentresource_nested_router = NestedSimpleRouter(
    apirouter, r'parentresource', lookup='parentresource',
    trailing_slash=False)
parentresource_nested_router.register(r'nestedresource', NestedResourceViewSet, 'nestedresource')

urlpatterns = patterns('',
    url(r'^api/', include(apirouter.urls)),
    url(r'^api/', include(parentresource_nested_router.urls)),
    # ...

And the NestedResourceViewSet has a custom_collection_operation method decorated with rest_framework_extensions.decorators.action, but the nested routes are still registered at the root. This is what I need:

^api/v1/ ^parentresource$ [name='parentresource-list']
^api/v1/ ^parentresource\.(?P<format>[a-z0-9]+)$ [name='parentresource-list']
^api/v1/ ^parentresource/(?P<id>[^/.]+)$ [name='parentresource-detail']
...
^api/v1/ ^parentresource/(?P<parentresource_id>[^/.]+)/nestedresource$ [name='nestedresource-list']
^api/v1/ ^parentresource/(?P<parentresource_id>[^/.]+)/nestedresource/(?P<id>[^/]+)$ [name='nestedresource-detail']
^api/v1/ ^parentresource/(?P<parentresource_id>[^/.]+)/nestedresource/custom_collection_operation$ [name='nestedresource-custom-collection-operation']

But they are generated at the root:

^api/ ^parentresource$ [name='parentresource-list']
^api/ ^parentresource\.(?P<format>[a-z0-9]+)$ [name='parentresource-list']
^api/ ^parentresource/(?P<id>[^/.]+)$ [name='parentresource-detail']
...
^api/ ^nestedresource/custom_collection_operation$ [name='nestedresource-custom-operation-list']
^api/ ^nestedresource$ [name='nestedresource-list']
^api/ ^nestedresource/(?P<id>[^/]+)$ [name='nestedresource-detail']

Smarter Way of Doing HyperlinkedIdentityField

Right now I feel that in order to use HyperlinkedIdentityField I end up repeating myself.

employees = serializers.HyperlinkedIdentityField(view_name='employee-list', lookup_field='slug',
    slug_url_kwarg='parent_lookup_institution__slug')

My urls.py looks like:

institutions_router = router.register('institutions', views.InstitutionViewSet)
institutions_router.register('employees', views.EmployeeViewSetUnderInstitution,
   base_name="employee", parents_query_lookups=["institution__slug"])

Is there a smarter / cleaner way of doing this?

Cannot create key bits for args and kwargs of decorated methods

I think it's useful to generate cache keys based on the positional and/or keyword method arguments for the decorated method. In particular, if I have a view for a URL that's like GET /cities/(?P<user_id>)/, then Django will pass a kwarg called user_id to my view.

I see that there are key bits for params and request. Why not args or kwargs? Please see my pull request for a simple implementation.

Etag strategy for resource lists and nested resources

I'm coming across two problems:

  • When fetching a list of resources, the etag stays the same even if resources in the list have changed.
  • If a resource has a serialised nested resource, when the nested resource is updated, the parent e-tag is not.

Can you think of a strategy to deal with either of these issues?

ListModelViewSet

Consider adding the following to viewsets:

class ListModelViewSet(mixins.ListModelMixin,
                       GenericViewSet):
    """
    A viewset that provides default `list()` actions.
    """
    pass

This would complement ReadOnlyModelViewSet.

See: encode/django-rest-framework#2113

Mixin to include ETag in list responses

Just wondering whether it makes sense, or there's scope, to add a mixin that includes the ETag for each result in a list response, say as a key in the JSON– I essentially want to get a bunch of a results, and use the ETag from each to If-Match PATCH them.

Is that a sensible approach? Is it easy to add? Should there be a mixin in this repo to add that?

Mixin for last-modified header

There is a mixin for etags, which is really useful, but in many cases it would be better to deal with caching based on a date. In a lot of our data, we store the last time something was modified which means we would be able to use the last-modified header for caching purposes.

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.

"GitHub Style" Nested Routing

Support for GitHub style nested routing:

/<userId>/<reposId>/...

this instead of:

/<userId>/repositories/<reposId>/...

release to pypi

HI @chibisov thanks for the great work here, I'm looking to move my nested routers over from DRF Nested routers to this package as it offers some other cool enhancements, but I see that functionality is not available on the latest pypi version.. any ideas on when it will be ? (so i don't have to install this package from github)...

Thanks in advance..

@farridav

0.2.4 source tarball contains .pyc files, confusing setuptools

$ tar -tf drf-extensions-0.2.4.tar.gz | grep '\.pyc$'
drf-extensions-0.2.4/rest_framework_extensions/__pycache__/__init__.cpython-33 (2).pyc
drf-extensions-0.2.4/rest_framework_extensions/__pycache__/__init__.cpython-33.pyc
drf-extensions-0.2.4/rest_framework_extensions/__pycache__/__init__.cpython-34.pyc
drf-extensions-0.2.4/rest_framework_extensions/__pycache__/compat.cpython-33.pyc
drf-extensions-0.2.4/rest_framework_extensions/__pycache__/compat.cpython-34.pyc
... etc.

This breaks bdist_egg:

$ python setup.py bdist_egg
... snip ...
zip_safe flag not set; analyzing archive contents...
Traceback (most recent call last):
  File "setup.py", line 77, in <module>
    'Topic :: Internet :: WWW/HTTP',
  File "/usr/lib/python2.7/distutils/core.py", line 151, in setup
    dist.run_commands()
  File "/usr/lib/python2.7/distutils/dist.py", line 953, in run_commands
    self.run_command(cmd)
  File "/usr/lib/python2.7/distutils/dist.py", line 972, in run_command
    cmd_obj.run()
  File "/usr/lib/python2.7/dist-packages/setuptools/command/bdist_egg.py", line 203, in run
    os.path.join(archive_root,'EGG-INFO'), self.zip_safe()
  File "/usr/lib/python2.7/dist-packages/setuptools/command/bdist_egg.py", line 239, in zip_safe
    return analyze_egg(self.bdist_dir, self.stubs)
  File "/usr/lib/python2.7/dist-packages/setuptools/command/bdist_egg.py", line 347, in analyze_egg
    safe = scan_module(egg_dir, base, name, stubs) and safe
  File "/usr/lib/python2.7/dist-packages/setuptools/command/bdist_egg.py", line 381, in scan_module
    code = marshal.load(f)
ValueError: bad marshal data (unknown type code)

Please publish a new release without the .pyc files.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.