================
django-seriously
================
|build-status| |pypi-version|
... wait what? no seriously, why isn't that part of Django/DRF?
Opinionated collection of `Django`_ and `Django REST framework`_ tools that came in handy time and again.
- ``AdminItemAction``
- Allow triggering context-aware custom admin operations in model list views.
- ``admin_navigation_link``
- Allow navigation from the admin list view to other related models via links.
- ``MinimalUser`` (abstract model)
- Bare minimum user model ready for customization.
- Removes the username and auxiliary fields like ``first_name`` and ``last_name``.
- Allow creating users without a valid password (unusable password)
- Abstract since its highly recommended to subclass the user model anyway.
- ``ValidatedJSONField`` (model field)
- validate the structure of JSON fields with Pydantic models.
- ``TokenAuthentication``
- When OAuth2 adds too much complexity, DRF's TokenAuthentication is too simple, and
`django-rest-knox`_ does not quite fit the permissioning.
- No plain passwords in database (PBKDF2, i.e. hashed and salted)
- Enabled for permission scoping
- Easy (one-time-view) token creation in Django admin
- ``BaseModel`` (abstract model)
- Reusable base model with automatic ``created_at``, ``updated_at`` fields.
- Primary key is a random UUID (``uuid4``).
- Ensure validation logic (``full_clean()``) always runs, not just in a subset of cases.
- ``AppSettings``
- A settings container with defaults and string importing inspired by DRF's ``APISettings``
License
-------
Provided by `T. Franzel <https://github.com/tfranzel>`_, `Licensed under 3-Clause BSD <https://github.com/tfranzel/django-seriously/blob/master/LICENSE>`_.
Requirements
------------
- Python >= 3.6
- Django >= 3.0
- Django REST Framework (optional)
Installation
------------
.. code:: bash
$ pip install django-seriously
Demo
----
Showcasing ``AdminItemAction``, ``admin_navigation_link``, ``MinimalUser`` and ``TokenAuthentication``
.. image:: https://github.com/tfranzel/django-seriously/blob/master/docs/demo.gif
Usage
-----
``AdminItemAction``
===================
.. code:: python
# admin.py
from django_seriously.utils.admin import AdminItemAction
class UserAdminAction(AdminItemAction[User]):
model_cls = User
actions = [
("reset_invitation", "Reset Invitation"),
]
@classmethod
def is_actionable(cls, obj: User, action: str) -> bool:
# check whether action should be shown for this item
if action == "reset_invitation":
return is_user_resettable_check(obj) # your code
return False
def perform_action(self, obj: User, action: str) -> Any:
# perform the action on the item
if action == "reset_invitation":
perform_your_resetting(obj) # your code
obj.save()
@admin.register(User)
class UserAdmin(ModelAdmin):
# insert item actions into a list view column
list_display = (..., "admin_actions")
def admin_actions(self, obj: User):
return UserAdminAction.action_markup(obj)
.. code:: python
# urls.py
from django_seriously.utils.admin import AdminItemAction
urlpatterns = [
...
# item actions must precede regular admin endpoints
path("admin/", AdminItemAction.urls()),
path("admin/", admin.site.urls),
]
``admin_navigation_link``
=========================
.. code:: python
# admin.py
from django_seriously.utils.admin import admin_navigation_link
@admin.register(Article)
class ArticleAdmin(ModelAdmin):
# insert item actions into a list view column
list_display = ('id', "name", "author_link")
def author_link(self, obj: Article):
return admin_navigation_link(obj.author, obj.author.name)
``TokenAuthentication``
=======================
.. code:: python
# settings.py
INSTALLED_APPS = [
...
# only required if auth token is not extended by you
'django_seriously.authtoken',
...
]
SERIOUSLY_SETTINGS = {
"AUTH_TOKEN_SCOPES": ["test-scope", "test-scope2"]
}
# views.py
from django_seriously.authtoken.authentication import TokenAuthentication, TokenHasScope
class TestViewSet(viewsets.ModelViewSet):
...
permission_classes = [TokenHasScope]
authentication_classes = [TokenAuthentication]
required_scopes = ['test-scope']
``MinimalUser``
===============
.. code:: python
# models.py
from django_seriously.minimaluser.models import MinimalAbstractUser
from django_seriously.utils.models import BaseModel
# BaseModel is optional but adds useful uuid, created_at, updated_at
class User(BaseModel, MinimalAbstractUser):
pass
# admin.py
from django_seriously.minimaluser.admin import MinimalUserAdmin
@admin.register(User)
class UserAdmin(MinimalUserAdmin):
pass
.. _Django: https://www.djangoproject.com/
.. _Django REST framework: https://www.django-rest-framework.org/
.. _django-rest-knox: https://github.com/James1345/django-rest-knox
.. |pypi-version| image:: https://img.shields.io/pypi/v/django-seriously.svg
:target: https://pypi.python.org/pypi/django-seriously
.. |build-status| image:: https://github.com/tfranzel/django-seriously/actions/workflows/ci.yml/badge.svg
:target: https://github.com/tfranzel/django-seriously/actions/workflows/ci.yml
Raw data
{
"_id": null,
"home_page": "https://github.com/tfranzel/django-seriously",
"name": "django-seriously",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "",
"keywords": "",
"author": "T. Franzel",
"author_email": "tfranzel@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/2d/42/cbf5c950932da755667cb348e7f7881ac86660256a34f0b13de53c97769f/django-seriously-0.4.3.tar.gz",
"platform": null,
"description": "================\ndjango-seriously\n================\n\n|build-status| |pypi-version|\n\n ... wait what? no seriously, why isn't that part of Django/DRF?\n\nOpinionated collection of `Django`_ and `Django REST framework`_ tools that came in handy time and again.\n\n- ``AdminItemAction``\n - Allow triggering context-aware custom admin operations in model list views.\n\n- ``admin_navigation_link``\n - Allow navigation from the admin list view to other related models via links.\n\n- ``MinimalUser`` (abstract model)\n - Bare minimum user model ready for customization.\n - Removes the username and auxiliary fields like ``first_name`` and ``last_name``.\n - Allow creating users without a valid password (unusable password)\n - Abstract since its highly recommended to subclass the user model anyway.\n\n- ``ValidatedJSONField`` (model field)\n - validate the structure of JSON fields with Pydantic models.\n\n- ``TokenAuthentication``\n - When OAuth2 adds too much complexity, DRF's TokenAuthentication is too simple, and\n `django-rest-knox`_ does not quite fit the permissioning.\n - No plain passwords in database (PBKDF2, i.e. hashed and salted)\n - Enabled for permission scoping\n - Easy (one-time-view) token creation in Django admin\n\n- ``BaseModel`` (abstract model)\n - Reusable base model with automatic ``created_at``, ``updated_at`` fields.\n - Primary key is a random UUID (``uuid4``).\n - Ensure validation logic (``full_clean()``) always runs, not just in a subset of cases.\n\n- ``AppSettings``\n - A settings container with defaults and string importing inspired by DRF's ``APISettings``\n\n\nLicense\n-------\n\nProvided by `T. Franzel <https://github.com/tfranzel>`_, `Licensed under 3-Clause BSD <https://github.com/tfranzel/django-seriously/blob/master/LICENSE>`_.\n\nRequirements\n------------\n\n- Python >= 3.6\n- Django >= 3.0\n- Django REST Framework (optional)\n\nInstallation\n------------\n\n.. code:: bash\n\n $ pip install django-seriously\n\n\nDemo\n----\n\nShowcasing ``AdminItemAction``, ``admin_navigation_link``, ``MinimalUser`` and ``TokenAuthentication``\n\n.. image:: https://github.com/tfranzel/django-seriously/blob/master/docs/demo.gif\n\nUsage\n-----\n\n``AdminItemAction``\n===================\n\n.. code:: python\n\n # admin.py\n from django_seriously.utils.admin import AdminItemAction\n\n\n class UserAdminAction(AdminItemAction[User]):\n model_cls = User\n actions = [\n (\"reset_invitation\", \"Reset Invitation\"),\n ]\n\n @classmethod\n def is_actionable(cls, obj: User, action: str) -> bool:\n # check whether action should be shown for this item\n if action == \"reset_invitation\":\n return is_user_resettable_check(obj) # your code\n return False\n\n def perform_action(self, obj: User, action: str) -> Any:\n # perform the action on the item\n if action == \"reset_invitation\":\n perform_your_resetting(obj) # your code\n obj.save()\n\n\n @admin.register(User)\n class UserAdmin(ModelAdmin):\n # insert item actions into a list view column\n list_display = (..., \"admin_actions\")\n\n def admin_actions(self, obj: User):\n return UserAdminAction.action_markup(obj)\n\n.. code:: python\n\n # urls.py\n from django_seriously.utils.admin import AdminItemAction\n\n urlpatterns = [\n ...\n # item actions must precede regular admin endpoints\n path(\"admin/\", AdminItemAction.urls()),\n path(\"admin/\", admin.site.urls),\n ]\n\n\n``admin_navigation_link``\n=========================\n\n.. code:: python\n\n # admin.py\n from django_seriously.utils.admin import admin_navigation_link\n\n @admin.register(Article)\n class ArticleAdmin(ModelAdmin):\n # insert item actions into a list view column\n list_display = ('id', \"name\", \"author_link\")\n\n def author_link(self, obj: Article):\n return admin_navigation_link(obj.author, obj.author.name)\n\n\n``TokenAuthentication``\n=======================\n\n.. code:: python\n\n # settings.py\n INSTALLED_APPS = [\n ...\n # only required if auth token is not extended by you\n 'django_seriously.authtoken',\n ...\n ]\n\n SERIOUSLY_SETTINGS = {\n \"AUTH_TOKEN_SCOPES\": [\"test-scope\", \"test-scope2\"]\n }\n\n # views.py\n from django_seriously.authtoken.authentication import TokenAuthentication, TokenHasScope\n\n class TestViewSet(viewsets.ModelViewSet):\n ...\n permission_classes = [TokenHasScope]\n authentication_classes = [TokenAuthentication]\n required_scopes = ['test-scope']\n\n\n``MinimalUser``\n===============\n\n.. code:: python\n\n # models.py\n from django_seriously.minimaluser.models import MinimalAbstractUser\n from django_seriously.utils.models import BaseModel\n\n # BaseModel is optional but adds useful uuid, created_at, updated_at\n class User(BaseModel, MinimalAbstractUser):\n pass\n\n # admin.py\n from django_seriously.minimaluser.admin import MinimalUserAdmin\n\n @admin.register(User)\n class UserAdmin(MinimalUserAdmin):\n pass\n\n\n.. _Django: https://www.djangoproject.com/\n.. _Django REST framework: https://www.django-rest-framework.org/\n.. _django-rest-knox: https://github.com/James1345/django-rest-knox\n\n.. |pypi-version| image:: https://img.shields.io/pypi/v/django-seriously.svg\n :target: https://pypi.python.org/pypi/django-seriously\n.. |build-status| image:: https://github.com/tfranzel/django-seriously/actions/workflows/ci.yml/badge.svg\n :target: https://github.com/tfranzel/django-seriously/actions/workflows/ci.yml\n",
"bugtrack_url": null,
"license": "BSD",
"summary": "Opinionated collection of Django and DRF tools that came in handy time and again.",
"version": "0.4.3",
"project_urls": {
"Homepage": "https://github.com/tfranzel/django-seriously",
"Source": "https://github.com/tfranzel/django-seriously"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "fe24d014f274253db0fa6cd8b27883f8e2edc3f6ae8e0e6d93b9b1b613752dd2",
"md5": "e498733f5aef62f7eda231009a6932be",
"sha256": "771f88a24f6166bdb3a944769fa09e24c317ea1b8f5ee8040d121d30b4395219"
},
"downloads": -1,
"filename": "django_seriously-0.4.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "e498733f5aef62f7eda231009a6932be",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 21741,
"upload_time": "2023-08-19T23:48:17",
"upload_time_iso_8601": "2023-08-19T23:48:17.365720Z",
"url": "https://files.pythonhosted.org/packages/fe/24/d014f274253db0fa6cd8b27883f8e2edc3f6ae8e0e6d93b9b1b613752dd2/django_seriously-0.4.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "2d42cbf5c950932da755667cb348e7f7881ac86660256a34f0b13de53c97769f",
"md5": "d72dde1249a78c237b47414ca83e51d9",
"sha256": "591a2be6e18c229117e0196d9c8e6bd600f5c52f9eebe868e709c71acb53ef58"
},
"downloads": -1,
"filename": "django-seriously-0.4.3.tar.gz",
"has_sig": false,
"md5_digest": "d72dde1249a78c237b47414ca83e51d9",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 22111,
"upload_time": "2023-08-19T23:48:19",
"upload_time_iso_8601": "2023-08-19T23:48:19.092598Z",
"url": "https://files.pythonhosted.org/packages/2d/42/cbf5c950932da755667cb348e7f7881ac86660256a34f0b13de53c97769f/django-seriously-0.4.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-08-19 23:48:19",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "tfranzel",
"github_project": "django-seriously",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"tox": true,
"lcname": "django-seriously"
}