python web framework

ربط موقعك ببايثون بقاعدة بيانات وإدارة المستخدمين

|

تعلّم كيف تربط موقعك المبني ببايثون وجانغو بقاعدة بيانات PostgreSQL وتُدير المستخدمين وصلاحياتهم باحترافيةٍ خطوةً بخطوة.

عدد الكلمات: ~١٩٠٠ · مدة القراءة: ١٠ دقائق

قواعد البيانات وإدارة المستخدمين ببايثون

كيف تربط موقعك بقاعدة بياناتٍ حقيقية وتُدير المستخدمين وصلاحياتهم باحترافية


ملاحظة للقارئ: هذا المقال مستقلٌّ تماماً ويمكنك تطبيق كل ما فيه دون قراءة مقالاتٍ سابقة. لكن إذا لم تكن قد بنيت موقعاً ببايثون بعد، فننصحك بمراجعة مقالتنا: تحويل موقعك الثابت HTML إلى موقع ديناميكي ببايثون وفلاسك.

حتى الآن، كل البيانات التي تعاملنا معها في هذه السلسلة كانت مؤقتةً — تختفي فور إيقاف السكريبت، أو مخزّنةً في ملفاتٍ CSV بسيطة. هذا يكفي للتجريب والنماذج الأولية، لكنه لا يكفي لأي موقعٍ حقيقيٍّ تبنيه لعميلٍ أو لنفسك. الموقع الحقيقي يحتاج ذاكرةً دائمةً تتذكر المستخدمين وطلباتهم ومشترياتهم وتعليقاتهم حتى بعد إعادة تشغيل الخادم مئة مرة.

هذه الذاكرة الدائمة اسمها قاعدة البيانات Database. وفي هذا المقال من منصة ذي يزن، سنتعلم كيف نربط موقعنا المبني ببايثون بقاعدة بياناتٍ حقيقية، وكيف نُخزّن البيانات ونستردّها باستخدام محرك ORM الخاص بجانغو، وأخيراً كيف نبني نظام مستخدمين كاملاً بتسجيل دخولٍ وصلاحياتٍ بأسطرٍ قليلة.

Python code displayed on screen in an exciting way

لماذا PostgreSQL تحديداً؟

حين يتعلق الأمر بقواعد البيانات لمشاريع الويب الجادة، يُواجه الفريلانسر خياراتٍ عدة: SQLite وMySQL وPostgreSQL وغيرها. دعنا نوضّح متى تختار كل واحدة:

SQLite — قاعدة بياناتٍ مدمجةٌ في ملفٍّ واحد، ممتازةٌ للتطوير المحلي والمشاريع الصغيرة جداً. جانغو يستخدمها افتراضياً لأنها لا تحتاج أي تثبيت. لكنها لا تصلح للمشاريع التي يستخدمها أكثر من مستخدمٍ واحدٍ في اللحظة ذاتها.

MySQL — شائعةٌ جداً ومدعومةٌ من معظم شركات الاستضافة. خيارٌ جيدٌ لكنها تفتقر لبعض الميزات المتقدمة.

PostgreSQL — قاعدة البيانات الأكثر احترافيةً واكتمالاً في العالم مفتوح المصدر. تدعم البيانات المعقدة، والبحث النصي الكامل، وأنواع البيانات المتقدمة، وتتحمل أحمالاً ضخمة. معظم المنصات الاحترافية الكبيرة تعمل عليها، لهذا نختارها.

النصيحة العملية: طوّر مشروعك محلياً على SQLite وانشره على الخادم بـ PostgreSQL. جانغو يجعل التبديل بين قواعد البيانات سهلاً جداً لأنه يتعامل معها جميعاً بنفس الأسلوب.

تثبيت PostgreSQL وربطها بجانغو

أولاً، ثبّت PostgreSQL على جهازك. إذا كنت تعمل على ويندوز Windows أو ماك Mac، حمّل المثبّت من الموقع الرسمي. على لينكس Linux:

sudo apt update
sudo apt install postgresql postgresql-contrib

ثم أنشئ قاعدة بياناتٍ ومستخدماً لمشروعك:

# الدخول إلى واجهة PostgreSQL
sudo -u postgres psql

-- إنشاء قاعدة بيانات للمشروع
CREATE DATABASE myproject_db;

-- إنشاء مستخدم بكلمة مرور
CREATE USER myproject_user WITH PASSWORD 'your_strong_password';

-- منح الصلاحيات الكاملة
GRANT ALL PRIVILEGES ON DATABASE myproject_db TO myproject_user;

