altschool / dynamic-rest Goto Github PK
View Code? Open in Web Editor NEWDynamic extensions for Django REST Framework
License: MIT License
Dynamic extensions for Django REST Framework
License: MIT License
Hello, currently I work on support for django 2.0 and drf 3.7.
I update tests and circle config.
I had several warnings for unsupported versions od django and django-rest-framework.
Maybe support for unsupported django and rest framework versions should be droped for future development and maintance simplification.
Ps.
I think Django 1.8, 1.11 and 2.0 should be supported now.
Is there a fundamental reason why nested belongs-to relations are not supported?
dynamic-rest/dynamic_rest/fields/fields.py
Line 109 in eb0a253
I was able to get them working with a few tweaks and am wondering if this is a bad idea.
Thanks
I know that embedded relationships is more likely to produce a bigger payload than sideloaded ones as explained here at https://github.com/AltSchool/dynamic-rest#embedded-relationships
My question is whether the performance of the query is also not as good for embedded relationships compared to sideloaded ones?
I am using dynamic-rest. According to the documentation, I have this model with a dynamically generated foreign key:
class PscSerializer(DynamicModelSerializer):
class Meta:
model = PSC
name = 'psc'
fields = ('id', 'description', 'created', 'modified', 'pscno', 'productno', 'serviceno', 'luns')
luns = DynamicRelationField('LunSerializer', many=True)
Which produces:
Exception Type: AttributeError at /api/v1/pscs/
Exception Value: luns is not a valid field for <class 'pscs.models.PSC'>
Sure, luns
is not a field in the PSC
model, but a dynamic field. What is going on? What am I doing wrong here?
I am using:
Django==2.0.4
djangorestframework==3.7.7
dynamic-rest==1.8.0
And:
» python --version
Python 3.6.4
I saw the latest version is v1.5.7, howerver, the latest version I can install from pip command is v1.5.0.
I would appreciate if you update pypi version, thanks!
First of all, awesome work on dynamic-rest. This extension definitely provides some essential functionalities the django rest framework should offer natively.
We've been thinking about using dynamic-rest, but recently discovered this article What does this mean in terms of maintaining this library going forward? It seems like the support for the extension is already slowing down(?) #195 I just want to hear your honest opinion on its future so we can make sensible decisions.
List of (one-to-many) related ids is returned for PUT/PATCH even though DynamicRelationField is deferred both in settings and in serializer definition. This is a big problem if you imagine e.g. a User having thousands of Transactions, then when you want to (partially) update User (e.g. change his/her name), you get back the complete list of his/her Transaction ids.
I've created a minimal project reproducing this issue here. You can see that the relation field is deffered both in settings and in serializer. When you create a Parent record with some Child records and then try to PATCH the Parent record, related Child ids are included in PATCH response. Should I try to investigate further or is this for some reason the desired behavior?
The code below always returns all the units
associated with the curriculum
being serialized, and ignores the filter.
class CurriculumSerializer(DynamicModelSerializer):
units = DynamicRelationField('UnitSerializer', many=True, queryset=Unit.objects.filter(id=1))
class Meta:
model = Curriculum
name = 'curriculum'
fields = ('id', 'units')
class UnitSerializer(DynamicModelSerializer):
class Meta:
model = Unit
name = 'unit'
fields = ('id',)
When offloading the queryset to a function with an embedded print or ipdb, such as
def get_unit_queryset(field):
print 'IS THIS EVER HAPPENING?"
return Unit.objects.filter(id=1)
the result is the same and the print statement is never executed. The function is never called.
My assumption, which remains unaltered after reading the docs, would be that any deferred fields on a serializer would be included if the query had a parameter like include[]=*. Does my assumption jive with the intended behavior?
I attempted a search for any obvious bug in the code base but gave up after awhile. I did however land on the following workaround, which for anyone interested is code you should add to your ViewSet class. The basic idea behind this workaround is to intercept any wildcards and expand them to explicit field includes/excludes as that all seems to work great. Note, my datastructures are trees not graphs so I didn't bother to guard against the infinite recursion that will happen if you try this code with some serializers that reference each other...
`
def get_request_fields( self ):
if hasattr( self, '_exp_request_fields' ):
return self._exp_request_fields
request_fields = self._expand_wildcards( super( DataViewSet, self ).get_request_fields( ), self.serializer_class )
self._exp_request_fields = request_fields
return request_fields
def _expand_wildcards( self, req_fields, serializer_cls ):
if '*' in req_fields:
for field in serializer_cls.Meta.fields:
if ( field not in serializer_cls._declared_fields or
not isinstance( serializer_cls._declared_fields[field], DynamicRelationField ) ):
req_fields[field] = req_fields.get( field, True ) and req_fields['*']
else:
embed = req_fields.setdefault( field, { } )
if isinstance( embed, dict ):
embed['*'] = embed.get( '*', True ) and req_fields['*']
del req_fields['*']
for rf, requested in req_fields.items( ):
if isinstance( requested, dict ):
self._expand_wildcards( requested, serializer_cls._declared_fields[rf].serializer_class )
return req_fields
`
Nice project. I tried it right about now because of the DynamicRelationField.
When I added dynamic-rest to my project via pip install dynamic-rest
, it downgraded Django to 1.9 and REST Framework to 3.3.0. The latest versions are 1.9.7 and 3.3.3 respectively. Django has had both bug- and vulnerability patches in 1.9 release, so it would be nice to get the latest patch.
As I'm guessing this is because of these lines in install_requires.txt:
Django>=1.7,<=1.9
djangorestframework>=3.1.0,<=3.3.0
Could you for instance update this to:
Django>=1.7,<1.10
djangorestframework>=3.1.0,<3.4.0
Thanks.
Let’s say I want to run a filter like this
User.objects.filter(Q(username="admin") | Q(first_name="test"))
I understand drest does not support this in the end point.
How can I modify so as to allow something like this in the endpoint? I am okay to make a PR for this. I just want to get some guidance so I can conform to drest architecture
The lookup key in DynamicListSerializer.update
in my case is a UUID so the data lookup fails.
Multiple values for the same filter do not seem to be supported; eg. if my query looks like this: ?filter{-option}=value1&filter{-option}=value2
to exclude two different values from the results, only the first is respected.
https://github.com/AltSchool/dynamic-rest/blob/master/dynamic_rest/viewsets.py#L78 overrides the REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES']
setting. Why? Also, why is there a DYNAMIC_REST setting to disable the browsable API?
I think the easier solution would be using the DRF settings. To enable the dynamic browsable API, just add it to these settings. Like:
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'dynamic_rest.renderers.DynamicBrowsableAPIRenderer',
'myproject.renderers.MyRenderer',
),
I am having problems with how drf
, dynamic-rest
and django_filters
are playing together.
I have:
Python 3.6.4
Django==2.0.4
djangorestframework==3.7.7
dynamic-rest==1.8.1
django-filter==1.1.0
I have this defined:
INSTALLED_APPS = (
...
'rest_framework', # utilities for rest apis
'dynamic_rest',
'django_filters', # for filtering rest endpoints
...
}
And this:
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
),
}
This does not work:
class PscViewSet(DynamicModelViewSet):
queryset = PSC.objects.all()
serializer_class = PscSerializer
permission_classes = (AllowAny,)
filter_fields = ('owner',)
No filtering is possible, and the Filters
button is not shown in the browsable API.
Doing this:
class PscViewSet(DynamicModelViewSet):
queryset = PSC.objects.all()
serializer_class = PscSerializer
permission_classes = (AllowAny,)
filter_backends = (filters.DjangoFilterBackend,) # This added
filter_fields = ('owner',)
allows for filtering, but no Filters
button is shown in the browsable API.
Doing this:
class PscViewSet(viewsets.ModelViewSet):
queryset = PSC.objects.all()
serializer_class = PscSerializer
permission_classes = (AllowAny,)
filter_fields = ('owner',)
allows for filtering and shows a Filters
button in the browsable API.
Hi there,
I read https://github.com/AltSchool/dynamic-rest/blob/master/CONTRIBUTING.md but I am still not too sure how to run tests locally before submitting a PR.
I am using this for my own production and for a brand new project, we like to use DREST with the following:
I be happy to help expand compatibility so long as it's within my capability.
Can advise?
https://github.com/AltSchool/dynamic-rest/blob/master/dynamic_rest/filters.py#L656
This gets the serializer_class
attribute from the view. I prefer using the get_serializer_class
method instead of the serializer_class
attribute (for some complicated but valid reason ^^).
DRF first tries to use the method before falling back to the attribute, Dynamic REST should behave the same:
https://github.com/encode/django-rest-framework/blob/master/rest_framework/filters.py#L222
I would suggest using DRF's get_default_valid_fields
method which (unlike get_valid_fields
) seems to return serializer fields.
I could easily fix this, though I'm not sure about how to write a test for it (or if that is even necessary).
I have two serializer classes: FolderSerializer and FileSerializer, see below. I want to include the full representation of any parent folder by default in subfolders, but in doing so I get an infinite recursion loop in filters.py going from line 339 -> line 405 -> line 495 -> line 339 etc. I do not have a loop in my object hierarchy, even when visiting the detail page of a folder without parent (=None) I get this issue. Setting a depth on the Meta class does not help, when changing to the reverse relation (including subfolders in parents) I get a stack overflow error in python resulting in 'Abort trap: 6'.
class FolderSerializer(BaseSerializer):
files = DynamicRelationField("FileSerializer", many=True, deferred=True)
parentFolder = DynamicRelationField("FolderSerializer", embed=True)
class Meta:
model = Folder
fields = ('id', 'parentFolder', 'name', 'files')
read_only_fields = ('id', 'parentFolder', 'files')
class FileSerializer(BaseSerializer):
class Meta:
model = File
fields = ('id',) // Just for testing, only include id
class Folder(models.Model):
id = models.IntegerField(primary_key=True)
owner = models.ForeignKey("User", related_name="folders")
parentFolder = models.ForeignKey('Folder', related_name='subfolders', blank=True, null=True)
name = models.CharField(max_length=40, default="Unnamed folder")
like GET 127.0.0.1:8000/user/profile/?only_fileds[]=name
Hi,
Can you release 1.6.8 to PyPi please, @aleontiev? The fix in bcf9c6cf4a5e2d740b3526a1af75a00ceea419de is not released so I'm getting:
ContextualVersionConflict: (Django 1.11.5, Requirement.parse('Django<=1.11,>=1.8'), set(['dynamic-rest']))
Thanks!
Hello I have a problem with sideloading, when I nest Serializer and include the same object multiple time, but with another fields not all fields are returned.
Location (pk 2) is included in Car (field: short_name) and Part (field: name) but in sideloaded object sometimes short_name
is returned and sometimes name
never both.
Example:
# models.py
class Location(models.Model):
name = models.CharField(max_length=60)
short_name = models.CharField(max_length=30)
description = models.TextField()
class Car(models.Model):
name = models.CharField(max_length=60)
location = models.ForeignKey(Location)
class Part(models.Model):
car = models.ForeignKey(Car)
name = models.CharField(max_length=60)
location = models.ForeignKey(Location)
# serializers.py
class LocationSerializer(DynamicModelSerializer):
name = serializers.CharField(deferred=True)
short_name = serializers.CharField(deferred=True)
description = serializers.CharField(deferred=True)
location = serializers.DynamicRelationField('LocationSerializer', many=True, deferred=True)
class Meta:
model = Location
class PartSerializer(DynamicModelSerializer):
name = serializers.CharField(deferred=True)
description = serializers.CharField(deferred=True)
location = serializers.DynamicRelationField('LocationSerializer', many=True, deferred=True)
class Meta:
model = Car
class CarSerializer(DynamicModelSerializer):
parts = serializers.DynamicRelationField('PartSerializer', many=True, deferred=True)
name = serializers.CharField(deferred=True)
description = serializers.CharField(deferred=True)
class Meta:
model = Car
# viewsets.py
class CarViewset(DynamicModelViewset):
serializer_class = CarSerializer
For query:
localhost:8080/api/cars/1/?include[]=name&include[]=location.short_name&include[]=parts.name&include[]=parts.location.name
I radomly get one of responses:
{
"cars": [
{
"id": 1,
"name": "Porshe",
"location": 2
}
],
"locations": [
{
"id": 1
"name": "China",
},
{
"id": 2
"short_name": "US",
}
],
"parts": [
{
"id": 2,
"name": "wheel",
"location": 2
},
{
"id": 2,
"name": "tire",
"location": 1
}
]
}
or
{
"cars": [
{
"id": 1,
"name": "Porshe",
"location": 2
}
],
"locations": [
{
"id": 1
"name": "China",
},
{
"id": 2
"name": "United States",
}
],
"parts": [
{
"id": 2,
"name": "wheel",
"location": 2
},
{
"id": 2,
"name": "tire",
"location": 1
}
]
}
But I think correct response is like bellow
{
"cars": [
{
"id": 1,
"name": "Porshe",
"location": 2
}
],
"locations": [
{
"id": 1
"name": "China",
},
{
"id": 2
"name": "United States",
"short_name": "Us",
}
],
"parts": [
{
"id": 2,
"name": "wheel",
"location": 2
},
{
"id": 2,
"name": "tire",
"location": 1
}
]
}
I propose this way for fix that: ( wrapped in # SIDELOADING FIX #
comments)
# processors.py
"""This module contains response processors."""
from django.utils import six
from dynamic_rest.processors import SideloadingProcessor as BaseSideloadingProcessor
from rest_framework.utils.serializer_helpers import ReturnDict
from dynamic_rest.conf import settings
class SideloadingProcessor(BaseSideloadingProcessor):
"""A processor that sideloads serializer data.
Sideloaded records are returned under top-level
response keys and produces responses that are
typically smaller than their nested equivalent.
"""
def process(self, obj, parent=None, parent_key=None, depth=0):
"""Recursively process the data for sideloading.
Converts the nested representation into a sideloaded representation.
"""
if isinstance(obj, list):
for key, o in enumerate(obj):
# traverse into lists of objects
self.process(o, parent=obj, parent_key=key, depth=depth)
elif isinstance(obj, dict):
dynamic = self.is_dynamic(obj)
returned = isinstance(obj, ReturnDict)
if dynamic or returned:
# recursively check all fields
for key, o in six.iteritems(obj):
if isinstance(o, list) or isinstance(o, dict):
# lists or dicts indicate a relation
self.process(
o,
parent=obj,
parent_key=key,
depth=depth +
1
)
if not dynamic or getattr(obj, 'embed', False):
return
serializer = obj.serializer
name = serializer.get_plural_name()
instance = getattr(obj, 'instance', serializer.instance)
instance_pk = instance.pk if instance else None
pk = getattr(obj, 'pk_value', instance_pk) or instance_pk
# For polymorphic relations, `pk` can be a dict, so use the
# string representation (dict isn't hashable).
pk_key = repr(pk)
# sideloading
seen = True
# if this object has not yet been seen
if pk_key not in self.seen[name]:
seen = False
self.seen[name].add(pk_key)
# prevent sideloading the primary objects
if depth == 0:
return
# TODO: spec out the exact behavior for secondary instances of
# the primary resource
# if the primary resource is embedded, add it to a prefixed key
if name == self.plural_name:
name = '%s%s' % (
settings.ADDITIONAL_PRIMARY_RESOURCE_PREFIX,
name
)
if not seen:
# allocate a top-level key in the data for this resource
# type
if name not in self.data:
self.data[name] = []
# move the object into a new top-level bucket
# and mark it as seen
self.data[name].append(obj)
# SIDELOADING FIX #
if seen:
ob = [o for o in self.data[name] if o.instance.pk == pk][0]
ob.update(obj)
self.data[name] = [ob if o.instance.pk == pk else o for o in self.data[name]]
# SIDELOADING FIX #
# replace the object with a reference
if parent is not None and parent_key is not None:
parent[parent_key] = pk
Hi!
I am using dynamic-rest to support an application that requires atomic data consistency when performing API requests with sideloading. TL;DR: I think I need to be using select_related instead of prefetch_related when sideloading, but it doesn't seem like this is an option. Thoughts?
My research so for: Per your sideloading documentation, Django supports loading relationships using prefetch_related and select_related. From the Django docs I see that select_related produces a single SQL statement with JOINs, but is limited to foreign keys and one-to-one relationships while prefetch_related uses many SQL statements with joins on the Python side and because of this can also handle many-to-many and many-to-one relationships.
A cursory glance at the dynamic-rest code suggests that prefetch_related is being used to support sideloading. The upside to this is that you can support a wider selection of foreign key types. However, the downside is that using multiple queries to support sideloading means that the state of the database may have changed between performing the two queries.
So, I think I need to be using select_related instead of prefetch_related when sideloading, but it doesn't seem like this is an option. Am I on the write track in that this currently not supported by Dynamic REST? Do you have plans to support this? Would you be open to me adding this feature as a configurable option?
Alternatively, maybe I can wrap GET requests in a transaction? (Would this work the way I want it to work?) I know that Django has the ATOMIC_REQUESTS option, but as the docs state this can come with a significant performance impact.
(PS: Thanks in advanced for your time! We've really enjoyed using Dynamic REST to get our API up and running in a flash.)
Hello,
I have a model with a related many-to-many model. The related model contains several nullable foreign key fields. Because I am working with Datatables, which rely on nested JSON data, I am using embedded data.
However, The base model will only serialize individual instances if the many-to-many model (i.e. the junction table) has all of its fields set to deferred=True
. If I do not set the related model's fields to deferred, then I receive the following error:
'DynamicListSerializer' object has no attribute 'debug'
This happens even if I do not include[]
the related many-to-many model. It happens even if I specifically exclude it as well (which seems to tell me that a query is being run, even though I thought the field was being deferred).
Here is the full text of the error report:
Environment:
Request Method: GET
Request URL: http://localhost:8000/api/cases/157/
Django Version: 1.11
Python Version: 3.4.3
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'peasantlegaldb',
'coverage',
'rest_framework',
'webpack_loader',
'dynamic_rest',
'rest_framework_serializer_extensions',
'django_js_reverse',
'django_filters',
'peasantlegaldb.templatetags',
'widget_tweaks']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback:
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/dynamic_rest/fields/fields.py" in to_representation
296. return serializer.to_representation(related)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/dynamic_rest/serializers.py" in to_representation
48. return [self.child.to_representation(item) for item in iterable]
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/dynamic_rest/serializers.py" in <listcomp>
48. return [self.child.to_representation(item) for item in iterable]
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/dynamic_rest/serializers.py" in to_representation
535. representation = self._faster_to_representation(instance)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/dynamic_rest/serializers.py" in _faster_to_representation
518. ret[field.field_name] = field.to_representation(attribute)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/dynamic_rest/fields/fields.py" in to_representation
289. related = getattr(instance, source)
During handling of the above exception ('Person' object has no attribute 'chevage'), another exception occurred:
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/django/core/handlers/exception.py" in inner
41. response = get_response(request)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/django/core/handlers/base.py" in _get_response
217. response = self.process_exception_by_middleware(e, request)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/django/core/handlers/base.py" in _get_response
215. response = response.render()
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/django/template/response.py" in render
107. self.content = self.rendered_content
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/response.py" in rendered_content
72. ret = renderer.render(self.data, accepted_media_type, context)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/renderers.py" in render
703. context = self.get_context(data, accepted_media_type, renderer_context)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/dynamic_rest/renderers.py" in get_context
16. context
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/renderers.py" in get_context
637. raw_data_put_form = self.get_raw_data_form(data, view, 'PUT', request)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/renderers.py" in get_raw_data_form
559. content = renderer.render(serializer.data, accepted, context)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/dynamic_rest/serializers.py" in data
607. data = super(WithDynamicSerializerMixin, self).data
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/serializers.py" in data
531. ret = super(Serializer, self).data
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/rest_framework/serializers.py" in data
262. self._data = self.to_representation(self.instance)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/dynamic_rest/serializers.py" in to_representation
535. representation = self._faster_to_representation(instance)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/dynamic_rest/serializers.py" in _faster_to_representation
518. ret[field.field_name] = field.to_representation(attribute)
File "/home/vagrant/.virtualenvs/medievaldb/lib/python3.4/site-packages/dynamic_rest/fields/fields.py" in to_representation
299. if serializer.debug:
Exception Type: AttributeError at /api/cases/157/
Exception Value: 'DynamicListSerializer' object has no attribute 'debug'
I can copy-paste my models and serializers too, if that would help.
I am not sure what is going on, since dynamic-rest 1.8.0
is supposed to be compatible with django 2.0.7:
» poetry add dynamic-rest==1.8.0
Updating dependencies
Resolving dependencies... (0.2s)
[SolverProblemError]
Because dynamic-rest (1.8.0) depends on Django (>=1.8,<2.0)
and poetry-demo depends on Django (^2.0.7), dynamic-rest is forbidden.
So, because poetry-demo depends on dynamic-rest (=1.8.0), version solving failed.
add [-D|--dev] [--git GIT] [--path PATH] [-E|--extras EXTRAS] [--optional] [--python PYTHON] [--platform PLATFORM] [--allow-prereleases] [--dry-run] [--] <name> (<name>)...
I am on python 3.6.5:
» python --version
Python 3.6.5
First of all, this package seems very promising and maybe I´m just misunderstanding how it works...but:
Is there a possibility to restrict which ViewSet actions that the DynamicViewSet class exposes? Basically I would just like to make use of the include feature on one of my current ViewSet actions (e.g. retrieve). As I understand I would need your Serializer, Viewset, and Router to make this work? And that would make my current ViewSet (DRF) a complete CRUD ViewSet which is not what I want since it currently only holds the retrieve action.
In my example I´m fetching a User object and I would like to expand (include) the relationship that the user has to its set of permissions and groups...just that, nothing more (at the moment at least).
Sometimes views allow certain methods and not others. You can whitelist the ones you want in DRF with, for instance:
class MyView(
mixins.UpdateModelMixin,
viewsets.GenericViewSet):
instead of using ModelViewSet
which incorporates all actions.
How would you replicate this with a DynamicViewSet?
I can only get the request GET /events/1/location/
to work if deferred=True
for the DynamicRelationField
"location" in my EventSerializer.
Informational:
django-admin => 1.10.6
python => 2.7.13
Simple Project
Hi,
the latest relased version on pypi is 1.6.4
Can you update package?
Best wishes,
Darek
Hi,
like in subject pip3 install dynamic_rest
downgrade django version to bugged 1.11 version.
If I declare one field as deferred I cannot use it as sort parameter,
For example:
class AnimalSerializer(DynamicModelSerializer):
class Meta:
model = Animal
fields = "__all__"
deferred_fields = ('boughtOn',)
When I try to call myapi.com/animal/?include[]=boughtOn&sort[]=boughtOn
I get the follow message:
"Invalid filter field: [u'boughtOn']"
I debug the dynamic-rest and it only validates the sort fields with not deferred fields in the serializer.
Django==2.0.3
DRF==3.7.7
The dynamic_rest.patches.patch_prefetch_one_level
patch is incompatible.
prefetcher.get_prefetch_queryset returns ValueError: too many values to unpack (expected 5)
I'm looking to expand the functionality to handle sorting and filtering for JSON field data.
Would like this to work using PostgresSQL database's built-in jsonb object which allows indexing. Would involve augmenting one of the models to include nested JSON. Here are the options I came up with:
https://docs.djangoproject.com/en/2.1/ref/contrib/postgres/fields/
Hi,
I know this isn't the right place for Q&A, but I haven't found any documented place to ask questions, so I'm asking here. Is there a way to dynamically sort records in descending order, e.g. something like /clients?sort[]=name.desc&page=2&per_page=5
(this doesn't work obviously). I could sort the records on the client side, but that doesn't cover the pagination case.
Is there any way to use the list(self, request, *args, **kwargs)
method to exclude certain serializer fields?
I'm using the Taggit library (https://github.com/alex/django-taggit) and have run into an issue when exposing tags
on one of my serializers:
The field looks like this :
tags = DynamicRelationField(TagSerializers,
many=True,
read_only=True)
It blows up with this error from the taggit object manager: https://github.com/alex/django-taggit/blob/master/taggit/managers.py#L100
I've tried adding requires=['tags.*', '*'],
but I get the same error.
Thanks!
it seem you import six in utils.py
, but six is not in your install_requires.txt
.
hi,
I found a bug if make a search with a field that does not exists in the serializer : /?filter{fieldnotinserializer}=val
.
ValueError: too many values to unpack
it seem that the signature of DynamicSortingFilter.get_valid_fields does not match his parent class's.
the original result from django-rest-framework is a list of 2n tuple, but you return a list of 3n tuple.
it seem that this broke the OrderingFilter.get_template_context method since the commit aeb57913c9f2a7ad1ffc1db825c3e6f44b4818ee of restframowork which do no longer pass the result of get_valid_fields but iterate over it instead.
this happen by browsing the django-rest-framework interface
version used :
I have models that look something like this:
class MyModelA(django.db.models.Model):
name = models.CharField(unique=True, max_length=20)
class MyModelB(ExtraDataModel):
name = models.CharField(unique=True, max_length=20)
my_model_a = models.ForeignKey(MyModelA, on_delete=models.CASCADE)
And serializers that set up foreign key fields using DynamicRelationField
. If I make a POST to /my_model_b/ with a my_model_a id corresponding to a non-existent MyModelA, then I get a 404 response code back. This seems weird, because the endpoint that I am communicating with, /my_model_b/, definitely exists. I would instead classify this as a validation error.
I've found where the NotFound exception is being thrown by catching the exception in the DynamicModelViewSet
create method:
Traceback (most recent call last):
File "/Users/jvillbrandt/repos/asrs/app/urls.py", line 77, in create
response = super(ViewSet, self).create(request, *args, **kwargs)
File "/Users/jvillbrandt/repos/asrs/env/lib/python2.7/site-packages/dynamic_rest-1.6.7-py2.7.egg/dynamic_rest/viewsets.py", line 533, in create
request, *args, **kwargs)
File "/Users/jvillbrandt/repos/asrs/env/lib/python2.7/site-packages/djangorestframework-3.6.2-py2.7.egg/rest_framework/mixins.py", line 20, in create
serializer.is_valid(raise_exception=True)
File "/Users/jvillbrandt/repos/asrs/env/lib/python2.7/site-packages/djangorestframework-3.6.2-py2.7.egg/rest_framework/serializers.py", line 236, in is_valid
self._validated_data = self.run_validation(self.initial_data)
File "/Users/jvillbrandt/repos/asrs/env/lib/python2.7/site-packages/djangorestframework-3.6.2-py2.7.egg/rest_framework/serializers.py", line 431, in run_validation
value = self.to_internal_value(data)
File "/Users/jvillbrandt/repos/asrs/env/lib/python2.7/site-packages/dynamic_rest-1.6.7-py2.7.egg/dynamic_rest/serializers.py", line 564, in to_internal_value
value = super(WithDynamicSerializerMixin, self).to_internal_value(data)
File "/Users/jvillbrandt/repos/asrs/env/lib/python2.7/site-packages/djangorestframework-3.6.2-py2.7.egg/rest_framework/serializers.py", line 461, in to_internal_value
validated_value = field.run_validation(primitive_value)
File "/Users/jvillbrandt/repos/asrs/env/lib/python2.7/site-packages/djangorestframework-3.6.2-py2.7.egg/rest_framework/fields.py", line 524, in run_validation
value = self.to_internal_value(data)
File "/Users/jvillbrandt/repos/asrs/env/lib/python2.7/site-packages/dynamic_rest-1.6.7-py2.7.egg/dynamic_rest/fields/fields.py", line 338, in to_internal_value
return self.to_internal_value_single(data, self.serializer)
File "/Users/jvillbrandt/repos/asrs/env/lib/python2.7/site-packages/dynamic_rest-1.6.7-py2.7.egg/dynamic_rest/fields/fields.py", line 322, in to_internal_value_single
(related_model.__name__, data)
NotFound: 'MyModelA object with ID=0 not found
Is the 404 behavior expected in this scenario? Maybe I am doing something wrong? Otherwise, could you advise me to the best method to get this behavior to throw a 400 instead? In addition, I'd like the response body to include the name of the field that caused the error just like any other validation error.
PS: Any idea why there is a '
character in the front of the error message?
is it as simple as ?filter{field1.icontains}=query&filter{field2.icontains}=query&filter{field3.icontains}=query
?
I installed the demo site but the directory panel isn't showing up. Confirmed that the following is in settings.py per the documentation.
REST_FRAMEWORK = {
'PAGE_SIZE': 50,
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'dynamic_rest.renderers.DynamicBrowsableAPIRenderer'
)
}
I love this project. ❤️
I may start using this open source library in commercial projects. When I do receive revenue, I like to give back via some kind of patreon or some kind of direct contribution.
I am not talking about huge amounts. Maybe a $5 or $10 every once in a while.
Thank you for doing dynamic-rest
I am currently using
url(r"^$", TemplateView.as_view(template_name="pages/home.html"), name="home"),
so how do I change the default url for the browsable panel?
First of all, love this project so far!
From what I can determine from looking at https://github.com/AltSchool/dynamic-rest/blob/master/dynamic_rest/routers.py, it doesn't appear as though there's any support for managing nested relationships. Is this correct? If so, is there any intention on supporting this?
We are currently using drf-extensions to support nested routes, however I'd love to be able to rely solely on drf
and dynamic-rest
.
Getting import error
cannot import name 'replace_methodname'
Nested relationship endpoints like /events/5/users/
don't work when the DynamicRelationField
is deferred
, since deferred fields are removed from serializer.fields
here and DynamicModelViewSet.list_related()
raises ValidationError
if the field isn't found in serializer.fields
here. The deferred fields are included in serializer.get_all_fields()
, but I have no idea if it's safe to use that instead of serializer.fields
in DynamicModelViewSet.list_related()
.
I annotate the count of a relation in my queryset ...
queryset = Location.objects.all.annotate(cats_count=Count('cats'))
... and add the field to the serializer ...
cats_count = serializers.IntegerField(read_only=True)
This works fine, I can filter on locations and cats. But I can not filter on cats_count, like &filter{casts_count.gt}=0
(I want do do this dynamically, so I can include or exclude zero-results). But this raises an AttributeError: cats_count is not a valid field for <class 'models.Location'>
because generate_query_key only checks for model fields, not serializer fields https://github.com/AltSchool/dynamic-rest/blob/master/dynamic_rest/filters.py#L116
Any idea how I to approach this?
circle CI fails on Dependencies > pyenv local 2.7.10 3.3.3 3.4.3 3.5.0 with pyenv: version '3.3.3' not installed
(same goes for 3.5.0 if you fix that). Has there been some change on Circle CI?
This can be fixed by installing the versions before using them. Also, I would suggest testing the newest versions of Py2 and Py3.
This circle.yml works, though I think we could omit some of these versions to speed up the build:
dependencies:
override:
- pip install -r requirements.txt
- python setup.py develop
- pyenv install -s 2.7.13
- pyenv install -s 3.3.3
- pyenv install -s 3.4.3
- pyenv install -s 3.5.0
- pyenv install -s 3.6.1
- pyenv local 2.7.13 3.3.3 3.4.3 3.5.0 3.6.1
test:
override:
- ENABLE_INTEGRATION_TESTS=True py.test tests/integration
- tox
This issue is in connection with #176 issue
Unfortunately, there is another case not covered by previous issue PR:
# models.py
class Region(models.Model):
name = models.CharField(max_length=60)
short_name = models.CharField(max_length=30)
parent = models.ForeignKey('Region')
localhost:8080/api/regions/?include[]=name&include[]=parent&include[]=parent.short_name
Output is:
{
"+regions": [
{
"id": 3,
"short_name": "LBL",
}
],
"regions": [
{
"id": 1
"name": "Opolskie",
"parent": null
},
{
"id": 2
"name": "Opole",
"parent": 1
},
{
"id": 4,
"name": Lublin,
"parent": 3
}
]
}
But should be:
{
"+regions": [
{
"id": 3,
"short_name": "LBL",
}
],
"regions": [
{
"id": 1
"name": "Opolskie",
"short_name": "OPO",
"parent": null
},
{
"id": 2
"name": "Opole",
"parent": 1
},
{
"id": 4,
"name": Lublin,
"parent": 3
}
]
}
At this moment I don't have idea how to modify processors.py to cover this case.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.