Alex Daigle
2018-07-19 15:16:21 UTC
To whom this may concern,
My error message says 'APIRoot' object has no attribute 'get_queryset'. I
have my views initialized with a custom class, based on the SimpleMetadata
class in rest_framework.metadata.
# ./views/__init__.py
from rest_framework.metadata import SimpleMetadata
_filter_fields_cache = {}
_ordering_fields_cache = {}
class RodanMetadata(SimpleMetadata):
"""
Customize `OPTIONS` response to include filterable and orderable fields.
"""
def determine_metadata(self, request, view):
metadata = super(RodanMetadata, self).determine_metadata(request,
view)
metadata['filter_fields'] = self.get_filter_fields(view)
metadata['ordering_fields'] = self.get_ordering_fields(view)
return metadata
def get_filter_fields(self, view):
if view in _filter_fields_cache:
return _filter_fields_cache[view]
else:
if hasattr(view, 'filter_class'):
fc = view.filter_class()
fields = {}
for k in fc.filters.keys():
things = k.rsplit("__", 1)
field = things[0]
if field not in fields:
fields[field] = []
if len(things) == 1:
fields[field].append('exact')
elif len(things) == 2:
lookup_type = things[1]
fields[field].append(lookup_type)
elif hasattr(view, 'filter_fields'):
if isinstance(view.filter_fields, dict):
fields = view.filter_fields
else:
fields = {}
for field in view.filter_fields:
fields[field] = ['exact']
else:
fields = {}
_filter_fields_cache[view] = fields
return fields
def get_ordering_fields(self, view):
if view in _ordering_fields_cache:
return _ordering_fields_cache[view]
else:
m = view.get_queryset().model
fs = m._meta.fields
fields = set([])
for f in fs:
if f.primary_key or f.db_index:
fields.add(f.name)
s = view.get_serializer()
fields = fields.intersection(set(s.fields.keys()))
if hasattr(view, 'ordering_fields') and view.ordering_fields !=
'__all__':
fields = fields.intersection(set(view.ordering_fields))
fields = tuple(fields)
_ordering_fields_cache[view] = fields
return fields
And the main class like this. As we can see, get_queryset is not present
here, or in APIView from the rest_framework library.
# ./views/main.py
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework import permissions
import rodan
from rodan.jobs import package_versions
class APIRoot(APIView):
permission_classes = (permissions.AllowAny, )
def get(self, request, format=None):
response = {
'routes': {
'projects': reverse('project-list', request=request, format=
format),
'workflows': reverse('workflow-list', request=request,
format=format),
'workflowjobs': reverse('workflowjob-list', request=request,
format=format),
'workflowjobgroups': reverse('workflowjobgroup-list',
request=request, format=format),
'workflowruns': reverse('workflowrun-list', request=request,
format=format),
'runjobs': reverse('runjob-list', request=request, format=
format),
'jobs': reverse('job-list', request=request, format=format),
'users': reverse('user-list', request=request, format=format
),
'userpreferences': reverse('userpreference-list', request=
request, format=format),
'resultspackages': reverse('resultspackage-list', request=
request, format=format),
'connections': reverse('connection-list', request=request,
format=format),
'outputporttypes': reverse('outputporttype-list', request=
request, format=format),
'outputports': reverse('outputport-list', request=request,
format=format),
'inputporttypes': reverse('inputporttype-list', request=
request, format=format),
'inputports': reverse('inputport-list', request=request,
format=format),
'resources': reverse('resource-list', request=request,
format=format),
'resourcelists': reverse('resourcelist-list', request=
request, format=format),
'resourcetypes': reverse('resourcetype-list', request=
request, format=format),
'outputs': reverse('output-list', request=request, format=
format),
'inputs': reverse('input-list', request=request, format=
format),
'taskqueue-active': reverse('taskqueue-active', request=
request, format=format),
'taskqueue-scheduled': reverse('taskqueue-scheduled',
request=request, format=format),
'taskqueue-status': reverse('taskqueue-status', request=
request, format=format),
'workflowjobcoordinatesets': reverse(
'workflowjobcoordinateset-list', request=request, format=format),
'workflowjobgroupcoordinatesets': reverse(
'workflowjobgroupcoordinateset-list', request=request, format=format),
'auth-me': reverse('auth-me', request=request, format=format
),
'auth-register': reverse('auth-register', request=request,
format=format),
'auth-token': reverse('auth-token', request=request, format=
format),
'auth-reset-token': reverse('auth-reset-token', request=
request, format=format),
'auth-change-password': reverse('auth-change-password',
request=request, format=format),
},
'configuration': {
'page_length': settings.REST_FRAMEWORK['PAGINATE_BY'],
'job_packages': package_versions,
},
'version': rodan.__version__
}
return Response(response)
I found the `get_queryset` method in generic.py(inside the rest_framework
library), and not in metadata.py. It is inside the GenericAPIView class. My
question is, should I add the method in the custom class(APIRoot)? Or
somehow import the class to add this method?
def get_queryset(self):
"""
Get the list of items for this view.
This must be an iterable, and may be a queryset.
Defaults to using `self.queryset`.
This method should always be used rather than accessing
`self.queryset`
directly, as `self.queryset` gets evaluated only once, and those
results
are cached for all subsequent requests.
You may want to override this if you need to provide different
querysets depending on the incoming request.
(Eg. return a list of items that is specific to the user)
"""
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
)
queryset = self.queryset
if isinstance(queryset, QuerySet):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
return queryset
My error message says 'APIRoot' object has no attribute 'get_queryset'. I
have my views initialized with a custom class, based on the SimpleMetadata
class in rest_framework.metadata.
# ./views/__init__.py
from rest_framework.metadata import SimpleMetadata
_filter_fields_cache = {}
_ordering_fields_cache = {}
class RodanMetadata(SimpleMetadata):
"""
Customize `OPTIONS` response to include filterable and orderable fields.
"""
def determine_metadata(self, request, view):
metadata = super(RodanMetadata, self).determine_metadata(request,
view)
metadata['filter_fields'] = self.get_filter_fields(view)
metadata['ordering_fields'] = self.get_ordering_fields(view)
return metadata
def get_filter_fields(self, view):
if view in _filter_fields_cache:
return _filter_fields_cache[view]
else:
if hasattr(view, 'filter_class'):
fc = view.filter_class()
fields = {}
for k in fc.filters.keys():
things = k.rsplit("__", 1)
field = things[0]
if field not in fields:
fields[field] = []
if len(things) == 1:
fields[field].append('exact')
elif len(things) == 2:
lookup_type = things[1]
fields[field].append(lookup_type)
elif hasattr(view, 'filter_fields'):
if isinstance(view.filter_fields, dict):
fields = view.filter_fields
else:
fields = {}
for field in view.filter_fields:
fields[field] = ['exact']
else:
fields = {}
_filter_fields_cache[view] = fields
return fields
def get_ordering_fields(self, view):
if view in _ordering_fields_cache:
return _ordering_fields_cache[view]
else:
m = view.get_queryset().model
fs = m._meta.fields
fields = set([])
for f in fs:
if f.primary_key or f.db_index:
fields.add(f.name)
s = view.get_serializer()
fields = fields.intersection(set(s.fields.keys()))
if hasattr(view, 'ordering_fields') and view.ordering_fields !=
'__all__':
fields = fields.intersection(set(view.ordering_fields))
fields = tuple(fields)
_ordering_fields_cache[view] = fields
return fields
And the main class like this. As we can see, get_queryset is not present
here, or in APIView from the rest_framework library.
# ./views/main.py
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework import permissions
import rodan
from rodan.jobs import package_versions
class APIRoot(APIView):
permission_classes = (permissions.AllowAny, )
def get(self, request, format=None):
response = {
'routes': {
'projects': reverse('project-list', request=request, format=
format),
'workflows': reverse('workflow-list', request=request,
format=format),
'workflowjobs': reverse('workflowjob-list', request=request,
format=format),
'workflowjobgroups': reverse('workflowjobgroup-list',
request=request, format=format),
'workflowruns': reverse('workflowrun-list', request=request,
format=format),
'runjobs': reverse('runjob-list', request=request, format=
format),
'jobs': reverse('job-list', request=request, format=format),
'users': reverse('user-list', request=request, format=format
),
'userpreferences': reverse('userpreference-list', request=
request, format=format),
'resultspackages': reverse('resultspackage-list', request=
request, format=format),
'connections': reverse('connection-list', request=request,
format=format),
'outputporttypes': reverse('outputporttype-list', request=
request, format=format),
'outputports': reverse('outputport-list', request=request,
format=format),
'inputporttypes': reverse('inputporttype-list', request=
request, format=format),
'inputports': reverse('inputport-list', request=request,
format=format),
'resources': reverse('resource-list', request=request,
format=format),
'resourcelists': reverse('resourcelist-list', request=
request, format=format),
'resourcetypes': reverse('resourcetype-list', request=
request, format=format),
'outputs': reverse('output-list', request=request, format=
format),
'inputs': reverse('input-list', request=request, format=
format),
'taskqueue-active': reverse('taskqueue-active', request=
request, format=format),
'taskqueue-scheduled': reverse('taskqueue-scheduled',
request=request, format=format),
'taskqueue-status': reverse('taskqueue-status', request=
request, format=format),
'workflowjobcoordinatesets': reverse(
'workflowjobcoordinateset-list', request=request, format=format),
'workflowjobgroupcoordinatesets': reverse(
'workflowjobgroupcoordinateset-list', request=request, format=format),
'auth-me': reverse('auth-me', request=request, format=format
),
'auth-register': reverse('auth-register', request=request,
format=format),
'auth-token': reverse('auth-token', request=request, format=
format),
'auth-reset-token': reverse('auth-reset-token', request=
request, format=format),
'auth-change-password': reverse('auth-change-password',
request=request, format=format),
},
'configuration': {
'page_length': settings.REST_FRAMEWORK['PAGINATE_BY'],
'job_packages': package_versions,
},
'version': rodan.__version__
}
return Response(response)
I found the `get_queryset` method in generic.py(inside the rest_framework
library), and not in metadata.py. It is inside the GenericAPIView class. My
question is, should I add the method in the custom class(APIRoot)? Or
somehow import the class to add this method?
def get_queryset(self):
"""
Get the list of items for this view.
This must be an iterable, and may be a queryset.
Defaults to using `self.queryset`.
This method should always be used rather than accessing
`self.queryset`
directly, as `self.queryset` gets evaluated only once, and those
results
are cached for all subsequent requests.
You may want to override this if you need to provide different
querysets depending on the incoming request.
(Eg. return a list of items that is specific to the user)
"""
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
)
queryset = self.queryset
if isinstance(queryset, QuerySet):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
return queryset
--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.