fastapi-admin-kit 0.1.1__tar.gz → 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/PKG-INFO +1 -1
  2. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/__init__.py +1 -1
  3. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/roles.py +1 -1
  4. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/search.py +3 -2
  5. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/csrf.py +3 -2
  6. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/views.py +6 -3
  7. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/form/pipeline.py +20 -3
  8. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/inspection/__init__.py +28 -0
  9. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/router.py +8 -4
  10. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/js/admin.js +1 -1
  11. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/base.html +3 -0
  12. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/class_views.py +4 -2
  13. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/factory.py +8 -4
  14. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/profile.py +8 -2
  15. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/renderers.py +2 -1
  16. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/roles.py +60 -31
  17. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/totp.py +4 -1
  18. fastapi_admin_kit-0.1.1/test_debug.db-journal +0 -0
  19. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/.gitignore +0 -0
  20. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/LICENSE +0 -0
  21. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/README.md +0 -0
  22. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/actions/__init__.py +0 -0
  23. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/actions/base.py +0 -0
  24. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/actions/registry.py +0 -0
  25. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/__init__.py +0 -0
  26. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/admin_config.py +0 -0
  27. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/admin_database.py +0 -0
  28. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/admin_router.py +0 -0
  29. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/admin_template.py +0 -0
  30. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/builtin_models.py +0 -0
  31. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/core.py +0 -0
  32. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/decorators.py +0 -0
  33. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/state.py +0 -0
  34. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin.py +0 -0
  35. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/__init__.py +0 -0
  36. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/auth.py +0 -0
  37. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/crud.py +0 -0
  38. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/deps.py +0 -0
  39. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/schema_generator.py +0 -0
  40. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/schemas.py +0 -0
  41. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/__init__.py +0 -0
  42. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/context.py +0 -0
  43. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/diff.py +0 -0
  44. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/event_bus.py +0 -0
  45. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/events.py +0 -0
  46. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/listener.py +0 -0
  47. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/logger.py +0 -0
  48. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/middleware.py +0 -0
  49. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/models.py +0 -0
  50. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/sqlalchemy_logger.py +0 -0
  51. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/__init__.py +0 -0
  52. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/backend.py +0 -0
  53. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/dependencies.py +0 -0
  54. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/identity.py +0 -0
  55. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/models.py +0 -0
  56. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/password.py +0 -0
  57. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/permissions.py +0 -0
  58. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/protocol.py +0 -0
  59. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/ratelimit.py +0 -0
  60. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/router.py +0 -0
  61. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/session.py +0 -0
  62. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/totp.py +0 -0
  63. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/cli/__init__.py +0 -0
  64. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/cli/__main__.py +0 -0
  65. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/cli/scaffold.py +0 -0
  66. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/cli/user.py +0 -0
  67. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/__init__.py +0 -0
  68. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/audit.py +0 -0
  69. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/auth.py +0 -0
  70. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/behavior.py +0 -0
  71. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/database.py +0 -0
  72. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/nav.py +0 -0
  73. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/storage.py +0 -0
  74. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/theme.py +0 -0
  75. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/ui.py +0 -0
  76. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/dashboard/__init__.py +0 -0
  77. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/db.py +0 -0
  78. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/exceptions.py +0 -0
  79. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/field_types.py +0 -0
  80. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/filters/__init__.py +0 -0
  81. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/filters/base.py +0 -0
  82. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/filters/registry.py +0 -0
  83. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/flash.py +0 -0
  84. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/form/__init__.py +0 -0
  85. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/inspection/registry.py +0 -0
  86. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/inspection.py +0 -0
  87. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/modeladmin.py +0 -0
  88. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/models/__init__.py +0 -0
  89. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/models/base.py +0 -0
  90. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/nav.py +0 -0
  91. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/pagination/__init__.py +0 -0
  92. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/pagination/base.py +0 -0
  93. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/pagination/cursor.py +0 -0
  94. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/pagination/dynamic.py +0 -0
  95. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/pagination/offset.py +0 -0
  96. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/plugins/__init__.py +0 -0
  97. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/py.typed +0 -0
  98. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/registry/__init__.py +0 -0
  99. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/registry/core.py +0 -0
  100. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/registry/validation.py +0 -0
  101. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/registry.py +0 -0
  102. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/css/admin.css +0 -0
  103. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/css/presets.css +0 -0
  104. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/css/tokens.css +0 -0
  105. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/css/variables.css +0 -0
  106. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/icons/heroicons.svg +0 -0
  107. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/js/htmx-config.js +0 -0
  108. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/storage/__init__.py +0 -0
  109. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/storage/base.py +0 -0
  110. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/storage/local.py +0 -0
  111. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/macros/form_fields.html +0 -0
  112. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/macros/icons.html +0 -0
  113. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/macros/table.html +0 -0
  114. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/macros/widgets.html +0 -0
  115. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/2fa/setup.html +0 -0
  116. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/2fa/verify.html +0 -0
  117. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/audit_detail.html +0 -0
  118. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/audit_log.html +0 -0
  119. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/dashboard.html +0 -0
  120. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/detail.html +0 -0
  121. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/form.html +0 -0
  122. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/list.html +0 -0
  123. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/login.html +0 -0
  124. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/profile/password.html +0 -0
  125. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/profile/profile.html +0 -0
  126. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/role_form.html +0 -0
  127. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/roles/form.html +0 -0
  128. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/roles/list.html +0 -0
  129. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/roles.html +0 -0
  130. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/settings/theme.html +0 -0
  131. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/users/form.html +0 -0
  132. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/users/list.html +0 -0
  133. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/_inline_edit_row.html +0 -0
  134. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/command_palette.html +0 -0
  135. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/field_wrapper.html +0 -0
  136. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/flash_messages.html +0 -0
  137. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/head.html +0 -0
  138. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/head_minimal.html +0 -0
  139. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/inline_edit_form.html +0 -0
  140. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/list_table.html +0 -0
  141. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/mobile_backdrop.html +0 -0
  142. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/pagination.html +0 -0
  143. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/permission_widget.html +0 -0
  144. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/scripts.html +0 -0
  145. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/sidebar.html +0 -0
  146. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/topbar.html +0 -0
  147. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/types.py +0 -0
  148. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/validation.py +0 -0
  149. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/__init__.py +0 -0
  150. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/audit.py +0 -0
  151. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/bulk.py +0 -0
  152. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/context.py +0 -0
  153. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/dashboard.py +0 -0
  154. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/delete.py +0 -0
  155. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/extra.py +0 -0
  156. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/form.py +0 -0
  157. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/list.py +0 -0
  158. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/protocols.py +0 -0
  159. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/search.py +0 -0
  160. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/settings.py +0 -0
  161. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/sidebar.py +0 -0
  162. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/users.py +0 -0
  163. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views.py +0 -0
  164. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/__init__.py +0 -0
  165. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/base.py +0 -0
  166. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/inputs.py +0 -0
  167. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/registry.py +0 -0
  168. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/relation.py +0 -0
  169. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/resolver.py +0 -0
  170. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/mkdocs.yml +0 -0
  171. {fastapi_admin_kit-0.1.1 → fastapi_admin_kit-0.1.2}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-admin-kit
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Drop-in admin panel for FastAPI + SQLAlchemy + SQLModel apps
5
5
  Project-URL: Homepage, https://github.com/borhanst/fastapi-admin-kit
