Skip to content

Permissions ​

This page lists the permission codenames that VUEDA checks and the codename that each request requires. It also lists the Row-Level Permissions hook signatures, the status code for each refused request, and the supported Permission Mapping values. Permission Model describes the Permission Layers and why each refusal takes the form it does. Every check on this page is server enforcement. Authorization vs UI Semantics describes how the client's visible actions relate to server enforcement.

Codenames ​

VUEDA models declare five actions in default_permissions. Importing core.patch_django adds list to every other model whose Meta does not declare its own default_permissions.

Each codename takes the form <app_label>.<action>_<model_name>.

ActionCodename for myapp.WidgetGrants
createmyapp.create_widgetPOST to the list route
readmyapp.read_widgetRetrieve, and GET on any extra action
updatemyapp.update_widgetPUT and PATCH
deletemyapp.delete_widgetSingle-object DELETE and bulk delete
listmyapp.list_widgetGET on the list route (the list action)

The table uses the default mapping. Under Django's names, the codenames change as Permission Name Mapping lists.

Required Codename per Request ​

A permission class maps each request method to a codename. ObjectPermissions is the default class for VUEDA viewsets, and its perms_map holds the mapping.

MethodObjectPermissions, default mappingObjectPermissions, Django's names
GET, HEADlist_ for the list action; read_ for every other actionview_ for every action
POSTcreate_add_
PUT, PATCHupdate_change_
DELETEdelete_delete_
OPTIONSNoneNone

Endpoints that name their model in the URL use DynamicObjectPermissions or its subclass WorkflowObjectPermissions. These are the workflow endpoints that address a model's data and workflow state history. Their crudl_perms_map names an action, which the class resolves through the mapping on each check.

MethodDynamicObjectPermissions action
GET, HEADread
POSTcreate
PUTupdate
PATCHread
DELETEdelete
OPTIONSNone

The field choices and filter choices endpoints check the read codename on the model. When the options are another model's rows, they also check the list codename on that model. Both resolve through the mapping on each check.

Workflow endpoints also check vueda_workflow.read_workflow, except object state and permitted_transitions. Workflow as a Permission Overlay lists the gates that each workflow endpoint applies.

Row-Level Hooks ​

A model opts in by declaring an inner RowLevelPermissions class that subclasses BaseRowLevelPermissions. Each hook is a classmethod, and the base class returns None from all four. Row-Level Permission Filtering describes which requests run each hook, and Permission Model describes the order of the instance hooks among the layers.

Signatures ​

HookSignatureRuns
check_querysetcheck_queryset(cls, queryset, perm, user, perm_type)For list, bulk delete, and Model History events about the model's rows
check_queryset_workflowcheck_queryset_workflow(cls, queryset, perm, user, perm_type, state_denied_annotation, state_granted_annotation)After check_queryset and the State Permission filter, on a Workflow-Enabled Model only
check_instancecheck_instance(cls, model, obj, perm, user, perm_type)In every Object-Scope Check, except when a state rule denied the codename
check_instance_workflowcheck_instance_workflow(cls, model, obj, perm, user, perm_type, grant_or_deny)Last in every object-scope check on a workflow-enabled model, whatever the state rules returned

Arguments ​

ArgumentHooksValue
querysetQueryset hooksThe rows so far. check_queryset_workflow receives them after the state filter, with the two state annotations added.
permAllThe codename being checked, as <app_label>.<codename>, after mapping. Instance hooks also receive the workflow and transition permission codenames that workflow checks test against the object.
userAllThe requesting user.
perm_type (queryset hooks)Queryset hooksThe caller's action name, before mapping: "list" for list, "delete" for bulk delete, "read" for history.
perm_type (instance hooks)Instance hooksThe codename's text before its first underscore, after mapping: read for myapp.read_widget. Under Django's names it is view, add, or change for those actions.
modelInstance hooksThe object's class.
objInstance hooksThe object being checked.
state_denied_annotationcheck_queryset_workflowThe name of a boolean annotation: True when a state rule for the row's current state denies the codename to one of the user's groups.
state_granted_annotationcheck_queryset_workflowThe name of a boolean annotation: True when such a rule grants it.
grant_or_denycheck_instance_workflowThe state rules' result for the object: True (grant), False (deny), or None (no rule matched).