-- الخروج
\q

الآن ثبّت مكتبة الاتصال بين بايثون وPostgreSQL:

pip install psycopg2-binary

وعدّل ملف إعدادات جانغو settings.py ليتصل بقاعدة بياناتك:

# mysite/settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'myproject_db',
        'USER': 'myproject_user',
        'PASSWORD': 'your_strong_password',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

ثم شغّل أمر الترحيل الأولي Migration لإنشاء الجداول الافتراضية لجانغو:

python manage.py migrate

إذا ظهرت رسالة «Operations to perform… Running migrations…» دون أخطاء، فالاتصال يعمل بنجاح.

محرك ORM في جانغو: تحدّث مع قاعدة البيانات ببايثون لا بـ SQL

محرك ORM أي المحوّل الكائني العلاقي Object Relational Mapper هو القلب النابض لجانغو. بدلاً من كتابة استعلاماتٍ SQL معقدة مثل SELECT * FROM projects WHERE client_id = 5، تكتب كود بايثون عادياً ويترجمه جانغو إلى SQL تلقائياً. هذا يعني:

  • كودٌ أكثر وضوحاً وأسهل قراءةً
  • حمايةٌ تلقائيةٌ من ثغرات حقن SQL الخطيرة SQL Injection
  • إمكانية التبديل بين قواعد البيانات دون تغيير الكود

تعريف نماذج البيانات Models — قلب أي مشروع

لنبنِ نظاماً لإدارة مشاريع الفريلانسر. كل نموذجٍ Model هو جدولٌ في قاعدة البيانات:

# mainapp/models.py
from django.db import models
from django.contrib.auth.models import User

class Client(models.Model):
    """نموذج العميل — كل فريلانسر لديه قائمة عملاء"""
    name = models.CharField(max_length=200, verbose_name="اسم العميل")
    email = models.EmailField(unique=True, verbose_name="البريد الإلكتروني")
    phone = models.CharField(max_length=20, blank=True, verbose_name="رقم الهاتف")
    country = models.CharField(max_length=100, blank=True, verbose_name="الدولة")
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "عميل"
        verbose_name_plural = "العملاء"
        ordering = ['-created_at']


class Project(models.Model):
    """نموذج المشروع — مرتبطٌ بعميلٍ واحد"""

    STATUS_CHOICES = [
        ('pending', 'قيد الانتظار'),
        ('active', 'جارٍ التنفيذ'),
        ('completed', 'مكتمل'),
        ('cancelled', 'ملغى'),
    ]

    title = models.CharField(max_length=300, verbose_name="عنوان المشروع")
    client = models.ForeignKey(
        Client,
        on_delete=models.CASCADE,
        related_name='projects',
        verbose_name="العميل"
    )
    description = models.TextField(verbose_name="وصف المشروع")
    budget = models.DecimalField(
        max_digits=10, decimal_places=2,
        verbose_name="الميزانية بالدولار"
    )
    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='pending',
        verbose_name="حالة المشروع"
    )
    deadline = models.DateField(null=True, blank=True, verbose_name="تاريخ التسليم")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f"{self.title} — {self.client.name}"

    class Meta:
        verbose_name = "مشروع"
        verbose_name_plural = "المشاريع"
        ordering = ['-created_at']

الآن أنشئ جداول قاعدة البيانات من هذه النماذج:

python manage.py makemigrations
python manage.py migrate

العمليات الأساسية على قاعدة البيانات: إنشاءٌ وقراءةٌ وتعديلٌ وحذف

هذه العمليات الأربع تُعرف اختصاراً بـ CRUD أي إنشاء Create وقراءة Read وتحديث Update وحذف Delete، وهي أساس أي تطبيق ويب. إليك كيف تُنجزها ببايثون عبر محرك ORM في جانغو:

الإنشاء Create — إضافة سجلٍّ جديد

# في views.py أو أي ملف بايثون داخل مشروع جانغو
from .models import Client, Project

# إنشاء عميلٍ جديد وحفظه في قاعدة البيانات
new_client = Client.objects.create(
    name="شركة التقنية العربية",
    email="info@arabtech.com",
    country="السعودية"
)

# إنشاء مشروعٍ مرتبطٍ بهذا العميل
new_project = Project.objects.create(
    title="موقع الشركة الجديد",
    client=new_client,
    description="تصميم وتطوير موقع ويبٍ احترافي",
    budget=2500.00,
    status='active'
)

القراءة Read — استرجاع البيانات

# جلب جميع العملاء
all_clients = Client.objects.all()