6
6
  Project-URL: Documentation, https://borhanst.github.io/fastapi-admin-kit/
@@ -73,4 +73,4 @@ __all__ = [
73
73
  # Per-model assets
74
74
  "AdminExtra",
75
75
  ]
76
- __version__ = "0.1.1"
76
+ __version__ = "0.1.2"
@@ -106,7 +106,7 @@ async def update_role(
106
106
  )
107
107
 
108
108
 
109
- @router.delete("/{role_id}", status_code=204)
109
+ @router.delete("/{role_id}", status_code=204, response_model=None)
110
110
  async def delete_role(
111
111
  request: Request,
112
112
  role_id: int,
@@ -56,6 +56,7 @@ async def get_search_suggestions(
56
56
  if registry is None or not q.strip():
57
57
  return {"suggestions": [], "query": q}
58
58
 
59
+ admin_path = request.app.state.admin_config["admin_path"]
59
60
  query_lower = q.strip().lower()
60
61
  suggestions: list[dict[str, Any]] = []
61
62
 
@@ -79,7 +80,7 @@ async def get_search_suggestions(
79
80
  "model": table_name,
80
81
  "label": verbose_name_plural,
81
82
  "sublabel": table_name,
82
- "url": f"/admin/{table_name}",
83
+ "url": f"{admin_path}/{table_name}",
83
84
  }
84
85
  )
85
86
 
@@ -120,7 +121,7 @@ async def get_search_suggestions(
120
121
  "field": field_name,
121
122
  "label": f"{verbose_name_plural} → {field_label}",
122
123
  "sublabel": f"{table_name}.{field_name}",
123
- "url": f"/admin/{table_name}?q={q}",
124
+ "url": f"{admin_path}/{table_name}?q={q}",
124
125
  }
125
126
  )