Under the default mapping, the two perm_type values agree. They differ when the mapping renames an action: for list under Django's names, the queryset hooks receive "list" and perm ends in view_<model_name>.

Return Values ​

ReturnQueryset hooksInstance hooks
QFilters the queryset by the condition.Not accepted.
TrueLeaves the queryset unchanged.Grants, replacing the decision of the earlier layers.
FalseReturns an empty queryset. From check_queryset, the state filter and check_queryset_workflow do not run.Denies, replacing the decision of the earlier layers.
NoneLeaves the queryset unchanged.Keeps the decision of the earlier layers.

A check_instance_workflow result is final, a state deny included. check_queryset_workflow can only remove rows, so it cannot restore a row that the state filter removed.

Status Codes ​

The status code that a refused request returns depends on the check that refused it. Permission Model describes why.

RequestRefusalStatusResponse
Any viewset request, including list and createThe Model-Scope Check fails, and no state grant defers it (Model-Scope Deferral)403detail message
listRow filtering removes every row200Empty results, totalRecords of 0
RetrieveThe object check denies read404The same response as a missing object
update, partial_update, single-object DELETEThe object check denies the action, and the user can read the object403detail message
update, partial_update, single-object DELETEThe object check denies the action, and the user cannot read the object404The same response as a missing object
Bulk delete (destroy with pks)A pk is missing, removed by row filtering, or refused by its object check400One error per such pk, keyed by pk: "Object with pk=<pk> does not exist." Nothing is deleted.
Field choices, filter choicesThe user lacks read_ on the model, or list_ on the related model403detail message
Workflow endpoints other than object state and permitted_transitionsThe user lacks vueda_workflow.read_workflow403detail message
Object state, object transitions, single-object execute transition, workflow state historyThe object check denies read403detail message
Bulk execute transitionAn object_ids entry is missing, or the user cannot read it404The same response for both. No transition is applied.
Execute transitionThe user lacks a Workflow Permission or Transition Permission; the transition code is unknown; the transition does not leave the current state; another request holds the row lock400Validation error. A bulk request keys the errors by object id and applies no transition.
permitted_transitionsThe model does not enable class Vueda.Workflow200[], for any user with read_ on the model
permitted_transitionsThe user lacks read_ on the model, vueda_workflow.read_workflow, or the workflow's workflow permissions403detail message
Any workflow checkThe model enables class Vueda.Workflow but has no workflow definition500WorkflowNotConfiguredError message in detail

Workflow as a Permission Overlay describes the transition gates and the workflow endpoint rules.

Permission Name Mapping ​

PERMISSION_NAMES_MAPPING renames permission actions (see Permission Mapping). Map Django and VUEDA Permission Names gives the steps to set it and check the result. VUEDA supports two values. The check_permission_names_mapping system check reports any other value as vueda_core.E018.

The default, from core.default_settings.get_defaults:

python
PERMISSION_NAMES_MAPPING = {
    "add": "create",
    "change": "update",
    "view": "read",
}

Django's names, for a database whose permission rows and group assignments already use add, change, and view:

python
PERMISSION_NAMES_MAPPING = {
    "create": "add",
    "list": "view",
    "read": "view",
    "update": "change",
}
ConsumerReads the mappingFollows
Permission row creation (migrate)When it runsAny key
ObjectPermissions.perms_mapOnce, when patch_django is importedOnly the values add, change, and view, each when it is not also a key. A view value makes every GET require view_, for list and detail alike.
Row-level filtering, DynamicObjectPermissions, choice endpointsWhen each check runsAny key

Map list to view whenever read maps to view. The viewsets then check the same codename as row-level filtering and the choice endpoints. Other mappings, such as "delete": "remove" or "list": "browse", create permission rows that ObjectPermissions never checks.