# جلب عميلٍ واحد بالمعرّف ID
client = Client.objects.get(id=1)

# البحث والتصفية — المشاريع النشطة فقط
active_projects = Project.objects.filter(status='active')

# تصفيةٌ متعددة — مشاريع عميلٍ بعينه بميزانيةٍ فوق 1000 دولار
big_projects = Project.objects.filter(
    client=client,
    budget__gt=1000
).order_by('-created_at')

# جلب أول نتيجة فقط
latest_project = Project.objects.filter(
    client=client
).first()

التحديث Update — تعديل سجلٍّ موجود

# تحديث مشروعٍ واحد
project = Project.objects.get(id=1)
project.status = 'completed'
project.save()

# تحديث عدة سجلاتٍ دفعةً واحدة
Project.objects.filter(status='pending').update(status='active')

الحذف Delete — إزالة سجلٍّ

# حذف مشروعٍ واحد
project = Project.objects.get(id=5)
project.delete()

# حذف جميع المشاريع الملغاة
Project.objects.filter(status='cancelled').delete()

نظام المستخدمين الجاهز في جانغو: تسجيل دخولٍ كاملٌ في دقائق

هنا تكمن قيمةٌ حقيقيةٌ لا مثيل لها في جانغو. بدلاً من بناء نظام تسجيل الدخول من الصفر — وهو أمرٌ يستغرق أياماً ويستوجب الانتباه لعشرات التفاصيل الأمنية — جانغو يُقدّمه جاهزاً.

تسجيل مستخدمٍ جديد

# mainapp/views.py
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages

def register(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, 'تم إنشاء حسابك بنجاح! يمكنك تسجيل الدخول الآن.')
            return redirect('login')
    else:
        form = UserCreationForm()

    return render(request, 'registration/register.html', {'form': form})

تسجيل الدخول والخروج — جانغو يتولى كل شيء

# mysite/urls.py
from django.urls import path, include
from mainapp import views

urlpatterns = [
    path('admin/', admin.site.urls),

    # جانغو يُوفّر views تسجيل الدخول والخروج وإعادة تعيين كلمة المرور جاهزة
    path('accounts/', include('django.contrib.auth.urls')),

    # صفحة التسجيل الخاصة بنا
    path('accounts/register/', views.register, name='register'),

    path('', views.home, name='home'),
    path('dashboard/', views.dashboard, name='dashboard'),
]

بمجرد إضافة django.contrib.auth.urls، تحصل تلقائياً على هذه الصفحات الجاهزة:

الرابط الوظيفة تحتاج كودًا إضافياً؟
/accounts/login/ صفحة تسجيل الدخول قالب HTML فقط
/accounts/logout/ تسجيل الخروج لا — يعمل تلقائياً
/accounts/password_change/ تغيير كلمة المرور قالب HTML فقط
/accounts/password_reset/ إعادة تعيين كلمة المرور بالإيميل إعداد البريد الإلكتروني فقط

حماية الصفحات: لا يدخل إلا المسجّلون

أكثر حالاتٍ استخداماً في أي موقعٍ به مستخدمون هي تقييد بعض الصفحات للمسجّلين فقط. في جانغو يكفي سطرٌ واحد:

# mainapp/views.py
from django.contrib.auth.decorators import login_required

@login_required  # هذا السطر يكفي لحماية الصفحة كاملاً
def dashboard(request):
    """لوحة التحكم — للمسجّلين فقط"""
    # request.user يحتوي دائماً على بيانات المستخدم المسجّل
    user_projects = Project.objects.filter(
        client__in=Client.objects.filter(created_by=request.user)
    )

    return render(request, 'dashboard.html', {
        'projects': user_projects,
        'user': request.user,
        'total_budget': sum(p.budget for p in user_projects),
        'active_count': user_projects.filter(status='active').count(),
    })

حين يحاول زائرٌ غير مسجّلٍ الوصول إلى هذه الصفحة، يُعيده جانغو تلقائياً إلى صفحة تسجيل الدخول ثم يُعيده بعد التسجيل إلى الصفحة التي أراد الوصول إليها. كل هذا بسطرٍ واحد.

ربط المشاريع بالمستخدمين: كل فريلانسر يرى مشاريعه فقط

لنُحكم النظام: كل مستخدمٍ يجب أن يرى عملاءه ومشاريعه فقط لا مشاريع الآخرين. نُعدّل النموذج ليرتبط بمستخدم جانغو:

# mainapp/models.py — تحديث نموذج العميل
from django.contrib.auth.models import User