126
127
 
@@ -224,9 +224,10 @@ async def auth_redirect_handler(request: Request, exc: HTTPException) -> Respons
224
224
  if exc.status_code == 401:
225
225
  accept = request.headers.get("accept", "")
226
226
  if "text/html" in accept:
227
- login_url = "/admin/login"
227
+ admin_path = request.app.state.admin_config["admin_path"]
228
+ login_url = f"{admin_path}/login"
228
229
  current_path = request.url.path
229
- if current_path != "/admin/login":
230
+ if current_path != f"{admin_path}/login":
230
231
  if request.url.query:
231
232
  login_url += f"?next={current_path}%3F{request.url.query}"
232
233
  else:
@@ -45,7 +45,8 @@ async def login_get(
45
45
  ) -> HTMLResponse:
46
46
  """GET /admin/login — show login page, redirect if already logged in."""
47
47
  if session_payload is not None:
48
- target = next if _is_safe_url(next) else "/admin/"
48
+ admin_path = request.app.state.admin_config["admin_path"]
49
+ target = next if _is_safe_url(next) else f"{admin_path}/"
49
50
  return RedirectResponse(url=target, status_code=status.HTTP_302_FOUND)
50
51
 
51
52
  jinja_env = request.app.state.admin_jinja_env
@@ -90,7 +91,8 @@ async def login_post(
90
91
  if next and _is_safe_url(next):
91
92
  redirect_url = next
92
93
  else:
93
- redirect_url = "/admin/"
94
+ admin_path = request.app.state.admin_config["admin_path"]
95
+ redirect_url = f"{admin_path}/"
94
96
 
95
97
  samesite = getattr(
96
98
  request.app.state.admin_state, "session_samesite", "strict"
@@ -149,7 +151,8 @@ async def logout_post(
149
151
  request.app.state.admin_state, "session_samesite", "strict"
150
152
  )
151
153
  response = RedirectResponse(
152
- url="/admin/login", status_code=status.HTTP_302_FOUND
154
+ url=f"{request.app.state.admin_config['admin_path']}/login",
155
+ status_code=status.HTTP_302_FOUND
153
156
  )
154
157
  response.delete_cookie(
155
158
  key=session_backend.cookie_name,
@@ -27,8 +27,13 @@ def build_form_context(
27
27
  fieldsets: list[FieldsetContext] = [FieldsetContext(fields=[])]
28
28
 
29
29
  for field_meta in registered.form_fields:
30
- col = next((c for c in registered.columns if c.name == field_meta.name), None)
31
- rel = next((r for r in registered.relationships if r.name == field_meta.name), None)
30
+ col = next(
31
+ (c for c in registered.columns if c.name == field_meta.name), None
32
+ )
33
+ rel = next(
34
+ (r for r in registered.relationships if r.name == field_meta.name),
35
+ None,
36
+ )
32
37
  widget = registered.get_widget(field_meta.name)
33
38
 
34
39
  value = values.get(field_meta.name)
@@ -39,6 +44,7 @@ def build_form_context(
39
44
  if value is None and rel is not None:
40
45
  try:
41
46
  from sqlalchemy import inspect as sa_inspect
47
+
42
48
  mapper = sa_inspect(type(obj))
43
49
  rel_prop = mapper.relationships.get(rel.name)
44
50
  if rel_prop is not None:
@@ -62,9 +68,13 @@ def build_form_context(
62
68
  ):
63
69
  try:
64
70
  from sqlalchemy import inspect as sa_inspect
71
+
65
72
  mapper = sa_inspect(type(obj))
66
73
  rel_prop = mapper.relationships.get(rel.name)
67
- if rel_prop is not None and rel_prop.direction.name == "MANYTOMANY":
74
+ if (
75
+ rel_prop is not None
76
+ and rel_prop.direction.name == "MANYTOMANY"
77
+ ):
68
78
  value = [str(item.id) for item in value]
69
79
  except Exception:
70
80
  pass
@@ -74,6 +84,13 @@ def build_form_context(
74
84
  widget_macro = widget.macro_name
75
85
  widget_ctx = widget.render_context(field_meta, value)
76
86
  widget_ctx["is_create"] = is_create
87
+ if request is not None:
88
+ admin_path = request.app.state.admin_config["admin_path"]
89
+ widget_ctx["admin_path"] = admin_path
90
+ if "search_url" in widget_ctx:
91
+ widget_ctx["search_url"] = widget_ctx["search_url"].replace(
92
+ "/admin/", f"{admin_path}/"
93
+ )
77
94
  if obj is not None:
78
95
  widget_ctx["obj_id"] = getattr(obj, "id", "")
79
96
  if rel is not None and rel_labels:
@@ -67,6 +67,34 @@ def get_pk_field(model: type) -> str | None:
67
67
  return tuple(col.key for col in pk_cols)
68
68
 
69
69
 
70
+ def cast_pk_value(model: type, value: Any) -> Any:
71
+ """Cast a string primary key value to the correct Python type.
72
+
73
+ Inspects the model's primary key column type and converts the value
74
+ accordingly. Supports Integer, BigInteger, String, and UUID types.
75
+ Returns the original value if type cannot be determined.
76
+ """
77
+ if value is None:
78
+ return None
79
+ mapper = inspect(model)
80
+ pk_cols = mapper.primary_key
81
+ if not pk_cols or len(pk_cols) != 1:
82
+ return value
83
+ pk_col = pk_cols[0]
84
+ from sqlalchemy import BigInteger, Integer
85
+ from sqlalchemy.dialects.postgresql import UUID as PG_UUID
86
+ from sqlalchemy.types import Uuid
87
+
88
+ col_type = type(pk_col.type)
89
+ if col_type in (Integer, BigInteger):
90
+ return int(value)
91
+ if col_type in (PG_UUID, Uuid):
92
+ from uuid import UUID
93
+
94
+ return UUID(str(value))
95
+ return value
96
+
97
+
70
98
  def auto_label(name: str) -> str:
71
99
  """Auto-generate a human-readable label from a field name.
72
100
 
@@ -150,13 +150,14 @@ def build_model_router(registered: RegisteredModel) -> APIRouter:
150
150
  from sqlalchemy import select
151
151
  from sqlalchemy.orm import selectinload
152
152
 
153
+ from fastapi_admin_kit.inspection import cast_pk_value
153
154
  mapper = sa_inspect(registered.model)
154
155
  options = [
155
156
  selectinload(getattr(registered.model, r.key))
156
157
  for r in mapper.relationships
157
158
  ]
158
159
  stmt = select(registered.model).options(*options).where(
159
- getattr(registered.model, registered.pk_field) == int(id)
160
+ getattr(registered.model, registered.pk_field) == cast_pk_value(registered.model, id)
160
161
  )
161
162
  result = await session.execute(stmt)
162
163
  obj = result.scalar_one_or_none()
@@ -209,13 +210,14 @@ def build_model_router(registered: RegisteredModel) -> APIRouter:
209
210
  from sqlalchemy import select
210
211
  from sqlalchemy.orm import selectinload
211
212
 
213
+ from fastapi_admin_kit.inspection import cast_pk_value
212
214
  mapper = sa_inspect(registered.model)
213
215
  options = [
214
216
  selectinload(getattr(registered.model, r.key))
215
217
  for r in mapper.relationships
216
218
  ]
217
219
  stmt = select(registered.model).options(*options).where(
218
- getattr(registered.model, registered.pk_field) == int(id)
220
+ getattr(registered.model, registered.pk_field) == cast_pk_value(registered.model, id)
219
221
  )
220
222
  result = await session.execute(stmt)
221
223
  obj = result.scalar_one_or_none()
@@ -377,7 +379,8 @@ def build_model_router(registered: RegisteredModel) -> APIRouter:
377
379
  if not action_obj:
378
380
  raise HTTPException(status_code=404, detail=f"Unknown action: {action_name}")
379
381
 
380
- obj = await session.get(registered.model, int(id))
382
+ from fastapi_admin_kit.inspection import cast_pk_value
383
+ obj = await session.get(registered.model, cast_pk_value(registered.model, id))
381
384
  if not obj:
382
385
  raise HTTPException(status_code=404, detail="Not found")
383
386
 
@@ -484,7 +487,8 @@ def build_model_router(registered: RegisteredModel) -> APIRouter:
484
487
 
485
488
  session = get_db_session(request)
486
489
  try:
487
- obj = await session.get(registered.model, int(id))
490
+ from fastapi_admin_kit.inspection import cast_pk_value
491
+ obj = await session.get(registered.model, cast_pk_value(registered.model, id))
488
492
  if obj is None:
489
493
  raise HTTPException(status_code=404, detail="Object not found")
490
494
 
@@ -565,7 +565,7 @@ document.addEventListener('alpine:init', () => {
565
565
  return;
566
566
  }
567
567
  try {
568
- const resp = await fetch(`/admin/search/suggestions?q=${encodeURIComponent(q)}`);
568
+ const resp = await fetch(`${window.__ADMIN_PATH__}/search/suggestions?q=${encodeURIComponent(q)}`);
569
569
  if (resp.ok) {
570
570
  const data = await resp.json();
571
571
  this.results = data.suggestions || [];
@@ -136,6 +136,9 @@
136
136
  <script>{{ _ui2.custom_js }}</script>
137
137
  {% endif %}
138
138
 
139
+ <script>
140
+ window.__ADMIN_PATH__ = {{ admin_path | default('/admin') | tojson }};
141
+ </script>
139
142
  <script src="/static/js/htmx-config.js"></script>
140
143
  <script src="/static/js/admin.js?v={{ static_version }}"></script>
141
144
  </body>
@@ -171,7 +171,8 @@ class BaseView:
171
171
  if not pk:
172
172
  continue
173
173
  try:
174
- loaded = await session.get(target_model, int(pk))
174
+ from fastapi_admin_kit.inspection import cast_pk_value
175
+ loaded = await session.get(target_model, cast_pk_value(target_model, pk))
175
176
  if loaded:
176
177
  objs.append(loaded)
177
178
  except (ValueError, TypeError):
@@ -1021,7 +1022,8 @@ class SearchView(BaseView):
1021
1022
  if exclude_id:
1022
1023
  pk_col = getattr(model, self.registered.pk_field, None)
1023
1024
  if pk_col is not None:
1024
- base = base.where(pk_col != int(exclude_id))
1025
+ from fastapi_admin_kit.inspection import cast_pk_value
1026
+ base = base.where(pk_col != cast_pk_value(model, exclude_id))
1025
1027
 
1026
1028
  base = base.limit(limit)
1027
1029
  result = session.execute(base)
@@ -104,7 +104,8 @@ async def _apply_m2m_from_data(
104
104
  if not pk:
105
105
  continue
106
106
  try:
107
- loaded = await session.get(target_model, int(pk))
107
+ from fastapi_admin_kit.inspection import cast_pk_value
108
+ loaded = await session.get(target_model, cast_pk_value(target_model, pk))
108
109
  if loaded:
109
110
  objs.append(loaded)
110
111
  except (ValueError, TypeError):
@@ -457,7 +458,8 @@ class ViewFactory:
457
458
  async def edit_form(request: Request, id: str, _: Any = None):
458
459
  templates = request.app.state.admin_jinja_env
459
460
  session = get_db_session(request)
460
- obj = await session.get(registered.model, int(id))
461
+ from fastapi_admin_kit.inspection import cast_pk_value
462
+ obj = await session.get(registered.model, cast_pk_value(registered.model, id))
461
463
  if not obj:
462
464
  raise HTTPException(status_code=404, detail="Not found")
463
465
  checker = await _resolve_permission_checker(request)
@@ -483,7 +485,8 @@ class ViewFactory:
483
485
  async def edit_submit(request: Request, id: str, _: Any = None):
484
486
  templates = request.app.state.admin_jinja_env
485
487
  session = get_db_session(request)
486
- obj = await session.get(registered.model, int(id))
488
+ from fastapi_admin_kit.inspection import cast_pk_value
489
+ obj = await session.get(registered.model, cast_pk_value(registered.model, id))
487
490
  if not obj:
488
491
  raise HTTPException(status_code=404, detail="Not found")
489
492
  form_data = await request.form()
@@ -555,7 +558,8 @@ class ViewFactory:
555
558
  await session.rollback()
556
559
  except Exception:
557
560
  pass
558
- obj = await session.get(registered.model, int(id))
561
+ from fastapi_admin_kit.inspection import cast_pk_value
562
+ obj = await session.get(registered.model, cast_pk_value(registered.model, id))
559
563
  if not obj:
560
564
  raise HTTPException(status_code=404, detail="Not found")
561
565
  try:
@@ -104,7 +104,10 @@ async def profile_update(
104
104
  user.full_name = full_name
105
105
  await session.flush()
106
106
 
107
- return RedirectResponse(url="/admin/profile", status_code=302)
107
+ return RedirectResponse(
108
+ url=f"{request.app.state.admin_config['admin_path']}/profile",
109
+ status_code=302,
110
+ )
108
111
 
109
112
 
110
113
  @router.get("/profile/password", response_class=HTMLResponse)
@@ -200,7 +203,10 @@ async def password_change_post(
200
203
  # Clear session and redirect to login
201
204
  from fastapi_admin_kit.auth.csrf import CSRF_COOKIE_NAME
202
205
 
203
- response = RedirectResponse(url="/admin/login", status_code=302)
206
+ response = RedirectResponse(
207
+ url=f"{request.app.state.admin_config['admin_path']}/login",
208
+ status_code=302,
209
+ )
204
210
  session_backend = request.app.state.admin_session_backend
205
211
  samesite = getattr(
206
212
  request.app.state.admin_state, "session_samesite", "strict"
@@ -623,7 +623,8 @@ class DefaultQueryProvider:
623
623
  for rel in mapper.relationships:
624
624
  if rel.direction.name == "MANYTOMANY":
625
625
  options.append(selectinload(getattr(self.registered.model, rel.key)))
626
- int_id = int(id) if id is not None else None
626
+ from fastapi_admin_kit.inspection import cast_pk_value
627
+ int_id = cast_pk_value(self.registered.model, id)
627
628
  if options:
628
629
  from sqlalchemy import select
629
630
  stmt = select(self.registered.model).options(*options).where(
@@ -22,7 +22,9 @@ async def _require_superuser(
22
22
  user: AdminUserProtocol = Depends(get_current_admin_user),
23
23
  ) -> AdminUserProtocol:
24
24
  if not getattr(user, "is_superuser", False):
25
- raise HTTPException(status_code=403, detail="Superuser access required.")
25
+ raise HTTPException(
26
+ status_code=403, detail="Superuser access required."
27
+ )
26
28
  return user
27
29
 
28
30
 
@@ -36,15 +38,13 @@ async def tables_search(
36
38
  registry = request.app.state.admin_registry
37
39
  models = registry.all()
38
40
 
39
- results = [
40
- {"id": m.table_name, "label": m.verbose_name}
41
- for m in models
42
- ]
41
+ results = [{"id": m.table_name, "label": m.verbose_name} for m in models]
43
42
 
44
43
  if q:
45
44
  q_lower = q.lower()
46
45
  results = [
47
- r for r in results
46
+ r
47
+ for r in results
48
48
  if q_lower in r["label"].lower() or q_lower in r["id"].lower()
49
49
  ]
50
50
 
@@ -66,17 +66,22 @@ async def role_list_view(
66
66
  role_data = []
67
67
  for role in roles:
68
68
  user_count = len(role.users)
69
- role_data.append({
70
- "role": role,
71
- "user_count": user_count,
72
- })
69
+ role_data.append(
70
+ {
71
+ "role": role,
72
+ "user_count": user_count,
73
+ }
74
+ )
73
75
 
74
76
  return templates.TemplateResponse(
75
77
  request,
76
78
  "pages/roles.html",
77
- await inject_sidebar_context(request, {
78
- "roles": role_data,
79
- }),
79
+ await inject_sidebar_context(
80
+ request,
81
+ {
82
+ "roles": role_data,
83
+ },
84
+ ),
80
85
  )
81
86
 
82
87
 
@@ -91,11 +96,14 @@ async def role_create_view(
91
96
  return templates.TemplateResponse(
92
97
  request,
93
98
  "pages/role_form.html",
94
- await inject_sidebar_context(request, {
95
- "role": None,
96
- "perm_data": {},
97
- "search_url": "/admin/tables/search",
98
- }),
99
+ await inject_sidebar_context(
100
+ request,
101
+ {
102
+ "role": None,
103
+ "perm_data": {},
104
+ "search_url": f"{request.app.state.admin_config['admin_path']}/tables/search",
105
+ },
106
+ ),
99
107
  )
100
108
 
101
109
 
@@ -118,10 +126,16 @@ async def role_edit_view(
118
126
  model_map = {m.table_name: m.verbose_name for m in models}
119
127
 
120
128
  perms = (
121
- await session.execute(
122
- select(AdminPermission).where(AdminPermission.role_id == role_id)
129
+ (
130
+ await session.execute(
131
+ select(AdminPermission).where(
132
+ AdminPermission.role_id == role_id
133
+ )
134
+ )
123
135
  )
124
- ).scalars().all()
136
+ .scalars()
137
+ .all()
138
+ )
125
139
 
126
140
  perm_data = {}
127
141
  for p in perms:
@@ -136,11 +150,14 @@ async def role_edit_view(
136
150
  return templates.TemplateResponse(
137
151
  request,
138
152
  "pages/role_form.html",
139
- await inject_sidebar_context(request, {
140
- "role": role,
141
- "perm_data": perm_data,
142
- "search_url": "/admin/tables/search",
143
- }),
153
+ await inject_sidebar_context(
154
+ request,
155
+ {
156
+ "role": role,
157
+ "perm_data": perm_data,
158
+ "search_url": f"{request.app.state.admin_config['admin_path']}/tables/search",
159
+ },
160
+ ),
144
161
  )
145
162
 
146
163
 
@@ -167,10 +184,16 @@ async def role_save_view(
167
184
  perm_data = {}
168
185
 
169
186
  existing_perms = (
170
- await session.execute(
171
- select(AdminPermission).where(AdminPermission.role_id == role_id)
187
+ (
188
+ await session.execute(
189
+ select(AdminPermission).where(
190
+ AdminPermission.role_id == role_id
191
+ )
192
+ )
172
193
  )
173
- ).scalars().all()
194
+ .scalars()
195
+ .all()
196
+ )
174
197
  existing_perm_map = {p.table_name: p for p in existing_perms}
175
198
 
176
199
  for table, data in perm_data.items():
@@ -200,7 +223,10 @@ async def role_save_view(
200
223
 
201
224
  await session.flush()
202
225
 
203
- return RedirectResponse(url="/admin/roles", status_code=302)
226
+ return RedirectResponse(
227
+ url=f"{request.app.state.admin_config['admin_path']}/roles",
228
+ status_code=302,
229
+ )
204
230
 
205
231
 
206
232
  @router.post("/roles/{role_id}/delete", response_class=RedirectResponse)
@@ -227,4 +253,7 @@ async def role_delete_view(
227
253
  await session.delete(role)
228
254
  await session.flush()
229
255
 
230
- return RedirectResponse(url="/admin/roles", status_code=302)
256
+ return RedirectResponse(
257
+ url=f"{request.app.state.admin_config['admin_path']}/roles",
258
+ status_code=302,
259
+ )
@@ -189,7 +189,10 @@ async def totp_disable_post(
189
189
  totp_record.backup_codes = None
190
190
  await session.flush()
191
191
 
192
- return RedirectResponse(url="/admin/profile/2fa", status_code=302)
192
+ return RedirectResponse(
193
+ url=f"{request.app.state.admin_config['admin_path']}/profile/2fa",
194
+ status_code=302,
195
+ )
193
196
 
194
197
 
195
198
  @router.post("/profile/2fa/backup-codes")