
كيفية برمجة تطبيق دليل مطاعم باستخدام Python Django
في عالمنا المتصل، أصبح البحث عن المطاعم وتصفح قوائمها وتقييمها عبر الإنترنت أمرًا ضروريًا.
إذا كنت تطمح لتعلم كيفية برمجة تطبيق دليل مطاعم شامل باستخدام Python Django،
فأنت في المكان الصحيح. هذا الدليل المفصل سيأخذك خطوة بخطوة خلال عملية
إنشاء منصة ديناميكية وسهلة الاستخدام لاكتشاف وتقييم المطاعم. سنتناول كل شيء
بدءًا من تصميم واجهة مستخدم جذابة لعرض المطاعم وتفاصيلها وقوائمها وتقييماتها،
مرورًا بتعريف نماذج البيانات لتخزين معلومات المطاعم والفئات والمواقع والأطعمة
والتقييمات، وصولًا إلى تمكين المستخدمين من إضافة مطاعم جديدة و حفظ
بيانات المطاعم وتقييمها، وتنفيذ وظائف البحث والتصفية، وإنشاء نظام
مستخدمين آمن، وأخيرًا نشر التطبيق ليصبح متاحًا للجمهور.
انطلق معنا في هذه الرحلة لتعلم كيفية برمجة تطبيق دليل مطاعم باستخدام
Python Django بطريقة منظمة وفعالة.
خطوات برمجة تطبيق دليل مطاعم باستخدام Python Django
الخطوة 1: إعداد بيئة التطوير وإنشاء مشروع Django
تأكد من تثبيت Python و pip على جهازك. ثم قم بتثبيت Django :
pip install django
-
* أنشئ مشروع Django جديدًا باسم restaurant_directory :
django-admin startproject restaurant_directory
cd restaurant_directory
--
* أنشئ تطبيقًا داخل المشروع باسم restaurants :
python manage.py startapp restaurants
--
الخطوة 2: تعريف نماذج البيانات (Models)
في ملف restaurants/models.py، سنقوم بتعريف نماذج البيانات
الأساسية للمطاعم والفئات والمواقع والأطعمة والتقييمات :
Python
from django.db import modelsfrom django.contrib.auth.models import Userfrom django.utils.text import slugify
class Category(models.Model): name = models.CharField(max_length=100, unique=True) slug = models.SlugField(max_length=100, unique=True, blank=True)
class Meta: verbose_name_plural = 'Categories'
def __str__(self): return self.name
def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name) super().save(*args, **kwargs)
class Location(models.Model): name = models.CharField(max_length=255, unique=True) slug = models.SlugField(max_length=255, unique=True, blank=True) latitude = models.FloatField(blank=True, null=True) longitude = models.FloatField(blank=True, null=True)
def __str__(self): return self.name
def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name) super().save(*args, **kwargs)
class Restaurant(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) category = models.ForeignKey(Category, on_delete=models.CASCADE) location = models.ForeignKey(Location, on_delete=models.CASCADE) name = models.CharField(max_length=255) slug = models.SlugField(max_length=255, unique=True, blank=True) description = models.TextField(blank=True, null=True) address = models.CharField(max_length=255) phone_number = models.CharField(max_length=20, blank=True, null=True) website = models.URLField(blank=True, null=True) opening_hours = models.TextField(blank=True, null=True) image = models.ImageField(upload_to='restaurants/', blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) is_active = models.BooleanField(default=True)
def __str__(self): return self.name
def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name) super().save(*args, **kwargs)
class FoodItem(models.Model): restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE, related_name='menu') name = models.CharField(max_length=255) description = models.TextField(blank=True, null=True) price = models.DecimalField(max_digits=8, decimal_places=2)
def __str__(self): return self.name
class Review(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE, related_name='reviews') rating = models.IntegerField(choices=[(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5')]) comment = models.TextField(blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True)
class Meta: unique_together = ('user', 'restaurant') ordering = ['-created_at']
def __str__(self): return f"Review by {self.user.username} for {self.restaurant.name}"
--
* أضف تطبيق restaurants إلى قائمة INSTALLED_APPS في
ملف restaurant_directory/settings.py :
Python
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'restaurants', # إضافة تطبيق restaurants هنا
]
--
* قم بإنشاء التغييرات وتنفيذها :
python manage.py makemigrations restaurants
python manage.py migrate
--
الخطوة 3: إنشاء واجهة المستخدم (Templates)
أنشئ مجلدًا باسم templates داخل مجلد تطبيق restaurants.
ثم أنشئ ملفات HTML التالية:
* restaurants/templates/restaurants/restaurant_list.html:
لعرض قائمة المطاعم:
HTML
<!DOCTYPE html>
<html>
<head>
<title>دليل المطاعم</title>
</head>
<body>
<h1>المطاعم المتاحة</h1>
<ul>
{% for restaurant in restaurants %}
<li><a href="{% url 'restaurant_detail' restaurant.slug %}">{{ restaurant.name }}</a> - {{ restaurant.location.name }}</li>
{% empty %}
<li>لا توجد مطاعم متاحة حاليًا.</li>
{% endfor %}
</ul>
<a href="{% url 'add_restaurant' %}">أضف مطعمًا جديدًا</a>
</body>
</html>
--
* restaurants/templates/restaurants/restaurant_detail.html :
لعرض تفاصيل المطعم وقائمة الطعام والتقييمات :
HTML
<!DOCTYPE html><html><head> <title>{{ restaurant.name }}</title></head><body> <h1>{{ restaurant.name }}</h1> {% if restaurant.image %} <img src="{{ restaurant.image.url }}" alt="{{ restaurant.name }}" style="max-width: 400px;"> {% endif %} <p>الموقع: {{ restaurant.location.name }}</p> <p>العنوان: {{ restaurant.address }}</p> {% if restaurant.phone_number %} <p>رقم الهاتف: {{ restaurant.phone_number }}</p> {% endif %} {% if restaurant.website %} <p>الموقع الإلكتروني: <a href="{{ restaurant.website }}">{{ restaurant.website }}</a></p> {% endif %} {% if restaurant.opening_hours %} <p>ساعات العمل: {{ restaurant.opening_hours }}</p> {% endif %} {% if restaurant.description %} <p>الوصف: {{ restaurant.description }}</p> {% endif %}
<h2>قائمة الطعام</h2> {% if restaurant.menu.all %} <ul> {% for item in restaurant.menu.all %} <li>{{ item.name }} - {{ item.price }} {% if item.description %} <p>{{ item.description }}</p> {% endif %} </li> {% endfor %} </ul> {% else %} <p>لا توجد عناصر في قائمة الطعام حاليًا.</p> {% endif %}
<h2>التقييمات</h2> {% if restaurant.reviews.all %} <ul> {% for review in restaurant.reviews.all %} <li>{{ review.user.username }} - التقييم: {{ review.rating }} {% if review.comment %} <p>{{ review.comment }}</p> {% endif %} {% if request.user.is_authenticated and request.user == review.user %} <a href="{% url 'edit_review' restaurant.slug review.id %}">تعديل التقييم</a> {% endif %} </li> {% endfor %} </ul> {% else %} <p>لا توجد تقييمات لهذا المطعم حتى الآن.</p> {% endif %}
{% if request.user.is_authenticated %} <h3>إضافة تقييم</h3> <form method="post" action="{% url 'add_review' restaurant.slug %}"> {% csrf_token %} {{ review_form.as_p }} <button type="submit">إضافة تقييم</button> </form> {% else %} <p><a href="{% url 'login' %}">سجل الدخول</a> لإضافة تقييم.</p> {% endif %}
<a href="{% url 'restaurant_list' %}">العودة إلى قائمة المطاعم</a></body></html>
--
* restaurants/templates/restaurants/add_restaurant.html :
لنموذج إضافة مطعم جديد:
HTML
<!DOCTYPE html>
<html>
<head>
<title>إضافة مطعم جديد</title>
</head>
<body>
<h1>أضف مطعمًا جديدًا</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ restaurant_form.as_p }}
<button type="submit">إضافة المطعم</button>
</form>
<a href="{% url 'restaurant_list' %}">العودة إلى قائمة المطاعم</a>
</body>
</html>
--
* restaurants/templates/restaurants/edit_review.html:
لنموذج تعديل التقييم:
HTML
<!DOCTYPE html>
<html>
<head>
<title>تعديل التقييم</title>
</head>
<body>
<h1>تعديل التقييم</h1>
<form method="post">
{% csrf_token %}
{{ review_form.as_p }}
<button type="submit">حفظ التعديلات</button>
</form>
<a href="{% url 'restaurant_detail' restaurant.slug %}">العودة إلى تفاصيل المطعم</a>
</body>
</html>
--
الخطوة 4: إنشاء النماذج (Forms)
في ملف restaurants/forms.py (إذا لم يكن موجودًا، قم بإنشائه) :
Python
from django import forms
from .models import Restaurant, FoodItem, Review
class AddRestaurantForm(forms.ModelForm):
class Meta:
model = Restaurant
fields = ['category', 'location', 'name', 'description', 'address', 'phone_number', 'website', 'opening_hours', 'image']
class AddFoodItemForm(forms.ModelForm):
class Meta:
model = FoodItem
fields = ['name', 'description', 'price']
class ReviewForm(forms.ModelForm):
rating = forms.ChoiceField(choices=[(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5')], widget=forms.RadioSelect)
class Meta:
model = Review
fields = ['rating', 'comment']
--
الخطوة 5: إنشاء طرق العرض (Views)
في ملف restaurants/views.py:
Python
from django.shortcuts import render, redirect, get_object_or_404from .models import Restaurant, Category, Location, FoodItem, Reviewfrom .forms import AddRestaurantForm, AddFoodItemForm, ReviewFormfrom django.contrib.auth.decorators import login_requiredfrom django.db import transactionfrom django.contrib import messages
def restaurant_list(request): restaurants = Restaurant.objects.filter(is_active=True).order_by('name') return render(request, 'restaurants/restaurant_list.html', {'restaurants': restaurants})
def restaurant_detail(request, slug): restaurant = get_object_or_404(Restaurant, slug=slug, is_active=True) review_form = ReviewForm() return render(request, 'restaurants/restaurant_detail.html', {'restaurant': restaurant, 'review_form': review_form})
@login_requireddef add_restaurant(request): if request.method == 'POST': restaurant_form = AddRestaurantForm(request.POST, request.FILES) if restaurant_form.is_valid(): restaurant = restaurant_form.save(commit=False) restaurant.user = request.user restaurant.save() messages.success(request, 'تمت إضافة المطعم بنجاح.') return redirect('restaurant_detail', slug=restaurant.slug) else: messages.error(request, 'حدث خطأ أثناء إضافة المطعم. يرجى التحقق من النموذج.') else: restaurant_form = AddRestaurantForm() return render(request, 'restaurants/add_restaurant.html', {'restaurant_form': restaurant_form})
@login_requireddef add_review(request, restaurant_slug): restaurant = get_object_or_404(Restaurant, slug=restaurant_slug, is_active=True) if request.method == 'POST': review_form = ReviewForm(request.POST) if review_form.is_valid(): review = review_form.save(commit=False) review.user = request.user review.restaurant = restaurant try: review.save() messages.success(request, 'تمت إضافة تقييمك بنجاح.') return redirect('restaurant_detail', slug=restaurant.slug) except Exception as e: messages.error(request, 'لقد قمت بتقييم هذا المطعم بالفعل.') return redirect('restaurant_detail', slug=restaurant.slug) else: messages.error(request, 'حدث خطأ أثناء إضافة تقييمك. يرجى التحقق من النموذج.') return redirect('restaurant_detail', slug=restaurant.slug)
@login_requireddef edit_review(request, restaurant_slug, review_id): restaurant = get_object_or_404(Restaurant, slug=restaurant_slug, is_active=True) review = get_object_or_404(Review, id=review_id, user=request.user, restaurant=restaurant) if request.method == 'POST': review_form = ReviewForm(request.POST, instance=review) if review_form.is_valid(): review_form.save() messages.success(request, 'تم تعديل تقييمك بنجاح.')return redirect('restaurant_detail', slug=restaurant.slug)else:messages.error(request, 'حدث خطأ أثناء تعديل تقييمك. يرجى التحقق من النموذج.')else:review_form = ReviewForm(instance=review)return render(request, 'restaurants/edit_review.html', {'review_form': review_form, 'restaurant': restaurant})
--
الخطوة 6: تعريف مسارات URL (URLs)
في ملف `restaurants/urls.py` (إذا لم يكن موجودًا، قم بإنشائه):
python
from django.urls import path
from . import views
urlpatterns = [
path('', views.restaurant_list, name='restaurant_list'),
path('add/', views.add_restaurant, name='add_restaurant'),
path('<slug:slug>/', views.restaurant_detail, name='restaurant_detail'),
path('<slug:restaurant_slug>/review/', views.add_review, name='add_review'),
path('<slug:restaurant_slug>/review/edit/<int:review_id>/', views.edit_review, name='edit_review'),
]
--
* قم بتضمين مسارات تطبيق restaurants في ملف
restaurant_directory/urls.py :
Python
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.shortcuts import redirect
urlpatterns = [
path('admin/', admin.site.urls),
path('restaurants/', include('restaurants.urls')),
path('accounts/', include('django.contrib.auth.urls')), # لتسجيل الدخول والخروج
path('', lambda request: redirect('/restaurants/')), # إعادة التوجيه إلى قائمة المطاعم عند الوصول إلى الجذر
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
--
* تأكد من إضافة 'django.contrib.auth' إلى
INSTALLED_APPS في settings.py.
الخطوة 7: إنشاء واجهة إدارة (Django Admin)
لتسهيل إدارة المطاعم والفئات والمواقع والأطعمة والتقييمات،
قم بتسجيل النماذج في Django Admin في ملف restaurants/admin.py :
Python
from django.contrib import adminfrom .models import Restaurant, Category, Location, FoodItem, Review
class FoodItemInline(admin.TabularInline): model = FoodItem extra = 3
@admin.register(Category)class CategoryAdmin(admin.ModelAdmin): list_display = ('name', 'slug') prepopulated_fields = {'slug': ('name',)}
@admin.register(Location)class LocationAdmin(admin.ModelAdmin): list_display = ('name', 'slug', 'latitude', 'longitude') prepopulated_fields = {'slug': ('name',)}
@admin.register(Restaurant)class RestaurantAdmin(admin.ModelAdmin): list_display = ('name', 'category', 'location', 'user', 'is_active', 'created_at') list_filter = ('category', 'location', 'is_active') search_fields = ('name', 'description', 'address') prepopulated_fields = {'slug': ('name',)} inlines = [FoodItemInline]
@admin.register(FoodItem)class FoodItemAdmin(admin.ModelAdmin): list_display = ('name', 'restaurant', 'price') list_filter = ('restaurant',) search_fields = ('name', 'description')
@admin.register(Review)class ReviewAdmin(admin.ModelAdmin): list_display = ('user', 'restaurant', 'rating', 'created_at') list_filter = ('restaurant', 'rating') search_fields = ('comment', 'user__username', 'restaurant__name')
--
* قم بإنشاء مستخدم مسؤول إذا لم يكن لديك واحدًا بالفعل :
python manage.py createsuperuser
--
* ثم قم بتشغيل خادم التطوير وقم بزيارة http://127.0.0.1:8000/admin/ ل
تسجيل الدخول وإدارة المطاعم والفئات والمواقع والأطعمة والتقييمات.
الخطوة 8: حفظ بيانات المطاعم والتقييمات
يتم حفظ بيانات المطاعم عند تقديم نموذج إضافة المطعم (AddRestaurantForm)
في طريقة العرض add_restaurant. يتم إنشاء كائن
Restaurant جديد مرتبط بالمستخدم والفئة والموقع.
يتم حفظ بيانات التقييمات عند تقديم نموذج التقييم (ReviewForm)
في طريقة العرض add_review. يتم إنشاء كائن Review جديد مرتبط بالمستخدم
والمطعم والتقييم والتعليق. Django ORM يتولى عملية التفاعل مع قاعدة
البيانات وحفظ البيانات بناءً على تعريف النماذج والعلاقات بينها.
الخطوة 9: نشر التطبيق
لنشر تطبيق Django، يمكنك اتباع الخطوات العامة التالية (باستخدام Gunicorn و Nginx كمثال):
* تثبيت Gunicorn :
pip install gunicorn
--
* اختبار Gunicorn: انتقل إلى مجلد مشروع Django وقم بتشغيل:
gunicorn restaurant_directory.wsgi:application
--
* تثبيت Nginx :
sudo apt update
sudo apt install nginx
--
* تكوين Nginx: قم بإنشاء ملف تكوين جديد للموقع الخاص بك في /etc/nginx/sites-available/ (مثل restaurant_directory) وقم بربطه بـ /etc/nginx/sites-enabled/. مثال على التكوين:
Nginx
server {
listen 80;
server_name your_domain_or_IP;
location /static/ {
alias /path/to/your/project/staticfiles/;
}
location /media/ {
alias /path/to/your/project/media/;
}
location / {
proxy_pass [http://127.0.0.1:8000](http://127.0.0.1:8000);
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
--
استبدل your_domain_or_IP بعنوان نطاقك أو عنوان IP الخاص بالخادم،
و /path/to/your/project/staticfiles/ بالمسار
الفعلي لمجلد الملفات الثابتة الخاص بك، و
/path/to/your/project/media/ بالمسار الفعلي لمجلد الوسائط الخاص بك.
* جمع الملفات الثابتة :
python manage.py collectstatic
--
تكوين نظام إدارة العمليات (مثل systemd) لتشغيل Gunicorn تلقائيًا.
* إعادة تشغيل Nginx :
sudo systemctl restart nginx
--
تأمين الخادم الخاص بك (مثل إعداد جدار حماية وتكوين HTTPS باستخدام Let's Encrypt).
* الخلاصة :
لقد استعرضنا الخطوات الأساسية لبرمجة تطبيق دليل مطاعم شامل باستخدام
Python Django، بدءًا من إنشاء واجهة المستخدم لعرض المطاعم وتفاصيلها
وقوائمها وتقييماتها ونماذج الإضافة والتقييم، مرورًا بتعريف نماذج البيانات
للمطاعم والفئات والمواقع والأطعمة والتقييمات، وصولًا إلى تمكين المستخدمين
من إضافة المطاعم وتقييمها و حفظ هذه البيانات وعرضها، وتقديم نظرة عامة على
عملية نشر التطبيق. يمكنك الآن تطوير هذا التطبيق بإضافة المزيد من الميزات
مثل البحث المتقدم، وتصفية المطاعم حسب الفئة والموقع ونوع الطعام والتقييم،
ونظام حجز الطاولات، وتكامل خرائط Google، والمزيد من التحسينات على واجهة
المستخدم وتجربة المستخدم. تذكر دائمًا التركيز على أمان التطبيق وحماية بيانات المستخدمين والصور المرفوعة.