# Django sweet utils.
[![Downloads](https://static.pepy.tech/personalized-badge/django-sweet-utils?period=total&units=international_system&left_color=black&right_color=orange&left_text=Downloads)](https://pepy.tech/project/django-sweet-utils)
A little django code sugar.
> If you find this package useful, please star it on [GitHub](https://github.com/AllYouZombies/django-sweet-utils).
## Quickstart
1. Add `django_sweet_utils` to your `INSTALLED_APPS` setting like this:
```
INSTALLED_APPS = [
...
'django_sweet_utils',
...
]
```
2. Inherit your models from `django_sweet_utils.db.models.Model`:
```
from django_sweet_utils.db.models import Model
class MyModel(Model):
...
```
From now your models has the following fields:
- `uuid4` as object id;
- `created_at` as object creation time;
- `updated_at` as object last update time;
- `is_deleted` as indicator that object is deleted or not;
Models that inherited from `django_sweet_utils.db.models.Model` can be filtered with simple `existing()` property:
```
from django_sweet_utils.db.models import Model
class MyModel(Model):
...
queryset = MyModel.objects.existing()
```
This returns queryset filtered by `is_deleted=False`
Also, now you don't need to catch `DoesNotExist` error when attempting to get some object while it does not exist.
Just use `get_or_none()` instead of `get()` and query returns `None` if there is no object.
## Features
### Models
#### Fake deletion
You can delete your objects without actual database deletion.
Just use `delete()` method on your model instance and it will be marked as deleted with `is_deleted=True`:
To perform actual deletion use `hard_delete()` method instead.
#### UUID4 as object id
Every model instance has `uuid4` field as object id.
#### Created and updated time
Every model instance has `created_at` and `updated_at` fields as object creation and last update time.
#### Existing objects
You can get only existing objects with `existing()` property on your model manager.
```python
queryset = MyModel.objects.existing()
```
#### Get or none
You can get object or `None` if it does not exist with `get_or_none()` method on your model manager.
```python
obj = MyModel.objects.get_or_none(pk=1)
```
### API
#### Views
Inherit your DRF API views from `django_sweet_utils.api.views`:
```
from django_sweet_utils.api.views import UpdateAPIView, DestroyAPIView
class MyUpdateView(UpdateAPIView):
...
class MyDestroyView(DestroyAPIView):
...
```
#### Pagination
There is `PageNumberPagination` class that adds `page_size` query parameter to `PageNumberPagination` class.
```python
REST_FRAMEWORK = {
...
'DEFAULT_PAGINATION_CLASS': 'django_sweet_utils.api.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
...
}
```
From now your views supports `POST` request method instead of `PATCH` and `DELETE`
DestroyAPIView does not perform actual database deletion, but only marks file as deleted with `is_deleted=True`
### Permissions
#### There is `DjangoModelPermissions` class that adds `view` permission to `DjangoModelPermissions` class on `GET` request method.
### Admin
Hard deletion action for admin panel.
```python
from django_sweet_utils.admin import hard_delete_selected
class MyModelAdmin(admin.ModelAdmin):
actions = [hard_delete_selected]
```
### Seriliazers
#### Prettier choice field
You can use custom `ChoiceField` instead of `ChoiceField` from `rest_framework` to get prettier choices representation in API.
```python
from django_sweet_utils.api.serializers import ChoiceField
class MySerializer(serializers.ModelSerializer):
my_field = ChoiceField(choices=MY_CHOICES)
```
#### Prettier multiple choice field
You can use custom `MultipleChoiceField` instead of `MultipleChoiceField` from `rest_framework` to get prettier choices representation in API.
```python
from django_sweet_utils.api.serializers import MultipleChoiceField
class MySerializer(serializers.ModelSerializer):
my_field = MultipleChoiceField(choices=MY_CHOICES)
```
### Template tags
#### `format_string` template tag
You can use `format_string` template tag to format string with arguments.
```html
{% load django_sweet_utils %}
{{ "Hello, {0}!".format_string("World") }}
```
#### `set_query_string_param` template tag
You can use `set_query_string_param` template tag to set query string parameter.
```html
{% load django_sweet_utils %}
{% set_query_string_param "page" 1 %}
```
More info about this tag you can find [here](django_sweet_utils/templatetags/query_string.py).
### Logging
#### Customised JSON formatter
There is `CustomisedJSONFormatter` class that formats log records as JSON.
```python
from django_sweet_utils.logging import CustomisedJSONFormatter
APP_LABEL = "my_app"
ENVIRONMENT = "production"
formatter = CustomisedJSONFormatter()
```
#### Customised JSON handler
There is `CustomHandler` class that handles log records as JSON.
```python
from django_sweet_utils.logging import CustomHandler
handler = CustomHandler()
```
### Misc
#### Custom JSON encoder
You can use `LazyEncoder` to serialize lazy objects to JSON.
```python
from django_sweet_utils.misc import LazyEncoder
json.dumps({"lazy": lazy_object}, cls=LazyEncoder)
```
Raw data
{
"_id": null,
"home_page": "https://github.com/AllYouZombies/django-sweet-utils",
"name": "django-sweet-utils",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "",
"keywords": "",
"author": "Astafeev Rustam",
"author_email": "rustam@astafeev.dev",
"download_url": "https://files.pythonhosted.org/packages/e4/66/6667c1fa156add7c1bb9d49a4175be663469a2060a301490fc5c116b77ab/django-sweet-utils-1.5.0.tar.gz",
"platform": null,
"description": "# Django sweet utils.\n\n[![Downloads](https://static.pepy.tech/personalized-badge/django-sweet-utils?period=total&units=international_system&left_color=black&right_color=orange&left_text=Downloads)](https://pepy.tech/project/django-sweet-utils)\n \nA little django code sugar.\n \n> If you find this package useful, please star it on [GitHub](https://github.com/AllYouZombies/django-sweet-utils).\n \n## Quickstart\n\n1. Add `django_sweet_utils` to your `INSTALLED_APPS` setting like this:\n ```\n INSTALLED_APPS = [\n ...\n 'django_sweet_utils',\n ...\n ]\n ```\n\n2. Inherit your models from `django_sweet_utils.db.models.Model`:\n ```\n from django_sweet_utils.db.models import Model\n \n \n class MyModel(Model):\n ...\n ```\n \n From now your models has the following fields:\n - `uuid4` as object id;\n - `created_at` as object creation time;\n - `updated_at` as object last update time;\n - `is_deleted` as indicator that object is deleted or not; \n \n \n Models that inherited from `django_sweet_utils.db.models.Model` can be filtered with simple `existing()` property:\n ```\n from django_sweet_utils.db.models import Model\n \n \n class MyModel(Model):\n ...\n \n \n queryset = MyModel.objects.existing()\n ```\n This returns queryset filtered by `is_deleted=False`\n\n Also, now you don't need to catch `DoesNotExist` error when attempting to get some object while it does not exist.\n Just use `get_or_none()` instead of `get()` and query returns `None` if there is no object.\n\n\n## Features\n\n### Models\n\n#### Fake deletion\n\nYou can delete your objects without actual database deletion.\nJust use `delete()` method on your model instance and it will be marked as deleted with `is_deleted=True`:\n\nTo perform actual deletion use `hard_delete()` method instead.\n\n#### UUID4 as object id\n\nEvery model instance has `uuid4` field as object id.\n\n#### Created and updated time\n\nEvery model instance has `created_at` and `updated_at` fields as object creation and last update time.\n\n#### Existing objects\n\nYou can get only existing objects with `existing()` property on your model manager.\n\n```python\nqueryset = MyModel.objects.existing()\n```\n\n#### Get or none\n\nYou can get object or `None` if it does not exist with `get_or_none()` method on your model manager.\n\n```python\nobj = MyModel.objects.get_or_none(pk=1)\n```\n\n### API\n\n#### Views\n\nInherit your DRF API views from `django_sweet_utils.api.views`: \n \n```\nfrom django_sweet_utils.api.views import UpdateAPIView, DestroyAPIView\n\n\nclass MyUpdateView(UpdateAPIView):\n ...\n\n\nclass MyDestroyView(DestroyAPIView):\n ...\n```\n \n#### Pagination\n\nThere is `PageNumberPagination` class that adds `page_size` query parameter to `PageNumberPagination` class. \n \n```python\nREST_FRAMEWORK = {\n ...\n 'DEFAULT_PAGINATION_CLASS': 'django_sweet_utils.api.pagination.PageNumberPagination',\n 'PAGE_SIZE': 10,\n ...\n}\n```\n \nFrom now your views supports `POST` request method instead of `PATCH` and `DELETE`\nDestroyAPIView does not perform actual database deletion, but only marks file as deleted with `is_deleted=True`\n \n### Permissions\n\n#### There is `DjangoModelPermissions` class that adds `view` permission to `DjangoModelPermissions` class on `GET` request method.\n\n### Admin\n\nHard deletion action for admin panel.\n\n```python\nfrom django_sweet_utils.admin import hard_delete_selected\n\nclass MyModelAdmin(admin.ModelAdmin):\n actions = [hard_delete_selected]\n```\n\n### Seriliazers\n\n#### Prettier choice field\n\nYou can use custom `ChoiceField` instead of `ChoiceField` from `rest_framework` to get prettier choices representation in API.\n\n```python\nfrom django_sweet_utils.api.serializers import ChoiceField\n\nclass MySerializer(serializers.ModelSerializer):\n my_field = ChoiceField(choices=MY_CHOICES)\n```\n\n#### Prettier multiple choice field\n\nYou can use custom `MultipleChoiceField` instead of `MultipleChoiceField` from `rest_framework` to get prettier choices representation in API.\n\n```python\nfrom django_sweet_utils.api.serializers import MultipleChoiceField\n\nclass MySerializer(serializers.ModelSerializer):\n my_field = MultipleChoiceField(choices=MY_CHOICES)\n```\n\n### Template tags\n\n#### `format_string` template tag\n\nYou can use `format_string` template tag to format string with arguments.\n\n```html\n{% load django_sweet_utils %}\n\n{{ \"Hello, {0}!\".format_string(\"World\") }}\n```\n\n#### `set_query_string_param` template tag\n\nYou can use `set_query_string_param` template tag to set query string parameter.\n\n```html\n{% load django_sweet_utils %}\n\n{% set_query_string_param \"page\" 1 %}\n```\n\nMore info about this tag you can find [here](django_sweet_utils/templatetags/query_string.py).\n\n\n### Logging\n\n#### Customised JSON formatter\n\nThere is `CustomisedJSONFormatter` class that formats log records as JSON.\n\n```python\nfrom django_sweet_utils.logging import CustomisedJSONFormatter\n\nAPP_LABEL = \"my_app\"\nENVIRONMENT = \"production\"\n\nformatter = CustomisedJSONFormatter()\n```\n\n#### Customised JSON handler\n\nThere is `CustomHandler` class that handles log records as JSON.\n\n```python\nfrom django_sweet_utils.logging import CustomHandler\n\nhandler = CustomHandler()\n```\n\n\n### Misc\n\n#### Custom JSON encoder\n\nYou can use `LazyEncoder` to serialize lazy objects to JSON.\n\n```python\nfrom django_sweet_utils.misc import LazyEncoder\n\njson.dumps({\"lazy\": lazy_object}, cls=LazyEncoder)\n```\n\n",
"bugtrack_url": null,
"license": "MIT License",
"summary": "A little django code sugar.",
"version": "1.5.0",
"project_urls": {
"Homepage": "https://github.com/AllYouZombies/django-sweet-utils"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "9de82562a4df30a4444d45572f8bc53cb7bcb1e15c534a8420941dadc95df56f",
"md5": "f6e262cab748a95fea9d9290ad7286cb",
"sha256": "42beace9fef6bc47f91f5615cba0bb33b953e11c2cd489a7118e1f6157d84aeb"
},
"downloads": -1,
"filename": "django_sweet_utils-1.5.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "f6e262cab748a95fea9d9290ad7286cb",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 12674,
"upload_time": "2023-06-15T06:48:13",
"upload_time_iso_8601": "2023-06-15T06:48:13.429237Z",
"url": "https://files.pythonhosted.org/packages/9d/e8/2562a4df30a4444d45572f8bc53cb7bcb1e15c534a8420941dadc95df56f/django_sweet_utils-1.5.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "e4666667c1fa156add7c1bb9d49a4175be663469a2060a301490fc5c116b77ab",
"md5": "42fd21c1d7daa426384ccb4cac9a906f",
"sha256": "fc8a67ed886e2aaed06c8f2edfbab242f04cf6cd6af2421b73f11ea8a7eabfb2"
},
"downloads": -1,
"filename": "django-sweet-utils-1.5.0.tar.gz",
"has_sig": false,
"md5_digest": "42fd21c1d7daa426384ccb4cac9a906f",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 11569,
"upload_time": "2023-06-15T06:48:15",
"upload_time_iso_8601": "2023-06-15T06:48:15.281147Z",
"url": "https://files.pythonhosted.org/packages/e4/66/6667c1fa156add7c1bb9d49a4175be663469a2060a301490fc5c116b77ab/django-sweet-utils-1.5.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-06-15 06:48:15",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "AllYouZombies",
"github_project": "django-sweet-utils",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [],
"lcname": "django-sweet-utils"
}