Metadata-Version: 2.4
Name: django-field-permissions
Version: 1.0.0
Summary: A Django package for implementing field-level permissions on model fields.
Author-email: Eddie Mapes <1999eddiem@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Eddie Mapes
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
Project-URL: Homepage, https://github.com/eddiemapes/django-field-permissions
Classifier: License :: OSI Approved :: MIT License
Classifier: Framework :: Django
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Django>=4.2
Dynamic: license-file

# django-field-permissions

Django's built-in permission system works at the model level — a user can either access a model or they can't. There isn't a built-in way to say "this user can see the `email` field but not edit it" without a custom implementation. **django-field-permissions** fills that gap by adding field-level `read` and `edit` permissions that can be assigned to individual users or groups.

[![PyPI version](https://img.shields.io/pypi/v/django-field-permissions)](https://pypi.org/project/django-field-permissions/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

---

## Overview

django-field-permissions introduces a `FieldPermission` model that maps model fields to an access level (`read` or `edit`) and a set of users and/or groups. A middleware resolves the current user's permissions on every request and attaches them to `request.field_perms`. A template tag and utility function let you check those permissions anywhere in your templates or views.

**Key features:**

- Per-field `read` and `edit` access levels
- Assign permissions to individual users, groups, or both
- Check a user's field permissions in the template or backend
- Superusers automatically pass all permission checks, following Django convention
- Middleware-driven — resolved permissions are available on every request via `request.field_perms`
- Built-in caching with automatic invalidation via Django signals
- Django admin integration for managing permissions through the UI

---

## Installation

```bash
pip install django-field-permissions
```

---

## Quick Start

**1. Add to `INSTALLED_APPS`:**

```python
INSTALLED_APPS = [
    ...
    'field_permissions',
]
```

**2. Add the middleware:**

```python
MIDDLEWARE = [
    ...
    'field_permissions.middleware.FieldPermissionMiddleware',
]
```
Place this after AuthenticationMiddleware.

**3. Declare which models get field permissions:**

```python
# settings.py
FIELD_PERMISSIONS_ALLOWED_MODELS = [
    'myapp.MyModel',
    'otherapp.AnotherModel',
]
```

**4. Run migrations and sync permissions:**

```bash
python manage.py migrate
python manage.py sync_field_permissions
```

This creates one `read` record and one `edit` record in the database for every field on every model listed in `FIELD_PERMISSIONS_ALLOWED_MODELS`.


**5. Assign permissions in the Django admin:**

**Optional — wire up admin mixins to manage permissions from the User or Group admin pages:**

```python
from django.contrib import admin
from django.contrib.auth.models import User, Group
from django.contrib.auth.admin import UserAdmin, GroupAdmin
from field_permissions.admin import FieldPermissionUserAdminMixin, FieldPermissionGroupAdminMixin

class MyUserAdmin(FieldPermissionUserAdminMixin, UserAdmin):
    pass

class MyGroupAdmin(FieldPermissionGroupAdminMixin, GroupAdmin):
    pass

admin.site.unregister(User)
admin.site.unregister(Group)
admin.site.register(User, MyUserAdmin)
admin.site.register(Group, MyGroupAdmin)
```

---

A field permissions **FilteredSelectMultiple** widget is added to the **User** and **Group** edit and create pages in Django admin.

Otherwise permission records can be created via SQL / Django Shell.


**6. Check permissions in templates:**

```django
{% load field_permissions %}

# Format: request|has_field_perm:"model_name,field_name,access_level
# Returns True/False

{% if request|has_field_perm:"mymodel,email,read" %}
    {{ user.email }}
{% endif %}
```


**7. Check permissions in views:**

```python
from field_permissions.permissions import has_field_perm

def my_view(request):
    # Format: has_field_perm(request, 'model_name', 'field_name', 'access_level')
    # Returns True/False

    if has_field_perm(request, 'mymodel', 'email', 'edit'):
        # allow edit
        pass
```


## Configuration

All settings are optional, add any of the following to your `settings.py`:

| Setting | Default | Description |
|---|---|---|
| `FIELD_PERMISSIONS_ALLOWED_MODELS` | `[]` | Models to create field permissions for. Format: `["appname.ModelName"]` |
| `FIELD_PERMISSIONS_ENABLE` | `True` | Enable or disable the middleware globally |
| `FIELD_PERMISSIONS_USE_CACHE` | `True` | Cache resolved permissions per user |
| `FIELD_PERMISSIONS_CACHE_TIMEOUT` | `3600` | Cache TTL in seconds (default: 1 hour) |

Caches are automatically invalidated when any `FieldPermission` record or its user/group assignments change.

---

## License

MIT — see [LICENSE](LICENSE) for details.
