اذهب إلى المحتوى

لوحة المتصدرين

  1. ابراهيم الخضور

    • نقاط

      1

    • المساهمات

      163


  2. Ola Abbas

    Ola Abbas

    الأعضاء


    • نقاط

      1

    • المساهمات

      189


المحتوى الأكثر حصولًا على سمعة جيدة

المحتوى الأعلى تقييمًا في 12/01/24 in مقالات البرمجة

  1. حان الوقت الآن لإنشاء تطبيق مدونة متكامل باستخدام إطار عمل جانغو Django، فقد تعلمنا في المقال السابق كيف يمكن للنماذج Model والعروض View والقوالب Template أن تعمل معًا لإنشاء تطبيق جانغو لكن هذه العملية صعبة نوعًا ما، إذ يتوجب علينا كتابة 5 إجراءات على الأقل لكل ميزة نريد تحقيقها، وستكون الشيفرة البرمجية مكررةً في معظمها. لذا سنستخدم في هذا المقال واحدة من أفضل ميزات جانغو، وهي لوحة المدير Admin Panel المُضمَّنة، فما عليك سوى كتابة إجراء العرض لمعظم الميزات التي ترغب في إنشائها لتطبيقك، وسيتولى جانغو الباقي نيابة عنك تلقائيًا. إنشاء طبقة النموذج Model سنبدأ أولًا بتصميم بنية قاعدة البيانات. تصميم بنية قاعدة البيانات بالنسبة لأيّ نظام تدوين أساسي، ستحتاج إلى 4 نماذج على الأقل هي User و Category و Tag و Post، وسنضيف في المقال التالي بعض الميزات المتقدمة لاحقًا، ولكن سنكتفي حاليًا بهذه النماذج الأربعة فقط. نموذج المستخدم User المفتاح نوعه معلومات عنه المعرّف id عدد صحيح Integer يتزايد تلقائيًا الاسم name سلسلة نصية String - البريد الإلكتروني email سلسلة نصية فريد كلمة السر password سلسلة نصية - إن النموذج User مُضمَّن مسبقًا في جانغو، إذ يوفّر هذا النموذج المُضمَّن بعض الميزات الأساسية مثل تشفير كلمات المرور Password Hashing واستثياق المستخدمين User Authentication، بالإضافة إلى نظام الأذونات المُضمَّن مع مدير جانغو Django Admin كما سنوضّح لاحقًا. نموذج الفئة Category المفتاح نوعه معلومات عنه المعرّف id عدد صحيح Integer يتزايد تلقائيًا الاسم name سلسلة نصية String - الاسم المختصر slug سلسلة نصية فريد الوصف description نص - نموذج الوسم Tag المفتاح نوعه معلومات عنه المعرّف id عدد صحيح Integer يتزايد تلقائيًا الاسم name سلسلة نصية String - الاسم المختصر slug سلسلة نصية فريد الوصف description نص - نموذج المنشور Post المفتاح نوعه معلومات عنه المعرّف id عدد صحيح Integer يتزايد تلقائيًا العنوان title سلسلة نصية String - الاسم المختصر slug سلسلة نصية فريد المحتوى content نص - featured_image سلسلة نصية String - is_published قيمة منطقية Boolean - is_featured قيمة منطقية - created_at تاريخ Date - نموذج الموقع Site ستحتاج أيضًا إلى جدول آخر لتخزين المعلومات الأساسية للموقع بالكامل مثل الاسم والوصف والشعار. المفتاح نوعه معلومات عنه الاسم name سلسلة نصية String - الوصف description نص text - الشعار logo سلسلة نصية - العلاقات توجد ست علاقات بالنسبة لهذا التطبيق وهي: لكل مستخدم عدة منشورات لكل فئة عدة منشورات ينتمي كل وسم إلى منشورات متعددة ينتمي كل منشور إلى مستخدم واحد ينتمي كل منشور إلى فئة واحدة ينتمي كل منشور إلى وسوم متعددة تطبيق التصميم باستخدام جانغو الآن، بعد أن انتهينا من تصميم هذا النموذج، سنبدأ في تطبيقه كما سنوضح في الخطوات التالية نموذج الموقع Site لنبدأ بنموذج الموقع Site مع توفير خصائص لحفظ بيانات الموقع مثل اسم الموقع ووصفه وصورة الشعار كما يلي: class Site(models.Model): name = models.CharField(max_length=200) description = models.TextField() logo = models.ImageField(upload_to="logo/") class Meta: verbose_name_plural = "site" def __str__(self): return self.name لاحظ أن نوع حقل الصورة ImageField()‎ هو سلسلة نصية string، إذ لا يمكن لقواعد البيانات تخزين الصور، لذا تُخزَّن الصور في نظام ملفات خادمك، وسيحتفظ هذا الحقل بالمسار الذي يشير لموقع الصورة. سنرفع الصور في هذا المثال إلى المجلد ‎mediafiles/logo/‎، وتذكّر إضافة مجلد ملفات الوسائط ‎MEDIA_ROOT = "mediafiles/"‎ في الملف settings.py الذي أعددناه سابقًا. ملاحظة: تحتاج لأن تثبّت مكتبة Pillow على جهازك ليعمل الحقل ImageField()‎ كما يلي: pip install Pillow نموذج الفئة Category بعدها سنصميم نموذج الفئة Category الذي سيُستخدم لتنظيم المحتويات ضمن المدونة ضمن فئات ويحدد الحقول التي سنحتاج إليها لتمثيل الفئات بشكل صحيح في قاعدة البيانات. يتضمن نموذج الفئة Category المحتويات التالية: class Category(models.Model): name = models.CharField(max_length=200) slug = models.SlugField(unique=True) description = models.TextField() class Meta: verbose_name_plural = "categories" def __str__(self): return self.name ينبغي أن يكون النموذج Category مفهومًا بالنسبة لك، لكن دعنا نوضّح الصنف Meta، الذي سنستخدمه لإضافة البيانات الوصفية Metadata إلى النماذج. تمثّل البيانات الوصفية للنموذج أيّ شيء ليس حقلًا مثل خيارات الترتيب واسم جدول قاعدة البيانات وما إلى ذلك، حيث استخدمنا في مثالنا الخيار verbose_name_plural لتحديد صيغة الجمع لكلمة "category"، فجانغو ليس ذكيًا مثل لارافيل Laravel في هذا الجانب، فإن لم نمنح جانغو صيغة الجمع الصحيحة، فسوف يستخدم الجمع "categorys"، وهذا خاطئ. تحدد الدالة ‎__str__(self)‎ الحقل الذي سيستخدمه جانغو عند الإشارة إلى فئة معينة، حيث استخدمنا في مثالنا الحقل name، وسنوضّح أهمية ذلك عندما نصل إلى قسم مدير جانغو. نموذج الوسم Tag يتضمن نموذج الوسم Tag لتخزين الوسوم التي سترتبط بالمنشورات وهو يتضمن اسم الوسم والرابط اللطيف له ووصفه كما توضح الشيفرة التالية: class Tag(models.Model): name = models.CharField(max_length=200) slug = models.SlugField(unique=True) description = models.TextField() def __str__(self): return self.name نموذج المنشور Post لنعرف أخيرًا نموذج المنشور Post الذي يتضمن اسم المنشور والرابط اللطيف والمحتوى الرئيسي والصورة البارزة للمنشور وتاريخ إنشائه وحقلين منطقيين يوضحان هل نشر أم لا وهل هو منشور مميز أما لا كما توضح الشيفرة التالية: from ckeditor.fields import RichTextField . . . class Post(models.Model): title = models.CharField(max_length=200) slug = models.SlugField(unique=True) content = RichTextField() featured_image = models.ImageField(upload_to="images/") is_published = models.BooleanField(default=False) is_featured = models.BooleanField(default=False) created_at = models.DateField(auto_now=True) # تعريف العلاقات category = models.ForeignKey(Category, on_delete=models.CASCADE) tag = models.ManyToManyField(Tag) user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) def __str__(self): return self.title لاحظ في السطر 1 أنه إذا نسختَ هذه الشيفرة البرمجية ولصقتها لديك، فسيخبرك محرّر نصوصك بعدم العثور على RichTextField و ckeditor، لأنها حزمة خارجية ولا تُضمَّن في إطار عمل جانغو. تذكّر أنه يمكنك فقط إضافة نص عادي عند إنشاء منشور في المقال السابق، وهذا ليس مثاليًا لمقال في مدونة. إذ تمنحك محرّرات النصوص الغنية أو محرّرات WYSIWYG القدرة على تحرير صفحات HTML مباشرةً دون كتابة الشيفرة البرمجية، حيث استخدمنا المحرّر CKEditor في هذا المقال. لذا يمكنك تثبيت المحرّر CKEditor من خلال تشغيل الأمر التالي: pip install django-ckeditor سجّل بعد ذلك ckeditor في ملف الإعدادات settings.py كما يلي: INSTALLED_APPS = [ "blog", "ckeditor", "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", ] تعريف العلاقات أخيرًا، يمكنك إضافة علاقات إلى النماذج، حيث سنضيف الأسطر الثلاثة التالية في النموذج Post للقيام بذلك كما يلي: category = models.ForeignKey(Category, on_delete=models.CASCADE) tag = models.ManyToManyField(Tag) user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) بما أننا نستخدم نموذج المستخدم User المُضمَّن (settings.AUTH_USER_MODEL)، فتذكر استيراد الوحدة settings كما يلي: from django.conf import settings ولِّد بعد ذلك ملفات التهجير Migration Files وطبّقها على قاعدة البيانات باستخدام الأمرين التاليين: python manage.py makemigrations python manage.py migrate إعداد لوحة مدير المدونة الخطوة التالية هي إعداد لوحة المدير، حيث يأتي جانغو مع نظام إدارة مضمَّن معه، ويمكنك استخدامه من خلال التسجيل بمستخدم Superuser باستخدام الأمر التالي: python manage.py createsuperuser يمكنك بعد ذلك الوصول إلى لوحة المدير من خلال الانتقال إلى العنوان ‎http://127.0.0.1:8000/admin/‎. لا تزال لوحة المدير فارغة حاليًا، ولا يوجد بها سوى تبويب الاستيثاق Authentication الذي يمكنك استخدامه لإسناد أدوار مختلفة للمستخدمين، وهذا أمر معقد إلى حد ما ويتطلب مقالًا آخر، لذا لن نتحدث عنه الآن، بل سنركز على كيفية ربط تطبيق المدونة blog بنظام المدير، حيث يجب أن تجد ملفًا بالاسم admin.py ضمن التطبيق blog، لذا أضف إليه الشيفرة البرمجية التالية: from django.contrib import admin from .models import Site, Category, Tag, Post # سجّل نماذجك هنا class CategoryAdmin(admin.ModelAdmin): prepopulated_fields = {"slug": ("name",)} class TagAdmin(admin.ModelAdmin): prepopulated_fields = {"slug": ("name",)} class PostAdmin(admin.ModelAdmin): prepopulated_fields = {"slug": ("title",)} admin.site.register(Site) admin.site.register(Category, CategoryAdmin) admin.site.register(Tag, TagAdmin) admin.site.register(Post, PostAdmin) نستورد في السطر 2 النماذج التي أنشأناها، ثم نسجل النماذج المستوردة باستخدام التابع admin.site.register()‎. لاحظ بعد ذلك وجود شيء إضافي عند تسجيل النموذج Category، وهو الصنف CategoryAdmin الذي عرّفناه في السطر 6، وبالتالي يمكنك تمرير بعض المعلومات الإضافية إلى نظام الإدارة في جانغو. يمكنك استخدام الميزة prepopulated_fields لتوليد أسماء لطيفة Slugs لجميع الفئات والوسوم والمنشورات، حيث تعتمد قيمة slug على الاسم name، ولنختبر ذلك من خلال إنشاء فئة جديدة. انتقل إلى العنوان ‎http://127.0.0.1:8000/admin/‎، وانقر على الفئات Categories، وأضف فئة جديدة. تذكّر أننا حددنا صيغة الجمع للكلمة Category في نموذجنا، فإن لم نفعل ذلك، فسيستخدم جانغو الجمع Categorys بدلًا من ذلك كما شرحنا سابقًا. لاحظ توليد الاسم اللطيف تلقائيًا عند كتابة الاسم. حاول الآن إضافة بعض البيانات التجريبية، يجب أن يعمل كل شيء بنجاح. عمليات ضبط اختيارية Optional Configurations لم ينتهي عملنا بعد، لذا افتح لوحة الفئات، ستلاحظ أن بإمكانك الوصول إلى الفئات من صفحة المنشور، ولكن لا توجد طريقة للوصول إلى المنشورات المقابلة من صفحة الفئة. لحل هذه المشكلة، يمكنك استخدام الصنف InlineModelAdmin في الملف blog/admin.py كما يلي: class PostInlineCategory(admin.StackedInline): model = Post max_num = 2 class CategoryAdmin(admin.ModelAdmin): prepopulated_fields = {"slug": ("name",)} inlines = [ PostInlineCategory ] أنشأنا أولًا الصنف PostInlineCategory، ثم استخدمناه في CategoryAdmin، وتعني عبارة max_num = 2 عرض منشورين فقط في صفحة الفئة التي ستبدو كما يلي: يمكنك بعد ذلك تطبيق الشيء نفسه مع TagAdmin في الملف blog/admin.py: class PostInlineTag(admin.TabularInline): model = Post.tag.through max_num = 5 class TagAdmin(admin.ModelAdmin): prepopulated_fields = {"slug": ("name",)} inlines = [ PostInlineTag ] لاحظ أن هذه الشيفرة البرمجية مشابهة جدًا لما سبق، ولكن المتغير model ليس Post فقط، بل هو Post.tag.through، لأن العلاقة بين المنشور Post والوسم Tag هي علاقة متعدد إلى متعدد Many-to-Many، وستكون النتيجة النهائية كما يلي: بناء طبقة العروض View ركزنا في الأقسام السابقة على الواجهة الخلفية ولوحة مدير المدونة، وسنركز الآن على جزء الواجهة الأمامية، وهو الجزء الذي يمكن للمستخدمين رؤيته، حيث سنبدأ بدوال العرض View Functions. بما أننا أعددنا لوحة المدير لمدونتنا، فلن نحتاج إلى إنشاء عمليات CRUD الكاملة، وبالتالي وسنهتم فقط بكيفية استرداد المعلومات من قاعدة البيانات. سنحتاج إلى أربع صفحات هي: الصفحة الرئيسية وصفحة الفئة وصفحة الوسم وصفحة المنشور، وسنحتاج إلى دالة عرض واحدة لكلٍّ منها. عرض الصفحة الرئيسية home ضع المحتويات التالية في الملف blog/views.py: from .models import Site, Category, Tag, Post def home(request): site = Site.objects.first() posts = Post.objects.all().filter(is_published=True) categories = Category.objects.all() tags = Tag.objects.all() return render(request, 'home.html', { 'site': site, 'posts': posts, 'categories': categories, 'tags': tags, }) نستورد في السطر 1 النماذج التي أنشأناها في المقال السابق. يحتوي الموقع في السطر 4 على المعلومات الأساسية لموقعنا، حيث نسترد دائمًا السجل الأول من قاعدة البيانات. يضمن التابع filter(is_published=True)‎ في السطر 5 عرض المقالات المنشورة فقط. بعد ذلك علينا تجهيز موجّه إرسال Dispatcher لعنوان URL المقابل لهذه الصفحة في الملف djangoBlog/urls.py كما يلي: path('', views.home, name='home'), عرض الفئة category ضع أيضًا المحتويات التالية في الملف blog/views.py: def category(request, slug): site = Site.objects.first() posts = Post.objects.filter(category__slug=slug).filter(is_published=True) requested_category = Category.objects.get(slug=slug) categories = Category.objects.all() tags = Tag.objects.all() return render(request, 'category.html', { 'site': site, 'posts': posts, 'category': requested_category, 'categories': categories, 'tags': tags, }) وتذكر تجهيز موجّه إرسال عنوان URL المقابل لهذه الصفحة في الملف djangoBlog/urls.py كما يلي: path('category/<slug:slug>', views.category, name='category'), مرّرنا متغيرًا إضافيًا هو slug من عنوان URL إلى دالة العرض، واستخدمنا هذا المتغير في السطرين 3 و 4 من الشيفرة البرمجية السابقة للعثور على الفئة والمنشورات الصحيحة. عرض الوسم tag ضع أيضًا المحتويات التالية في الملف blog/views.py: def tag(request, slug): site = Site.objects.first() posts = Post.objects.filter(tag__slug=slug).filter(is_published=True) requested_tag = Tag.objects.get(slug=slug) categories = Category.objects.all() tags = Tag.objects.all() return render(request, 'tag.html', { 'site': site, 'posts': posts, 'tag': requested_tag, 'categories': categories, 'tags': tags, }) تذكر تجهيز موجّه إرسال عنوان URL المقابل لهذه الصفحة في الملف djangoBlog/urls.py كما يلي: path('tag/<slug:slug>', views.tag, name='tag'), عرض المنشور post ضع أيضًا المحتويات التالية في الملف blog/views.py: def post(request, slug): site = Site.objects.first() requested_post = Post.objects.get(slug=slug) categories = Category.objects.all() tags = Tag.objects.all() return render(request, 'post.html', { 'site': site, 'post': requested_post, 'categories': categories, 'tags': tags, }) وتذكر تجهيز موجّه إرسال عنوان URL المقابل لهذه الصفحة في الملف djangoBlog/urls.py كما يلي: path('post/<slug:slug>', views.post, name='post'), إنشاء طبقة القوالب Template يمكنك استخدام قالب جاهز، فنحن في هذه السلسة لا نركز على لغتي HTML و CSS. وستكون بنية القالب الذي سنستخدمه كما يلي: templates ├── category.html ├── home.html ├── layout.html ├── post.html ├── search.html ├── tag.html └── vendor ├── list.html └── sidebar.html يحتوي الملف layout.html على ترويسة وتذييل الصفحة، وهو المكان الذي نستورد فيه عادة أكواد التنسيقات CSS وأكواد جافا سكريبت JavaScript. وتوجهنا دوال العرض إلى القوالب home و category و tag و post، وتتوسّع جميعها إلى القالب layout الذي يعتبر كأساس لها جميعًا. وتتواجد المكونات التي ستظهر عدة مرات في قوالب مختلفة ضمن المجلد vendor، ويمكنك استيرادها باستخدام الوسم include. قالب التخطيط Layout ضع المحتويات التالية في الملف layout.html: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> {% load static %} <link rel="stylesheet" href="{% static 'style.css' %}" /> {% block title %}{% endblock %} </head> <body class="container mx-auto font-serif"> <nav class="flex flex-row justify-between h-16 items-center border-b-2"> <div class="px-5 text-2xl"> <a href="/"> My Blog </a> </div> <div class="hidden lg:flex content-between space-x-10 px-10 text-lg"> <a href="https://github.com/ericnanhu" class="hover:underline hover:underline-offset-1" >GitHub</a > <a href="#" class="hover:underline hover:underline-offset-1">Link</a> <a href="#" class="hover:underline hover:underline-offset-1">Link</a> </div> </nav> {% block content %}{% endblock %} <footer class="bg-gray-700 text-white"> <div class="flex justify-center items-center sm:justify-between flex-wrap lg:max-w-screen-2xl mx-auto px-4 sm:px-8 py-10" > <p class="font-serif text-center mb-3 sm:mb-0"> Copyright © <a href="https://www.ericsdevblog.com/" class="hover:underline" >Eric Hu</a > </p> <div class="flex justify-center space-x-4"> . . . </div> </div> </footer> </body> </html> لاحظ في السطرين 7 و 8 الطريقة التي يمكنك بها استيراد الملفات الساكنة ملفات CSS و جافا سكريبت في جانغو، فكما وضحنا لن نتحدث في هذا المقال عن لغة CSS، ولكن ما يهمنا هو معرفة طريقة استيراد ملفات CSS إضافية لتطبيق جانغو. سيبحث جانغو عن الملفات الساكنة Static Files في مجلدات التطبيق الفردية افتراضيًا، حيث سيذهب إلى المجلد ‎/blog‎ في تطبيقنا blog، ويبحث عن المجلد static، ثم يبحث عن الملف style.css ضمن المجلد static كما هو محدد في القالب. blog ├── admin.py ├── apps.py ├── __init__.py ├── migrations ├── models.py ├── static │ ├── input.css │ └── style.css ├── tests.py └── views.py قالب الصفحة الرئيسية Home ضع المحتويات التالية في الملف home.html: {% extends 'layout.html' %} {% block title %} <title>Page Title</title> {% endblock %} {% block content %} <div class="grid grid-cols-4 gap-4 py-10"> <div class="col-span-3 grid grid-cols-1"> <!-- المنشور البارز --> <div class="mb-4 ring-1 ring-slate-200 rounded-md hover:shadow-md"> <a href="{% url 'post' featured_post.slug %}" ><img class="float-left mr-4 rounded-l-md object-cover h-full w-1/3" src="{{ featured_post.featured_image.url }}" alt="..." /></a> <div class="my-4 mr-4 grid gap-2"> <div class="text-sm text-gray-500"> {{ featured_post.created_at|date:"F j, o" }} </div> <h2 class="text-lg font-bold">{{ featured_post.title }}</h2> <p class="text-base"> {{ featured_post.content|striptags|truncatewords:80 }} </p> <a class="bg-blue-500 hover:bg-blue-700 rounded-md p-2 text-white uppercase text-sm font-semibold font-sans w-fit focus:ring" href="{% url 'post' featured_post.slug %}" >Read more →</a > </div> </div> {% include "vendor/list.html" %} </div> {% include "vendor/sidebar.html" %} </div> {% endblock %} لاحظ أننا فصلنا الشريط الجانبي وقائمة المنشورات ووضعناها في المجلد vendor بدلًا من كتابة شيفرتها البرمجية الثابتة، إذ سنستخدم المكونات نفسها في صفحة الفئة والوسم. قائمة المنشورات ضع أيضًا المحتويات التالية في الملف vendor/list.html: <!-- قائمة المنشورات --> <div class="grid grid-cols-3 gap-4"> {% for post in posts %} <!-- المنشور --> <div class="mb-4 ring-1 ring-slate-200 rounded-md h-fit hover:shadow-md"> <a href="{% url 'post' post.slug %}" ><img class="rounded-t-md object-cover h-60 w-full" src="{{ post.featured_image.url }}" alt="..." /></a> <div class="m-4 grid gap-2"> <div class="text-sm text-gray-500"> {{ post.created_at|date:"F j, o" }} </div> <h2 class="text-lg font-bold">{{ post.title }}</h2> <p class="text-base"> {{ post.content|striptags|truncatewords:30 }} </p> <a class="bg-blue-500 hover:bg-blue-700 rounded-md p-2 text-white uppercase text-sm font-semibold font-sans w-fit focus:ring" href="{% url 'post' post.slug %}" >Read more →</a > </div> </div> {% endfor %} </div> لاحظ في الأسطر من 3 إلى 27 كيف مرّرنا المتغير posts من العرض إلى القالب، حيث يحتوي هذا المتغير على مجموعة من المنشورات، وسنقوم بالمرور ضمن القالب على كل عنصر في هذه المجموعة باستخدام حلقة for. تذكّر في السطر 6 أننا أنشأنا موجّه إرسال عنوان URL كما يلي: path('post/<slug:slug>', views.post, name='post'), ستجد التعليمة ‎{% url 'post' post.slug %}‎ في القالب موجّهَ إرسال عنوان URL بالاسم 'posts'، وتسند القيمة post.slug إلى المتغير ‎<slug:slug>‎، والذي سيُمرَّر بعد ذلك إلى دالة العرض المقابلة. ينسّق المرشّح Filter الذي هو date في السطر 14 بيانات التاريخ المُمرَّرة إلى القالب لأن القيمة الافتراضية ليست سهلة الاستخدام، ويمكنك العثور على تنسيقات تواريخ أخرى في توثيق جانغو الرسمي. وضعنا مرشحَين بعد post.content في السطر 18، حيث يزيل المرشّح الأول وسوم HTML، ويأخذ المرشّح الثاني أول 30 كلمة ويقتطع الباقي. قالب الشريط الجانبي Sidebar ضع أيضًا المحتويات التالية في الملف vendor/sidebar.html: <div class="col-span-1"> <div class="border rounded-md mb-4"> <div class="bg-slate-200 p-4">Search</div> <div class="p-4"> <form action="" method="get"> <input type="text" name="search" id="search" class="border rounded-md w-44 focus:ring p-2" placeholder="Search something..."> <button type="submit" class="bg-blue-500 hover:bg-blue-700 rounded-md p-2 text-white uppercase font-semibold font-sans w-fit focus:ring">Search</button> </form> </div> </div> <div class="border rounded-md mb-4"> <div class="bg-slate-200 p-4">Categories</div> <div class="p-4"> <ul class="list-none list-inside"> {% for category in categories %} <li> <a href="{% url 'category' category.slug %}" class="text-blue-500 hover:underline" >{{ category.name }}</a > </li> {% endfor %} </ul> </div> </div> <div class="border rounded-md mb-4"> <div class="bg-slate-200 p-4">Tags</div> <div class="p-4"> {% for tag in tags %} <span class="mr-2" ><a href="{% url 'tag' tag.slug %}" class="text-blue-500 hover:underline" >{{ tag.name }}</a ></span > {% endfor %} </div> </div> <div class="border rounded-md mb-4"> <div class="bg-slate-200 p-4">More Card</div> <div class="p-4"> <p> . . . </p> </div> </div> </div> قالب الفئة Category ضع المحتويات التالية في الملف category.html: {% extends 'layout.html' %} {% block title %} <title>Page Title</title> {% endblock %} {% block content %} <div class="grid grid-cols-4 gap-4 py-10"> <div class="col-span-3 grid grid-cols-1"> {% include "vendor/list.html" %} </div> {% include "vendor/sidebar.html" %} </div> {% endblock %} قالب الوسم Tag ضع المحتويات التالية في الملف tag.html: {% extends 'layout.html' %} {% block title %} <title>Page Title</title> {% endblock %} {% block content %} <div class="grid grid-cols-4 gap-4 py-10"> <div class="col-span-3 grid grid-cols-1"> {% include "vendor/list.html" %} </div> {% include "vendor/sidebar.html" %} </div> {% endblock %} قالب المنشور Post أخيرًا، يتضمن قالب المنشور المحتويات التالية: {% extends 'layout.html' %} {% block title %} <title>Page Title</title> {% endblock %} {% block content %} <div class="grid grid-cols-4 gap-4 py-10"> <div class="col-span-3"> <img class="rounded-md object-cover h-96 w-full" src="{{ post.featured_image.url }}" alt="..." /> <h2 class="mt-5 mb-2 text-center text-2xl font-bold">{{ post.title }}</h2> <p class="mb-5 text-center text-sm text-slate-500 italic">By {{ post.user|capfirst }} | {{ post.created_at }}</p> <div>{{ post.content|safe }}</div> <div class="my-5"> {% for tag in post.tag.all %} <a href="{% url 'tag' tag.slug %}" class="text-blue-500 hover:underline" mr-3">#{{ tag.name }}</a> {% endfor %} </div> </div> {% include "vendor/sidebar.html" %} </div> {% endblock %} لاحظ في السطر 19 أننا أضفنا المرشح safe، لأن جانغو سيعرض شيفرة HTML كنص عادي افتراضيًا لأسباب أمنية، لذا يجب ان نخبر جانغو بأنه يمكن عرض شيفرات HTML كما هي. أصبح كل شيءجاهزًا، كل ما عليك الأن هو تشغيل خادم التطوير باستخدام الأمر التالي، وعرض تطبيق جانغو الأول الخاص بك: python manage.py runserver ترجمة -وبتصرّف- للمقال Django for Beginners #4 - The Blog App لصاحبه Eric Hu. اقرأ أيضًا المقال السابق: استخدام عمليات CRUD لإدارة مدونة في جانغو إنشاء تطبيق جانغو وتوصيله بقاعدة بيانات إنشاء موقع ويب هيكلي بجانغو رفع مستوى أمان تطبيقات جانغو في بيئة الإنتاج البدء مع إطار العمل جانغو لإنشاء تطبيق ويب
    1 نقطة
  2. يُعد عنوان URL بالإضافة إلى النص التشعبي Hypertext وبروتوكول HTTP أحد المفاهيم المفتاحية للويب فهو الآلية التي تستخدمها المتصفحات browsers للوصول أي مورد موجود في الويب. عنوان URL هو مجرّد عنوان فريد لمورد على الويب، نظريًا يدل كل عنوان URL صحيح على مورد فريد ومحدد كصفحة HTML أو ملف CSS أو صورة أو غيرها من الموارد، ولكن في واقع هناك بعض الاستثناءات، وأكثرها شيوعًا عنوان URL يشير إلى مورد لم يعد موجودًا أو تغيّر موقعه. وطالما أن المورد يُمثّل بعنوان URL والخادم هو من يتعامل مع عنوان URL فلذلك تقع على عاتق مالك الخادم مهمة إدارة الموارد وعناوين URL المرتبطة بها بعناية. سنتعرف في هذا المقال على تفاصيل عنوان URL وكيفية عمل هذه العناوين على الويب. ننصحك قبل الشروع في إكمال قراءة المقال أن تطلع على مقال كيف تعمل شبكة الإنترنت؟ وأن يكون مفهوم الروابط التشعبية واضحًا بالنسبة لك. تشريح عنوان URL إليك بعض الأمثلة عن عناوين URL: https://developer.mozilla.org https://developer.mozilla.org/en-US/docs/Learn/ https://developer.mozilla.org/en-US/search?q=URL يمكن كتابة أيًا من تلك العناوين في شريط العنوان في المتصفح لتحميل الصفحة أو المورد المرتبط به. يتكون عنوان URL من أجزاء مختلفة بعضها إلزامي وبعضها اختياري. لاحظ الأجزاء المظللة في العنوان التالي والتي تُعد الأكثر أهمية في عنوان URL: لتوضيح الفكرة يمكن أن نشبّه عنوان URL بعنوان بريدي نمطي، إذ يمثل المخطط Scheme الخدمة البريدية التي تريد استخدامها، ويمثل اسم النطاق Domain name اسم المدينة أو البلدة، وستعمل المنفذ Port عمل الرمز البريدي، وسيمثل المسار Path البناء الذي ينبغي تسليم البريد إليه. أما المعاملات Parameters فستمثل أي معلومات إضافية كرقم الشقة وستمثل المرساة Anchor مستلم الرسالة الفعلي الذي وجَّهت رسالتك إليه. بروتوكول عنوان URL وهو القسم الأول من URL ويشير إلى البروتوكول الذي ينبغي استخدامه لطلب مورد معين من الخادم (البروتوكول هو طريقة لإعداد آلية لتبادل البيانات ونقلها عبر شبكة من الحواسيب). يُستخدم عادة برتوكولي HTTP و HTTPS (النسخة الآمنة) في مواقع الويب ولا بد من مخاطبة صفحات الويب باستخدام أحدهما. مع ذلك تدرك المتصفحات تمامًا كيف تتعامل مع بروتوكولات Schemes أخرى مثل :mailto (لفتح واجهة بريد إلكتروني) فلا تتفاجأ إن رأيت بروتوكولات أخرى. التصريح Authority يأتي بعد البروتوكول التصريح ويفصل بينهما النمط //:. يتضمن التصريح في حال وجوده اسم النطاق (www.example.com مثلًا) ورقم المنفذ (80 مثلًا) يفصل بينهما الرمز :. يشير النطاق Domain إلى خادم الويب الذي يُرسل إليه الطلب ويكون عادة على شكل اسم، كما يمكن استخدام عنوان آي بي لكن استخدامه نادر وغير ملائم في معظم الأحيان. يشير المنفذ Port إلى البوابة المستخدمة للوصول إلى المورد. يُحذف المنفذ عادة عند استخدام الخادم المنافذ المعيارية للبروتوكول HTTP، إذ يستخدم المنفذ 80 لبروتوكول HTTP والمنفذ 443 لبروتوكول HTTPS عند منح الإذن بالوصول إلى المورد. ما عدا ذلك لا بد من كتابة المنفذ المستخدم. في بعض الحالات لا يستخدم URL قسم التصريح كما هو الحال في واجهات البريد الإلكتروني (mailto:foobar). إذ يحتوي URL مخططًا فقط دون تصريح، لذلك لن تجد النمط //، وإنما ستجد فقط النقطتين المتعامدتين التي تعمل فقط كفاصل بين المخطط وعنوان البريد الإلكتروني. المسار إلى مورد ويمثل الطريق للوصول إلى مورد موجود على خادم ويب (path/to/myfile.html/‎ مثلًا). مثَّلت هذه المسارات في بدايات الويب الموقع الفيزيائي لملف على خادم، لكنه حاليًا مجرد اختصار يتعامل معه الخادم بطريقة معينة للوصول إلى المورد وغالبًا لا يشير إلى المكان الحقيقي لوجود المورد. المعاملات وهي قائمة من العناصر الثنائية على شكل"مفتاح/قيمة" يفصل بينها الرمز & مثل القائمة key1=value1&key2=value2 كما في الصورة السابقة. يمكن لخادم ويب استخدام هذه المعاملات في تنفيذ عمليات إضافية قبل أن يعيد المورد المطلوب. لكل خادم ويب قواعده الخاصة المتعلقة بمعالجة المعاملات، ومن الأفضل دومًا أن تسأل مالك الخادم عن طريقة تعامل خادمه مع المعاملات. المربط يمثل المربط # (ويشار إليه المرساة أحيانًا) طريقة للاشارة إلى جزء معين من المورد نفسه، وتشبه فكرته فكرة "الاشارة المرجعية" داخل المورد نفسه. فلو كان المورد ملف HTML مثلًا، سينتقل المتصفح إلى النقطة التي يُعرّفها المربط "#"، وفي حال كان المربط يشير إلى نقطة زمنية معينة من ملفات الصوتية أو الفيديو سيحاول المتصفح الانتقال إلى الزمن الذي يحدده المربط. وتجدر الإشارة هنا، إلى أن القسم الذي يقع بعد الرمز "#" (ويُدعى "مُعرِّف القطعة Fragment Identifier") لن يُرسل أبدًا إلى الخادم مع الطلب. كيف تستخدم URL بإمكانك كتابة أي URL ضمن شريط العنوان في المتصفح لتحضر المورد الذي يمثله، لكن هذا الاستخدام ما هو إلا رأس الهرم فقط! تستخدم لغة HTML عناوين URL بكثرة لكي: تنشئ روابطًا مع مستندات أخرى باستخدام العنصر <a>. تربط مستندًا مع موارده عبر عناصر متعددة مثل <link> أو <script>. تعرض الوسائط مثل الصور (باستخدام العنصر <img>) والفيديو (باستخدام العنصر <video>) والملفات الصوتية (باستخدام العنصر<audio>). تعرض ملفات HTML أخرى باستخدام العنصر <iframe>. تستخدم التقنيات الأخرى مثل CSS وJavaScript عناوين URL بكثرة أيضًا، وهذه التقنيات هي ما تشكل الويب في الواقع. عناوين URL المطلقة والنسبية تُعد الأمثلة التي أوردناها سابقًا عن عنوان URL عناوينًا مطلقة Absolute URLs، لكن لا يزال هناك نمط آخر وهي العناوين النسبية Relative URLs ولا بدّ من الإشارة إلى الفوارق بينهما بشيء من التفصيل. تعتمد الأجزاء التي ينبغي استخدامها من عنوان URL والأخرى التي يمكن إهمالها على السياق الذي يستخدم فيه عنوان URL. فمثلًا في شريط عنوان متصفحك لا يوجب أي سياق محدد لعناوين URL لهذا لا بدّ من كتابة URL بشكله الكامل (أو المطلق) كما فعلنا في الأمثلة السابقة. لا حاجة بالطبع في حالة المتصفح أن تذكر البروتوكول لأن المتصفح يستخدم البروتوكول HTTP افتراضيًا، ولا نذكر أيضًا المنفذ الذي نحتاجه إلا في الحالة التي نتصل فيها مع الخادم عبر منفذ غير اعتيادي، ولكن لا بد من كتابة بقية أجزاء عنوان URL. عندما يُستخدم عنوان URL داخل مستند كصفحة HTML ستختلف الأمور قليلًا. إذ يمتلك المتصفح في هذه الحالة عنوان URL الخاص بالمستند ككل، وبالتالي سيتمكن من استخدام معلوماته لإكمال الأجزاء الناقصة لعنوان URL الموجود داخل المستند. يمكن التمييز بين عنوان URL المطلق والنسبي بالنظر فقط إلى جزء المسار، فإذا بدأ عنوان URL بالرمز / فسيحضر المتصفح المورد من أعلى عنوان جذري للخادم دون الحاجة إلى المكان الذي يشير إليه المستند. لنلق نظرة على بعض الأمثلة لتوضيح الأمر. أمثلة عن عناوين URL مطلقة يُعد العنوان الآتي مطلقًا أو كاملًا https://developer.mozailla.org/docs/learn بينما يعد العنوان التالي غير كامل إذ سيستخدم هذا العنوان البروتوكول الضمني للمستند الذي يتضمن عنوان URL. developer.mozilla.org/en-us/docs/Learn// أما العنوان الآتي فهو اسم نطاق ضمني، وهي الحالة الأكثر استخدامًا لعناوين URL المطلقة داخل مستندات HTML. /en-us/docs/learn/ يستخدم المتصفح في هذه الحالة نفس البروتوكول واسم النطاق المستخدمان في تحميل المستند الذي يحتوي على عنوان URL لاحظ أنه لا يمكن حذف اسم النطاق دون حذف البروتوكول أيضًا. أمثلة عن عناوين URL نسبية لتفهم الأمثلة التالية بطريقة صحيحة، سنفترض أن عناوين URL ستُستدعى من داخل المستند الموجود على عنوان URL التالي: https://developer.mozilla.org/en-us/docs/Learn يستخدم العنوان "Skills/Infrastructure/Understanding_URLs" فكرة الموارد الفرعية، فطالما أنّ عنوان URL لم يبدأ بالرمز / سيحاول المتصفح أن يجد المستند في مجلد فرعي ضمن المجلد الذي يحتوي المورد الحالي أي سنرغب في مثالنا في الوصول إلى عنوان URL التالي: https://developer.mozilla.org/en-us/docs/Learn/Skills/Infrastructure/Understanding_URLs. بينما يستخدم العنوان "‎../CSS/display" فكرة التراجع إلى الخلف في مسار الشجرة، ونستخدم في هذه الحالة النمط /.. الموروث من نظام ملفات يونكس لكي نخبر المتصفح أن ينتقل إلى المجلد الأعلى مباشرة. أي أننا نريد هنا الوصول إلى عنوان URL التالي: https://developer.mozilla.org/en-US/docs/Learn/../CSS/display والذي يمكن اختصاره إلى: https://developer.mozilla.org/en-US/docs/CSS/display عناوين URL الدلالية بالرغم من الصبغة التقنية الواضحة لهذا النوع، إلا أن عناوين URL الدلالية Semantic URLs هي طريقة دخول إلى موقع ويب معين يمكن للبشر فهمها. أي يمكن أن يحفظها المستخدم بسهولة ويدخلها بنفسه في شريط عنوان المتصفح، وطالما أنّ المستخدمين هم مركز اهتمام الويب، فمن أفضل الممارسات التي ينبغي نشرها هي بناء ما يُدعى عناوين URL واضحة ومقروءة Clean URL، وهي عناوين تستخدم كلمات في صلب موضوع محتوى العناوين يمكن لأي شخص فهمها دون أن تكون لديه أي فكرة تقنية عن كيفية إنجاز الأمر. لا علاقة بالطبع للدلالات اللغوية بالحواسيب، فلربما بدت لك عناوين URL كخليط من الرموز العشوائية، لكن هناك إيجابيات عدة لكتابة URL مقروء من قبل المستخدم منها: سهولة تعديلها. تجعل الكثير من النقاط أكثر وضوحًا للمستخدم مثل الموقع الذي يتواجد فيه وما الذي يفعله في هذا الموقع أو ما الذي يقرأه أو يتفاعل معه على الويب. يمكن لعناوين URL المقروءة أن تحسن ترتيب وتصنيف الصفحات في محركات البحث. ترجمة -وبتصرف- للمقال What is a URL. اقرأ أيضًا ما هو خادم الويب؟ ما هي الأدوات المستخدمة في بناء مواقع ويب؟ ما هي أدوات مطوري الويب المدمجة في المتصفحات؟ ما هي أسماء النطاقات في شبكة الإنترنت؟
    1 نقطة
×
×
  • أضف...