diff --git a/sqladmin/application.py b/sqladmin/application.py index b774241a..489d8d73 100644 --- a/sqladmin/application.py +++ b/sqladmin/application.py @@ -293,16 +293,50 @@ async def _details(self, request: Request) -> None: if not model_view.can_view_details or not model_view.is_accessible(request): raise HTTPException(status_code=403) + if hasattr(model_view, "check_can_view_details"): + pk = request.path_params.get("pk") + assert pk is not None and isinstance( + pk, str + ), f'pk not found in request.path_params "{request.path_params}"' + model = await model_view.get_object_for_details(pk) + can_view_details_row = await model_view.check_can_view_details( + request, model + ) + if can_view_details_row is not True: + raise HTTPException(status_code=403) + async def _delete(self, request: Request) -> None: model_view = self._find_model_view(request.path_params["identity"]) + if not model_view.can_delete or not model_view.is_accessible(request): raise HTTPException(status_code=403) + if hasattr(model_view, "check_can_delete"): + pks = request.query_params.get("pks") + assert pks is not None and isinstance( + pks, str + ), f'pks not found in request.query_params "{request.query_params}"' + for pk in pks.split(","): + model = await model_view.get_object_for_details(pk) + can_delete_row = await model_view.check_can_delete(request, model) + if can_delete_row is not True: + raise HTTPException(status_code=403) + async def _edit(self, request: Request) -> None: model_view = self._find_model_view(request.path_params["identity"]) if not model_view.can_edit or not model_view.is_accessible(request): raise HTTPException(status_code=403) + if hasattr(model_view, "check_can_edit"): + pk = request.path_params.get("pk") + assert pk is not None and isinstance( + pk, str + ), f'pk not found in request.path_params "{request.path_params}"' + model = await model_view.get_object_for_details(pk) + can_edit_row = await model_view.check_can_edit(request, model) + if can_edit_row is not True: + raise HTTPException(status_code=403) + async def _export(self, request: Request) -> None: model_view = self._find_model_view(request.path_params["identity"]) if not model_view.can_export or not model_view.is_accessible(request): diff --git a/sqladmin/models.py b/sqladmin/models.py index 5215ee8e..06676633 100644 --- a/sqladmin/models.py +++ b/sqladmin/models.py @@ -1019,6 +1019,24 @@ async def after_model_delete(self, model: Any, request: Request) -> None: By default do nothing. """ + async def check_can_view_details(self, request: Request, model: Any) -> bool: + """ + You can add a custom model attribute checker before view details. + """ + return self.can_view_details + + async def check_can_edit(self, request: Request, model: Any) -> bool: + """ + You can add a custom model attribute checker before edit. + """ + return self.can_edit + + async def check_can_delete(self, request: Request, model: Any) -> bool: + """ + You can add a custom model attribute checker before delete. + """ + return self.can_delete + async def scaffold_form(self, rules: List[str] | None = None) -> Type[Form]: if self.form is not None: return self.form diff --git a/sqladmin/templates/sqladmin/details.html b/sqladmin/templates/sqladmin/details.html index db7a1c90..2860a05e 100644 --- a/sqladmin/templates/sqladmin/details.html +++ b/sqladmin/templates/sqladmin/details.html @@ -50,7 +50,7 @@

Go Back - {% if model_view.can_delete %} + {% if model_view.check_can_delete(request, model) %}
{% endif %} - {% if model_view.can_edit %} + {% if model_view.check_can_edit(request, model) %}
Edit diff --git a/sqladmin/templates/sqladmin/list.html b/sqladmin/templates/sqladmin/list.html index cbdb0fae..6caadce1 100644 --- a/sqladmin/templates/sqladmin/list.html +++ b/sqladmin/templates/sqladmin/list.html @@ -118,19 +118,19 @@

{{ model_view.name_plural }}

- {% if model_view.can_view_details %} + {% if model_view.check_can_view_details(request, row) %}
{% endif %} - {% if model_view.can_edit %} + {% if model_view.check_can_edit(request, row) %} {% endif %} - {% if model_view.can_delete %} + {% if model_view.check_can_delete(request, row) %}