-
سه شنبه, ۳۰ آذر ۱۴۰۰، ۱۱:۴۵ ب.ظ
-
۶۰۹
سلام دوستان :)
توی پست امروز قراره با هم نحوه ساخت یک encyclopedia رو ببینیم.
خب اول شاید از خودتون بپرسین که encyclopedia یعنی چی؟ encyclopedia در واقع یک جور دایرة المعارف آنلاین هست، مثل wikipedia.
توی قسمت اول این پست قراره اول با هم کد های back-end (همون Django) رو ببینیم و توی قسمت دوم هم با هم طراحی front-end (که حتما خودتون میدونین با HTML و CSS هست).
خب توی پست های (ساخت پلتفرم mail با Django - قسمت اول) و (ساخت پلتفرم mail با Django - قسمت دوم) ساختار اولیه Django (نحوه ساخت پروژه، اپلیکیشن، فایل های مهم توی پروژه و نحوه اجرا کردن پروژه) آشنا شدیم.
پس حالا باید اول یک پروژه (project) به اسم wiki درست کنیم که پروژه رو داخلش قرار بدیم. حالا داخل project که ساختین یک app به اسم encyclopedia ایجاد کنین.
حالا بعد از درست کردن project و app بریم ببینیم این encyclopedia ما اصلا چجوری کار میکنه :))
خب شاید با خودتون فکر کنین که یک دیتابیس هست که توی تمام اطلاعات مربوط به چیز های مختلف قرار گرفته و... ولی باید بگم که اشتباه فکر کردین!
من ترجیح دادم توی این پروژه به جای استفاده از دیتابیس و الکی پیچیده کردن کار خیلی راحت یک فولدر درست کنم که چند تا فایل .md توشون باشه.
این کار یک برتری خیلی مهم نسبت به استفاده از دیتابیس داره اونم اینه که احتمالا حدس زدین که الکی فرمت فایل ها رو md نذاشتیم بلکه بخاطر این که بتونیم از markdown language استفاده کنیم.
خوبی این کار اینه که بجای استفاده از کد های پیچیده HTML و... خیلی راحت از بلوک های کد ساده markdown استفاده کنیم و با استفاده از ماژول markdown2 اون ها رو تبدیل به HTML کنیم و در نهایت به عنوان خروجی نمایشش بدیم. پس قبل از اینکه markdown رو توضیح بدم برین و ماژول markdown2 رو نصب کنین.
خب مثلا یک تیکه کد از markdown به این شکل هست:
#وبلاگ فربد
خروجی HTML این کد بصورت زیره:
<h1> وبلاگ فربد </h1>
البته خیلی خیلی کد های بیشتری هست که میتونین توی سایت اصلی خود markdown اون ها رو بخونین و من اگه الان بخوام بگن تا صبح طول میکشه :)))
خب حالا بریم سراغ بحث اصلیمون.
قرار شد که به جای database از فایل های md استفاده کنیم. اما بقیه پروژه چی؟؟؟ کل encyclopedia که همین نیست!
پروژه بخش های دیگه هم داره مثل بخش اضافه کردن صفحه جدید، ویرایش صفحه، و انتخاب تصادفی صفحه هم هست.
پس بریم کار اصلی پروژه رو انجام بدیم.
فایل urls.py رو باز کنین و کد های زیر رو داخلش قرار بدین:
from django.urls import path from . import views urlpatterns = [ path("", views.index, name="index"), path("wiki/<title>", views.entry, name="entry"), path("search", views.search, name="search"), path("random", views.random_page, name="random"), path("create", views.create, name="create"), path("edit/<title>", views.edit, name="edit"), ]
توضیح: خب کد خیلی واضح هست و ما اومدیم path هامون رو تعریف کردیم و برای هر کدومشون آدرس یک تابع توی فایل views.py رو دادیم.
حالا فایل views.py رو باز کنین و کد های زیر رو داخلش قرار بدین:
from django.shortcuts import render, redirect from markdown2 import markdown from . import util from random import randint import re def listToString(s): str1 = "" for ele in s: str1 += ele return str1 def index(request): return render(request, "encyclopedia/index.html", { "entries": util.list_entries() }) def entry(request, title): content = util.get_entry(title.strip()) if content == None: return render(request, "encyclopedia/not_found.html") content = markdown(content) return render(request, "encyclopedia/entry.html", {'content': content, 'title': title}) def search(request): search_value = request.GET['q'] if search_value in util.list_entries(): return render(request, "encyclopedia/entry.html", { "content": markdown(util.get_entry(search_value)), "title": search_value }) elif re.search(search_value, listToString(util.list_entries())) is not None: match_list = [] for i in util.list_entries(): if re.search(search_value, i) is not None: match_list.append(i) return render(request, "encyclopedia/search.html", { "page_title": match_list }) else: return render(request, "encyclopedia/search_results_not_found.html") def random_page(request): entries = util.list_entries() random_title = entries[randint(0, len(entries)-1)] return redirect("entry", title=random_title) def create(request): if request.method == "POST": title = request.POST.get("title").strip() content = request.POST.get("content").strip() if title == "" or content == "": return render(request, "encyclopedia/add.html", {"message": "Can't save with empty field.", "title": title, "content": content}) if title in util.list_entries(): return render(request, "encyclopedia/add.html", {"message": "Title already exist. Try another.", "title": title, "content": content}) util.save_entry(title, content) return redirect("entry", title=title) return render(request, "encyclopedia/add.html") def edit(request, title): content = util.get_entry(title.strip()) if content == None: return render(request, "encyclopedia/edit.html", {'error': "404 Not Found"}) if request.method == "POST": content = request.POST.get("content").strip() if content == "": return render(request, "encyclopedia/edit.html", {"message": "Can't save with empty field.", "title": title, "content": content}) util.save_entry(title, content) return redirect("entry", title=title) return render(request, "encyclopedia/edit.html", {'content': content, 'title': title})
خب توی این بخش، اول ماژول های مورد نیازمون رو import کردیم.
و بعد هم توابع مورد نیاز رو تعریف کردیم که اونا هم چیز خاصی ندارن.
اما شاید به یک چیزی توجه کرده باشین،اونم این که ما از یک فایل به اسم util.py استفاده کردیم که اصلا وجود نداره!
علت وجود نداشتنش هم اینه که اصلا جزو فایل های مورد نیاز برای Django نیست و ما خودمون تعریفش میکنیم و توابع مورد نیاز برای اضافه کردن، پاک کردن و لود کردن مقادیر فایل های md رو تعریف کردیم.
پس بریم util.py رو تعریف کنیم که یک وقت خدایی نکرده ارور نده!!
فایل util.py رو درست کنین و کد های زیر رو داخلش قرار بدین:
import re from django.core.files.base import ContentFile from django.core.files.storage import default_storage def list_entries(): """ Returns a list of all names of encyclopedia entries. """ _, filenames = default_storage.listdir("entries") return list(sorted(re.sub(r"\.md$", "", filename) for filename in filenames if filename.endswith(".md"))) def save_entry(title, content): """ Saves an encyclopedia entry, given its title and Markdown content. If an existing entry with the same title already exists, it is replaced. """ filename = f"entries/{title}.md" if default_storage.exists(filename): default_storage.delete(filename) default_storage.save(filename, ContentFile(content)) def get_entry(title): """ Retrieves an encyclopedia entry by its title. If no such entry exists, the function returns None. """ try: f = default_storage.open(f"entries/{title}.md") return f.read().decode("utf-8") except FileNotFoundError: return None def search(query): """ Returns a list of all names of encyclopedia entries containing the search query """ _, filenames = default_storage.listdir("entries") return list(sorted(re.sub(r"\.md$", "", filename) for filename in filenames if filename.endswith(".md") and query in filename.lower()))
توضیح: خب اول ماژول های مورد نیازمون رو import کردیم (اول regex و بعد هم ماژول های مورد نیاز برای استفاده از فایل ها) و بعد هم توابع مورد نیازمون رو برای استفاده از فایل ها تعریف کردیم.
خب بخش اول این پروژه (بخش back-end) تموم شد.
بخش front-end رو در قسمت بعدی طراحی خواهیم کرد.
امیدوارم براتون مفید بوده باشه D: