نموذج مستخدم جانغو: AbstractUser

يأتي Django مزودًا بنموذج مستخدم مدمج للمصادقة، ومع ذلك، توصي وثائق Django الرسمية بشدة باستخدام نموذج مستخدم مخصص للمشاريع الجديدة.

هناك طريقتان حديثتان لإنشاء نموذج مستخدم مخصص في جانغو بايثون : AbstractUser و AbstractBaseUser.

AbstractBaseUser يتطلب الكثير والكثير من العمل. لذلك سوف نستخدم AbstractUser.

سنقوم أيضًا بإنشاء نموذج UserProfile لتخزين معلومات إضافية حول المستخدمين بمساعدة رابط One-To-One، بعد ذلك، سنقوم بتوسيع وظيفة BaseUserManager قليلاً.

سنقوم أيضًا بإعداد (signal) لإنشاء ملف UserProfile تلقائيا عند إنشاء كائن المستخدم. وفي النهاية، سنخصص مدير Django.

ملاحظة: يجب أن نقوم بذلك في بداية المشروع قبل تشغيل أي عمليات ترحيل.

الخطوة 1: تطبيق جديد

قم بإنشاء تطبيق users باستخدام الأمر  python manage.py startapp users

قم الآن بتسجيل تطبيقك في تطبيقاتك المثبتة في settings.py:

INSTALLED_APPS += [ 'users', ]

قم بتعيين AUTH_USER_MODEL في settings.py على نموذج المستخدم الجديد:

 AUTH_USER_MODEL = 'users.User'

الخطوة 2: توسيع النموذج والمدير

قم بإنشاء ملف Constants.py داخل دليل تطبيق users.

# users/constants.py
SUPERUSER = 1
STAFF = 2
STUDENT = 3
TUTOR = 4

USER_TYPE_CHOICES = (
      (SUPERUSER, 'superuser'),
      (STAFF, 'staff'),
      (STUDENT, 'student'),
      (TUTOR, 'tutor'),
  )

قم بتوسيع نموذج User في users/models.py.

from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils import timezone
from apps.users.managers import UserManager
from . import constants as user_constants

class User(AbstractUser):
    username = None  # قم بإزالة حقل اسم المستخدم، وسوف نستخدم البريد الإلكتروني كمعرف فريد
    email = models.EmailField(unique=True, null=True, db_index=True)
    is_active = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    date_joined = models.DateTimeField(default=timezone.now)
    user_type = models.PositiveSmallIntegerField(choices=user_constants.USER_TYPE_CHOICES)

    REQUIRED_FIELDS = []
    USERNAME_FIELD = 'email'

    objects = UserManager()


class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True,related_name="user_profile")
    phone = models.CharField(max_length=255,blank=True,null=True)
    is_verified = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.user.email

قم بتوسيع UserManager في users/managers.py

# users/managers.py

from django.contrib.auth.models import BaseUserManager
from . import constants as user_constants


class UserManager(BaseUserManager):
    def create_user(self, email, password, **extra_fields):

        if not email:
            raise ValueError('The Email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_active', True)
        extra_fields.setdefault('user_type', user_constants.SUPERUSER)
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')
        return self.create_user(email, password, **extra_fields)

الخطوة 3:Migrations

قم بتشغيل الأوامر التالية لإجراء تغييرات على قاعدة البيانات

python manage.py makemigrations 
python manage.py migrate

الخطوة 4: إنشاء الإشارة

لنقم الآن بإنشاء إشارات لإنشاء مثيل UserProfile تلقائيًا في users/signals.py

# users/signals.py
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import UserProfile, User

@receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)
    instance.user_profile.save()

قم بتسجيل ملف الإشارات داخل users/apps.py عن طريق إضافة تابع جاهز واستيراد مسار ملف الإشارات.

# users/apps.py
from django.apps import AppConfig

class UsersConfig(AppConfig):
    name = 'apps.users'

    def ready(self):
        import apps.users.signals

بعد ذلك قم بإضافة default_app_config إلى users/init.py

# users/__init__.py
default_app_config = 'users.apps.UsersConfig'

الخطوة 5: توسيع نموذج المدير

سنقوم الأن بتوسيع UserCreationForm وUserChangeForm في users/forms.py

# users/forms.py
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import User


class CustomUserCreationForm(UserCreationForm):

    class Meta(UserCreationForm):
        model = User
        fields = ('email',)


class CustomUserChangeForm(UserChangeForm):

    class Meta:
        model = User
        fields = ('email',)

الخطوة 6: تخصيص مستخدم المدير

لنقم بتخصيص مسؤول Django الآن

# users/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import UserProfile, User
from .forms import CustomUserCreationForm, CustomUserChangeForm


class UserProfileInline(admin.StackedInline):
    model = UserProfile
    can_delete=False
    verbose_plural_name="User Profile"
    fk_name = 'user'  

class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserChangeForm
    model = User
    list_display_links = ['email']
    search_fields = ('email',)
    ordering = ('email',)
    # inlines = (UserProfileInline,)
    list_display = ('email', 'is_staff', 'is_active', 'is_superuser',)
    list_filter = ('email', 'is_staff', 'is_active', 'is_superuser', 'user_type')
    fieldsets = (
        (None, {'fields': ('username', 'password')}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email','user_type')}),
        (_('Permissions'), {
            'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'),
        }),
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
    )
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active', 'user_type')}
         ),
    )

    def get_inline_instances(self, request, obj=None):
        if not obj:
            return list()
        return super(CustomUserAdmin, self).get_inline_instances(request, obj)

admin.site.register(User, CustomUserAdmin)

الخطوة 7: التحقق

لقد قمت بتوسيع نموذج المستخدم بنجاح. لنقم الأن بإنشاء مستخدم

python manage.py createsuperuser

#output
Email: develop@pyarab.com
Password: ..........
Password (again): ..........
Superuser created successfully

اكتشاف المزيد من بايثون العربي

اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

Scroll to Top

اكتشاف المزيد من بايثون العربي

اشترك الآن للاستمرار في القراءة والحصول على حق الوصول إلى الأرشيف الكامل.

Continue reading