class Client(models.Model):
    owner = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='clients',
        verbose_name="مالك السجل"
    )
    name = models.CharField(max_length=200)
    email = models.EmailField()
    # ... بقية الحقول
# في الـ view — التأكد دائماً من أن المستخدم يرى بياناته فقط
@login_required
def clients_list(request):
    # فلترةٌ تلقائيةٌ بالمستخدم المسجّل
    clients = Client.objects.filter(owner=request.user)
    return render(request, 'clients.html', {'clients': clients})

@login_required
def add_client(request):
    if request.method == 'POST':
        name = request.POST.get('name')
        email = request.POST.get('email')
        # ربط العميل الجديد بالمستخدم المسجّل تلقائياً
        Client.objects.create(
            owner=request.user,
            name=name,
            email=email
        )
        return redirect('clients_list')
    return render(request, 'add_client.html')

نصائح أمنيةٌ مهمةٌ لا تتجاهلها

حين تتعامل مع بياناتٍ حقيقية لعملاء حقيقيين، الأمان ليس اختياراً:

  • لا تضع كلمات المرور وبيانات قاعدة البيانات في الكود مباشرة: استخدم متغيرات البيئة Environment Variables عبر مكتبة python-decouple أو python-dotenv.
  • فعّل HTTPS دائماً على الخادم: معظم منصات الاستضافة توفره مجاناً عبر Let’s Encrypt.
  • حماية CSRF مفعّلةٌ في جانغو افتراضياً: لا تُعطّلها أبداً. تأكد من وجود {% csrf_token %} في كل نموذجٍ HTML.
  • لا تعرض رسائل خطأٍ مفصّلة للزوار: أوقف وضع التنقيح DEBUG = False حين تنشر على الخادم الفعلي.
# مثالٌ على استخدام متغيرات البيئة بأمان
# أولاً: pip install python-decouple

# ملف .env (لا ترفعه على GitHub أبداً)
# SECRET_KEY=your-secret-key-here
# DB_PASSWORD=your-db-password

# settings.py
from decouple import config

SECRET_KEY = config('SECRET_KEY')

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': config('DB_NAME', default='myproject_db'),
        'USER': config('DB_USER', default='myproject_user'),
        'PASSWORD': config('DB_PASSWORD'),
        'HOST': config('DB_HOST', default='localhost'),
        'PORT': config('DB_PORT', default='5432'),
    }
}

درسٌ مهمٌّ تعلّمه المطورون بالطريقة الصعبة: رفع ملفٍّ يحتوي كلمة مرور قاعدة البيانات على GitHub حتى لو كان المستودع خاصاً هو خطأٌ لا يُغتفر. اجعل ملف .env أول سطرٍ تكتبه في ملف .gitignore.


خلاصة المقال والخطوة القادمة

اليوم انتقل موقعنا من الذاكرة المؤقتة إلى الذاكرة الدائمة. تعلمنا كيف نُعدّ قاعدة بياناتٍ PostgreSQL ونربطها بجانغو، كيف نُعرّف نماذج البيانات Models ونُجري عليها عمليات CRUD كاملة، وكيف نبني نظام مستخدمين بتسجيل دخولٍ وصلاحياتٍ وحمايةٍ للصفحات في أسطرٍ قليلة. هذه المهارات مجتمعةً تجعلك قادراً على تسليم موقعٍ ويبٍ كاملٍ وجاهزٍ للاستخدام الفعلي.

freelancer digital marketing work from home laptop success

الخطوة التالية الموصى بها:

موقعنا يقبل البيانات ويخزّنها، لكن ماذا لو أراد عميلٌ الدفع مقابل خدمةٍ تقدّمها أون لاين؟ أو ماذا لو أردت بيع أداةٍ ببايثون كخدمةٍ مشتركةٍ شهرية؟ في المقال القادم نخطو خطوةً أبعد ونتعلم كيف نبني واجهة برمجياتٍ API ببايثون لنبيع خدماتنا للمطورين والتطبيقات الأخرى.

تابع معنا المقال الثاني عشر: بناء API بسيط ببايثون لبيع خدماتك.


المراجع والمصادر:

  1. التوثيق الرسمي لقواعد بيانات جانغو: Django Database Documentation
  2. التوثيق الرسمي لنظام مصادقة جانغو: Django Authentication System
  3. الموقع الرسمي لـ PostgreSQL: PostgreSQL Official Documentation
  4. مكتبة python-decouple لإدارة متغيرات البيئة: python-decouple on PyPI

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *