-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
176 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
from .exceptions import BinderMethodNotAllowed, BinderNotFound | ||
|
||
|
||
def _route_decorator(is_detail, name=None, methods=None, extra_route='', unauthenticated=False, *, fetch_obj=False): | ||
def decorator(func): | ||
def wrapper(self, request=None, *args, **kwargs): | ||
if methods is not None and request.method not in methods: | ||
raise BinderMethodNotAllowed(methods) | ||
|
||
if fetch_obj: | ||
if 'pk' in kwargs: | ||
pk = kwargs['pk'] | ||
del kwargs['pk'] | ||
|
||
try: | ||
kwargs['obj'] = self.get_queryset(request).get(pk=pk) | ||
except self.model.DoesNotExist: | ||
raise BinderNotFound() | ||
else: | ||
if len(args) == 0: | ||
raise Exception('Can not fetch_obj if there is no pk!') | ||
|
||
args = list(args) | ||
pk = args[0] | ||
try: | ||
args[0] = self.get_queryset(request).get(pk=pk) | ||
except self.model.DoesNotExist: | ||
raise BinderNotFound() | ||
|
||
return func(self, request, *args, **kwargs) | ||
if is_detail: | ||
wrapper.detail_route = True | ||
else: | ||
wrapper.list_route = True | ||
|
||
wrapper.route_name = name | ||
wrapper.extra_route = extra_route | ||
wrapper.unauthenticated = unauthenticated | ||
return wrapper | ||
return decorator | ||
|
||
|
||
def list_route(*args, **kwargs): | ||
return _route_decorator(False, *args, **kwargs) | ||
|
||
|
||
def detail_route(*args, **kwargs): | ||
return _route_decorator(True, *args, **kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Stats | ||
|
||
Next to the regular CRUD API binder also supports an easy way to gather | ||
statistics about the records you are querying. The rest of this document | ||
assumes that `testapp.views.animal.AnimalView` is registered at `/api/animal/`. | ||
|
||
## Querying Stats | ||
|
||
Stats can be queried through `GET /api/animal/stats/`, this endpoint behaves | ||
similar to `GET /api/animal/` in terms of what filters etc you can supply. The | ||
only extra requirement is that it expects a `stats`-parameter indicating what | ||
stats you want to query. | ||
|
||
For example if you would want to query the stats `total` and `by_zoo` for all | ||
animals that do not have a caretaker you could do the following request: | ||
|
||
``` | ||
GET /api/animal/?stats=total,by_zoo&.caretaker:isnull=true | ||
{ | ||
"total": { | ||
"value": <total>, | ||
"filters": {}, | ||
}, | ||
"by_zoo": { | ||
"value": {, | ||
<zoo name>: <total>, | ||
... | ||
} | ||
"filters": {}, | ||
"group_by": "zoo.name", | ||
}, | ||
} | ||
``` | ||
|
||
So you can see you get some data for every statistic, the `value`-key here is | ||
the most important since it will contain the actual statistic. Next to that you | ||
will have some meta information with the `filters`-key and the optional | ||
`group_by`-key. This information can be used to filter on certain | ||
statistics. | ||
|
||
## Defining Stats | ||
|
||
You can define stats by setting the `stats` property on the view. This should | ||
be a dict that resembles this: | ||
|
||
``` | ||
{ | ||
name: { | ||
'expr': an aggregate expr to get the statistic, | ||
'filter': a dict of filters to filter the queryset with before getting the aggregate, leading dot not included (optional), | ||
'group_by': a field to group by separated by dots if following relations (optional), | ||
'annotations': a list of annotation names that have to be applied to the queryset for the expr to work (optional), | ||
}, | ||
... | ||
} | ||
``` | ||
|
||
By default the stat `total` is already defined for every view. This will give | ||
the total amount of records in the dataset. The definition for this looks like this: | ||
|
||
``` | ||
'total': { | ||
'expr': Count(Value(1)), | ||
}, | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters