Dynamic
1. Project Setup
Start by creating a new Django project if you don’t already have one.
django-admin startproject field_level_permissions
cd field_level_permissions
python manage.py startapp company_management
Make sure to add company_management to INSTALLED_APPS in settings.py:
# field_level_permissions/settings.py
INSTALLED_APPS = [
...
'company_management',
'django.contrib.auth', # Ensure auth is included for permission management
]
Run initial migrations:
python manage.py migrate
2. Create a Model with Sensitive Fields
We’ll create a Company model where certain fields (e.g., salary and designation) are restricted based on field-level permissions.
# company_management/models.py
from django.db import models
from django.core.validators import MinLengthValidator, RegexValidator
from django.contrib.auth.models import User, Group
class Company(models.Model):
name = models.CharField(
max_length=255,
unique=True,
validators=[
MinLengthValidator(3),
RegexValidator(regex=r'^[^\d]*$', message="Company name must not contain numbers.")
]
)
address = models.CharField(max_length=255, blank=True, null=True)
salary = models.DecimalField(max_digits=10, decimal_places=2)
designation = models.CharField(max_length=255, blank=True, null=True)
class Meta:
permissions = [
("change_salary", "Can change salary"),
("change_designation", "Can change designation"),
("add_salary", "Can add salary"),
("add_designation", "Can add designation"),
]
def __str__(self):
return self.name
Here, we have custom permissions for the fields salary and designation.
3. Assigning Permissions for Fields
Now, we need to assign these permissions to specific users. Django has built-in permission models, so you can easily manage this via the Django Admin interface or programmatically.
Assigning Permissions via Django Admin
- Create a superuser:
python manage.py createsuperuser- Register the
Companymodel in the admin:
# company_management/admin.py
from django.contrib import admin
from .models import Company
@admin.register(Company)
class CompanyAdmin(admin.ModelAdmin):
list_display = ('name', 'address', 'salary', 'designation')
- After running
python manage.py makemigrationsandpython manage.py migrate, head to/admin, login, and assign permissions to users forsalaryanddesignationfields.
এবার ডাটাবেজ migrate করলে পারমিশন গুলো অ্যাডমিন প্যানেল এ দেখা যাবে ওখান থেকে ইউসার বা গ্রুপ ধরে পারমিশন দেব যেমন মডেল লেভেল এ দেই ওখানেই এই নতুন পারমিশন গুলো শো করবে।
4. Checking Permissions at Field Level
We’ll now implement logic to ensure that users can only change specific fields based on their permissions.
from rest_framework import serializers
from .models import Company
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = '__all__' # This will include all fields from the modelIn the Company model, override the save method to check permissions before updating fields.
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from rest_framework.exceptions import PermissionDenied
from .models import Company
from .serializers import CompanySerializer
class CompanyViewSet(viewsets.ModelViewSet):
queryset = Company.objects.all()
serializer_class = CompanySerializer
permission_classes = [IsAuthenticated] # Ensure user is authenticated
# Check permissions for creating (add) data
def create(self, request, *args, **kwargs):
user = request.user
# Check if 'salary' field is in request and if user has permission to add it
if 'salary' in request.data and not user.has_perm('company_management.add_salary'):
raise PermissionDenied("You don't have permission to add salary.")
# Check if 'designation' field is in request and if user has permission to add it
if 'designation' in request.data and not user.has_perm('company_management.add_designation'):
raise PermissionDenied("You don't have permission to add designation.")
# If all checks pass, proceed with the normal create operation
return super().create(request, *args, **kwargs)
# Check permissions for updating data
def update(self, request, *args, **kwargs):
company = self.get_object()
user = request.user
# Check if user is trying to update 'salary' and has the permission to do so
if 'salary' in request.data and not user.has_perm('company_management.change_salary'):
raise PermissionDenied("You don't have permission to change the salary.")
# Check if user is trying to update 'designation' and has the permission to do so
if 'designation' in request.data and not user.has_perm('company_management.change_designation'):
raise PermissionDenied("You don't have permission to change the designation.")
# If all checks pass, proceed with the normal update operation
return super().update(request, *args, **kwargs)
All is Manual
ধরুন, আমরা Django REST Framework (DRF) ব্যবহার করে ফিল্ড-লেভেল পারমিশন অ্যাপ্লাই করতে চাই, যেখানে আমরা ViewSet এবং Serializer ব্যবহার করে API তৈরি করব। এখানে আমরা EmployeeProfile মডেলের নির্দিষ্ট ফিল্ডে CRUD অপারেশনগুলো গ্রুপের ভিত্তিতে নিয়ন্ত্রণ করব।
ধাপ ১: মডেল তৈরি
# models.py
from django.db import models
from django.contrib.auth.models import User, Group
class EmployeeProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
contact_number = models.CharField(max_length=15)
address = models.CharField(max_length=255)
# ফিল্ড-লেভেল পারমিশন চেক করার জন্য কাস্টম মেথড
def has_field_permission(self, field_name, action, user):
"""
গ্রুপের উপর ভিত্তি করে নির্দিষ্ট ফিল্ডের পারমিশন চেক করা
:param field_name: ফিল্ডের নাম (যেমন contact_number, address)
:param action: create, read, update, delete
:param user: request.user (বর্তমান লগিনকৃত ইউজার)
"""
# ফিল্ড পারমিশনের জন্য প্রয়োজনীয় গ্রুপ ডিফাইন করা
FIELD_PERMISSIONS = {
'contact_number': {
'create': ['Admin', 'Manager'],
'read': ['Admin', 'Manager', 'Supervisor'],
'update': ['Admin', 'Manager'],
'delete': ['Admin'],
},
'address': {
'create': ['Admin'],
'read': ['Admin', 'Manager', 'Supervisor', 'User'],
'update': ['Admin', 'Manager'],
'delete': ['Admin'],
}
}
# ইউজার কোন গ্রুপে আছে কিনা তা যাচাই করা
if field_name in FIELD_PERMISSIONS:
allowed_groups = FIELD_PERMISSIONS[field_name].get(action, [])
return user.groups.filter(name__in=allowed_groups).exists()
return False
ধাপ ২: সিরিয়ালাইজার তৈরি
আমরা DRF-এর মাধ্যমে EmployeeProfileSerializer তৈরি করব, যেখানে EmployeeProfile মডেলের ফিল্ডগুলিকে ফিল্ড-লেভেল পারমিশনের মাধ্যমে নিয়ন্ত্রণ করব।
# serializers.py
from rest_framework import serializers
from .models import EmployeeProfile
class EmployeeProfileSerializer(serializers.ModelSerializer):
class Meta:
model = EmployeeProfile
fields = ['user', 'contact_number', 'address']
# ফিল্ড-লেভেল পারমিশন চেক করা
def to_representation(self, instance):
request = self.context.get('request')
user = request.user
representation = super().to_representation(instance)
# ফিল্ড-লেভেল পারমিশনের ভিত্তিতে ফিল্ডগুলি চেক করা
if not instance.has_field_permission('contact_number', 'read', user):
representation.pop('contact_number')
if not instance.has_field_permission('address', 'read', user):
representation.pop('address')
return representation
এখানে, to_representation মেথডটি ব্যবহার করে আমরা API-তে রেসপন্সে কোন ফিল্ডগুলো দেখানো হবে, তা নির্ধারণ করছি। যদি ইউজার সেই ফিল্ড পড়ার অনুমতি না পায়, তবে আমরা সেই ফিল্ডটি সরিয়ে দিচ্ছি।
ধাপ ৩: API ViewSet তৈরি
এখন আমরা ViewSet তৈরি করব যা EmployeeProfileSerializer এবং ফিল্ড-লেভেল পারমিশন ব্যবহার করবে।
# views.py
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from .models import EmployeeProfile
from .serializers import EmployeeProfileSerializer
class EmployeeProfileViewSet(viewsets.ModelViewSet):
queryset = EmployeeProfile.objects.all()
serializer_class = EmployeeProfileSerializer
permission_classes = [IsAuthenticated]
# ফিল্ড আপডেট করার সময় পারমিশন চেক করা
def update(self, request, *args, **kwargs):
profile = self.get_object()
# ফিল্ড-লেভেল পারমিশন চেক করা
if not profile.has_field_permission('contact_number', 'update', request.user):
return Response({"detail": "আপনার contact_number আপডেট করার পারমিশন নেই।"}, status=status.HTTP_403_FORBIDDEN)
if not profile.has_field_permission('address', 'update', request.user):
return Response({"detail": "আপনার address আপডেট করার পারমিশন নেই।"}, status=status.HTTP_403_FORBIDDEN)
return super().update(request, *args, **kwargs)
এখানে, update মেথডের মধ্যে আমরা ফিল্ড-লেভেল পারমিশন চেক করছি এবং যদি ইউজার সেই ফিল্ড আপডেট করার পারমিশন না পায়, তাহলে আমরা 403 Forbidden রেসপন্স পাঠাচ্ছি।
ধাপ ৪: URL কনফিগারেশন
ViewSet-কে URL-এ যুক্ত করতে হবে।
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import EmployeeProfileViewSet
router = DefaultRouter()
router.register(r'employee-profiles', EmployeeProfileViewSet)
urlpatterns = [
path('', include(router.urls)),
]
ধাপ ৫: গ্রুপ এবং পারমিশন সেট করা
অ্যাডমিন প্যানেল বা কাস্টম স্ক্রিপ্টের মাধ্যমে ইউজারকে গ্রুপে যুক্ত করা এবং পারমিশন সেটআপ করা।
from django.contrib.auth.models import Group, User
# গ্রুপ তৈরি করা
admin_group, created = Group.objects.get_or_create(name='Admin')
manager_group, created = Group.objects.get_or_create(name='Manager')
# ইউজারকে গ্রুপে যুক্ত করা
user = User.objects.get(username='john')
user.groups.add(admin_group)
সারসংক্ষেপ
ViewSet-এ ফিল্ড আপডেট করার সময় পারমিশন চেক করেছি এবং উপযুক্ত রেসপন্স পাঠিয়েছি।
আমরা Django-র ডিফল্ট গ্রুপ ব্যবহার করে ফিল্ড-লেভেল পারমিশন কন্ট্রোল করেছি।
Serializer-এর মধ্যে ফিল্ড-লেভেল পারমিশন চেক করেছি।