# Alliance Utils
![CI Tests](https://github.com/AllianceSoftware/django-allianceutils/workflows/Django%20CI/badge.svg)
A collection of utilities for django projects from [Alliance Software](https://www.alliancesoftware.com.au/).
* [Installation](#installation)
* [Usage](#usage)
* [API](#api)
* [Auth](#auth)
* [Decorators](#decorators)
* [Filters](#filters)
* [Management](#management)
* [Commands](#commands)
* [Checks](#checks)
* [Middleware](#middleware)
* [Migrations](#migrations)
* [Models](#models)
* [Rules](#rules)
* [Serializers](#serializers)
* [Template Tags](#template-tags)
* [Util](#util)
* [Changelog](#changelog)
## Installation
`pip install django-allianceutils`
## System Requirements
* Tested with django 2.2 and 3.2
* Pull requests accepted for other versions, but at minimum we test against current LTS versions
* Python >=3.6 (no python 3.5 support)
## Usage
### API
#### Mixins
##### SerializerOptInFieldsMixin
Regulates fields exposed on a Serializer by default & as requested based on query parameters or context.
* Pass 'include_fields' / 'opt_in_fields' thru query params or context to use.
* multiple fields can either be separated by comma
eg, `/?include_fields=first_name,email&opt_in_fields=gait_recognition_prediction`
* or passed in the traditional list fashion
eg, `/?include_fields=first_name&include_fields=email&opt_in_fields=gait_recognition_prediction`
* or mixed eg, `/?include_fields=first_name,email&include_fields=boo`
* By default, all "fields" defined in serializer, minus those listed in "opt_in_fields" would be returned.
* If "include_fields" is supplied, only fields requested this way would be returned.
* If "opt_in_fields" is supplied, fields requested this way PLUS fields from #1 or #2 would be returned.
* Pinned fields are always returned (defaults to primary key)
Usage:
```python
class UserSerializer(SerializerOptInFieldsMixin, ModelSerializer):
class Meta:
model = User
fields = (
"id",
"first_name",
"last_name",
"email",
"region",
"activated_at",
"is_staff",
)
# These fields only returned if explicitly requested
opt_in_only_fields = ["activated_at", "is_staff"]
```
#### Permissions
##### register_custom_permissions
* Creates permissions that have no model by linking them to an empty content type
* Django creates permissions as part of
the [`post_migrate` signal](https://docs.djangoproject.com/en/stable/ref/signals/#post-migrate)
Usage
```py
def on_post_migrate(sender, **kwargs):
register_custom_permissions("myapp", ("my_perm", "My Permission"))
```
##### SimpleDjangoObjectPermissions
Permission class for Django Rest Framework that adds support for object level permissions.
Differs from just DRF's [DjangoObjectPermissions](https://www.django-rest-framework.org/api-guide/permissions/#object-level-permissions) because it
* does not require a queryset
* uses the same permission for every request http method and ViewSet method
Notes
* The default django permissions system will [always return False](https://docs.djangoproject.com/en/stable/topics/auth/customizing/#handling-object-permissions) if given an object; you must be using another permissions backend
* As per [DRF documentation](http://www.django-rest-framework.org/api-guide/permissions/#object-level-permissions): get_object() is only required if you want to implement object-level permissions
* **WARNING** If you override `get_object()` then you need to *manually* invoke `self.check_object_permissions(self.request, obj)`
* Will attempt to check permission both globally and on a per-object basis but considers it an error if the check returns True for both
*
Usage
* See [DRF permissions policy](https://www.django-rest-framework.org/api-guide/permissions/#setting-the-permission-policy) for details on apply Permissions policies globally
* To apply to a specific view you need to set `permission_required`
```python
class MyAPIView(SimpleDjangoObjectPermissions, APIView):
permission_required = 'my_module.my_permission'
permission_classes = [allianceutils.api.permissions.SimpleDjangoObjectPermissions]
```
If you have no object level permissions (eg. from rules) then it will just do a static permission check.
##### GenericDjangoViewsetPermissions
* Map viewset actions to Django permissions.
* The model used for permission is extracted from the ViewSet
* If you implement `get_permission_model` on the ViewSet that will be used
* Otherwise it will call `get_queryset` on the ViewSet and extract the model from the returned queryset
* To alter this behaviour extends `GenericDjangoViewsetPermissions` and implement `get_model`
* Usage example:
```
class MyViewSet(GenericDjangoViewsetPermissions, viewsets.ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MySerializer
```
* `GenericDjangoViewsetPermissions.default_actions_to_perms_map` defines the default set of permissions. These can be extended or overridden using `actions_to_perms_map`:
```
class MyViewSet(GenericDjangoViewsetPermissions, viewsets.ModelViewSet):
# ...
actions_to_perms_map = {
'create': []
}
```
* No permissions will be required for the create action, but permissions for other actions will remain unchanged.
* By default permissions checks are passed the relevant model instance for per-object permission checks
* This assumes that your backend doesn't ignore the model object (default django permissions simply ignore any object passed to a permissions check)
* Since there is no model object, functions decorated with `@list_route` will pass `None` as the permissions check object
#### Parsers
##### CamelCaseJSONParser
Parser that recursively turns camelcase keys into underscored keys for JSON data.
This can be set globally on the [DEFAULT_PARSER_CLASSES](https://www.django-rest-framework.org/api-guide/settings/#default_parser_classes)
setting or on a ViewSet on the `parser_classes` property.
##### CamelCaseMultiPartJSONParser
Parser that recursively turns camelcase keys into underscored keys for JSON data and handles file uploads.
This parser supports receiving JSON data where a field value anywhere in the structure can be a file.
This is achieved on the frontend by converting a structure like:
```js
{
name: 'Test',
photo: File,
}
```
And converting it to
```js
{
name: 'Test',
photo: '____ATTACHED_FILE_ID_1',
}
```
This is then set on a field `jsonData` and the file is set on `____ATTACHED_FILE_ID_1` and submitted
as multipart.
This parser then handles parsing the JSON data into a dict and setting each attached file on the
correct key in the dict.
Note that this works with nested data (ie. any File anywhere in a nested JSON structure is supported).
To activate this behaviour the `X-MultiPart-JSON` header must be set to '1' or 'true'. If this header
is not set it falls back to the default behaviour of MultiPartParser
This can be set globally on the [DEFAULT_PARSER_CLASSES](https://www.django-rest-framework.org/api-guide/settings/#default_parser_classes)
setting or on a ViewSet on the `parser_classes` property.
Example frontend code to activate:
```js
let fileCount = 0;
const files = {};
const replacer = (key, value) => {
if (value instanceof File) {
const id = `____ATTACHED_FILE_ID_${fileCount++}`;
files[id] = value;
return id;
}
return value;
};
const stringifiedData = JSON.stringify(data, replacer);
const body = new FormData();
const body.append('jsonData', stringifiedData);
for (const [fileKey, file] of Object.entries(files)) {
body.append(fileKey, file);
}
// eg. using a presto Endpoint
await myEndpoint.execute({
body,
headers: {
// Remove default content type from endpoint (eg. json)
'Content-Type': undefined,
PyPI 官网下载 | django-allianceutils-2.1.0.tar.gz
版权申诉
144 浏览量
2022-01-10
15:19:41
上传
评论
收藏 69KB GZ 举报
挣扎的蓝藻
- 粉丝: 13w+
- 资源: 15万+
最新资源
- redis-win-2.8.9,redis-win-2.8.9
- Servlet和JDBC实现三层架构
- Appium-Inspector-2024.6.1-win
- Screenshot_2024-06-14-21-22-39-202_net.csdn.csdnplus.jpg
- Appium-Server-GUI-windows-1.22.3-4
- 基于C语言+python实现的永磁同步电机矢量控制算法仿真+源码(毕业设计&课程设计&项目开发)
- APKPure_v3.20.05_apkpure.com.apk
- HKJC_AOSBS_PROD_L2.7R2Q_Build8172.apk
- jetson官网下载的官方资料
- 小游戏的java程序开发
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