-
چهارشنبه, ۳۱ شهریور ۱۴۰۰، ۱۱:۱۱ ق.ظ
-
۷۵۴
سلام دوستان:)
توی پست امروز قراره با هم یک پلتفرم mail با استفاده از API با django بسازیم!
خب این پروژه رو توی دو قسمت براتون میذارم.
قسمت اول مربوط به طراحی بخش back-end میشه و بخش دوم مربوط به طراحی front-end.
خب اول از همه بدونیم که django چیه؟
جنگو یک فریم ورک تحت وب آزاد و متن باز هستش که به زبان پایتون طراحی شده و از معماری Model-View-Template استفاده میکنه.
حالا بریم سراغ نصب جنگو
برای نصب این کتابخونه توی ویندوز برین توی cmd و دستور زیر رو وارد کنین:
pip install django
برای نصب این کتابخونه توی لینوکس هم برین توی ترمینال و دستور زیر رو وارد کنین:
sudo pip3 install django
خب حالا که این کتابخونه رو نصب کردیم باید یکم با ساختار اون آشنا بشیم.
خب سیستم جنگو به این صورت هستش که ما یک project اصلی داریم که داخل اون یک سری app ها تعریف شده که هر کدوم مسئولیت یک کار رو به عهده میگیرن.
مثلا گوگل رو فرض کنید.
گوگل کلش یک project هست و هر کدوم از بخش های اونم مثل search, images, youtube و.. app های اون هستن.
حالا که با ساختارش آشنا شدیم میتونیم پروژه خودمون رو شروع کنیم.
برای شروع یک پروژه میتونین در هر سیستم عاملی از دستور زیر استفاده کنین:
django-admin startproject project3
بجای project3 میتونین هر اسمی که دوست دارین بذارین ولی اینجا بهتره که همون project3 باشه.
خب حالا میتونین توی cmd یا terminal با استفاده از دستور زیر وارد پوشه ای پروژه داخلش درست شده بشین:
cd project3
خب حالا اگر در ویندوز دستور dir و در لینوکس ls رو وارد کنین، چندین فایل و فولدر میبینین.
یکی از اون فایل ها manage.py هست.
ما میتونیم با استفاده از این فایل دستور های زیادی رو اجرا کنیم که یکی از اونها startapp هستش که برای ما یک app جدید درست می کنه.
پس در cmd یا terminal دستور زیر رو وارد کنین:
python manage.py startapp mail
خب بجای project3 میتونین اسم app خودتون رو بذارین ولی اینجا همون projcet3 باشه بهتره.
خب حالا با استفاده از دستور cd وارد پوشه project3 بشین حالا در ویندوز dir و یا در لینوکس ls رو تایپ کنین.
حالا چندین فایل و پوشه خواهید دید.
فایل views.py مربوط به view هامون میشه. فایل models.py مربوط به model های دیتابیسمون میشه و فایل urls.py هم که بعدا خودمون میسازیمش مربوط به تنظیمات url ما خواهد بود. بقیه فایل ها هم اهمیت ندارن.
خب حالا با یک IDE (بهتون توصیه میکنم از visual studio code استفاده کنین) پوشه project خودتون رو باز کنین.
حالا فایل urls.py (در پوشه project3) باز کنین و مقادیر زیر رو داخلش قرار بدین:
from django.contrib import admin from django.urls import include, path urlpatterns = [ path('admin/', admin.site.urls), path('', include('mail.urls')) ]
اگر دقت کنین یک لیست به نام urlpatterns می بینین. مقدار اول مربوط به پنل ادمین django میشه که بعدا اونو توضیح میدم.
توی مقدار دوم یک path تعریف کردیم که توش گفتیم اگه توی url مقدار خالی وارد شد حالا بیا مقادیر فایل urls.py داخل پوشه mail رو در نظر بگیر.
حالا باید توی پوشه mail یک فایل به نام urls.py بسازین. بعد از اینکه فایل رو ساختین فایل رو باز کنین و مقادیر زیر رو داخلش قرار بدین:
from django.urls import path from . import views urlpatterns = [ path("", views.index, name="index"), path("login", views.login_view, name="login"), path("logout", views.logout_view, name="logout"), path("register", views.register, name="register"), # API Routes path("emails", views.compose, name="compose"), path("emails/<int:email_id>", views.email, name="email"), path("emails/<str:mailbox>", views.mailbox, name="mailbox"), ]
خب دوباره اگر دقت کنین 7 تا path داخل لیست urlpatterns می بینین. اولین path که مربوط به صفحه اصلی سایت میشه. سه تا path بعدی هم مربوط به ورود، ثبت نام و خروج کاربر میشن.
خب همونطور که گفتم ما قراره سایتمون رو بر اساس API طراحی کنیم حالا این یعنی چی؟
این یعنی اینکه ما یک سرور داریم که وقتی به یک آدرس مشخص داخل اون سرور یک request از نوع HTTP داده میشه سرور هم یک جوابی میده و ما میتونیم با استفاده از این نتایجی که سرور به ما داده کار هایی انجام بدیم. که این کار هم بعدا قراره با javascript انجام بدیم.
پس سه تا path بعدی مربوط به API میشن.
خب همونطور که میبینین توی ورودی دوم هر path یکی از توابع داخل فایل views.py رو اجرا میکنیم حالا باید بریم اونارو تعریف کنیم.
خب فایل views.py رو باز کنین و مقادیر زیر رو داخلش قرار بدین:
import json from django.contrib.auth import authenticate, login, logout from django.contrib.auth.decorators import login_required from django.db import IntegrityError from django.http import JsonResponse from django.shortcuts import HttpResponse, HttpResponseRedirect, render from django.urls import reverse from django.views.decorators.csrf import csrf_exempt from .models import User, Email def index(request): # Authenticated users view their inbox if request.user.is_authenticated: return render(request, "mail/inbox.html") # Everyone else is prompted to sign in else: return HttpResponseRedirect(reverse("login")) @csrf_exempt @login_required def compose(request): # Composing a new email must be via POST if request.method != "POST": return JsonResponse({"error": "POST request required."}, status=400) # Check recipient emails data = json.loads(request.body) emails = [email.strip() for email in data.get("recipients").split(",")] if emails == [""]: return JsonResponse({ "error": "At least one recipient required." }, status=400) # Convert email addresses to users recipients = [] for email in emails: try: user = User.objects.get(email=email) recipients.append(user) except User.DoesNotExist: return JsonResponse({ "error": f"User with email {email} does not exist.", "status": 400 }, status=400) # Get contents of email subject = data.get("subject", "") body = data.get("body", "") # Create one email for each recipient, plus sender users = set() users.add(request.user) users.update(recipients) for user in users: email = Email( user=user, sender=request.user, subject=subject, body=body, read=user == request.user ) email.save() for recipient in recipients: email.recipients.add(recipient) email.save() return JsonResponse({"message": "Email sent successfully.", "status": 201}, status=201) @login_required def mailbox(request, mailbox): # Filter emails returned based on mailbox if mailbox == "inbox": emails = Email.objects.filter( user=request.user, recipients=request.user, archived=False ) elif mailbox == "sent": emails = Email.objects.filter( user=request.user, sender=request.user ) elif mailbox == "archive": emails = Email.objects.filter( user=request.user, recipients=request.user, archived=True ) else: return JsonResponse({"error": "Invalid mailbox."}, status=400) # Return emails in reverse chronologial order emails = emails.order_by("-timestamp").all() return JsonResponse([email.serialize() for email in emails], safe=False) @csrf_exempt @login_required def email(request, email_id): # Query for requested email try: email = Email.objects.get(user=request.user, pk=email_id) except Email.DoesNotExist: return JsonResponse({"error": "Email not found."}, status=404) # Return email contents if request.method == "GET": return JsonResponse(email.serialize()) # Update whether email is read or should be archived elif request.method == "PUT": data = json.loads(request.body) if data.get("read") is not None: email.read = data["read"] if data.get("archived") is not None: email.archived = data["archived"] email.save() return HttpResponse(status=204) # Email must be via GET or PUT else: return JsonResponse({ "error": "GET or PUT request required." }, status=400) def login_view(request): if request.method == "POST": # Attempt to sign user in email = request.POST["email"] password = request.POST["password"] user = authenticate(request, username=email, password=password) # Check if authentication successful if user is not None: login(request, user) return HttpResponseRedirect(reverse("index")) else: return render(request, "mail/login.html", { "message": "Invalid email and/or password." }) else: return render(request, "mail/login.html") def logout_view(request): logout(request) return HttpResponseRedirect(reverse("index")) def register(request): if request.method == "POST": email = request.POST["email"] # Ensure password matches confirmation password = request.POST["password"] confirmation = request.POST["confirmation"] if password != confirmation: return render(request, "mail/register.html", { "message": "Passwords must match." }) # Attempt to create new user try: user = User.objects.create_user(email, email, password) user.save() except IntegrityError as e: print(e) return render(request, "mail/register.html", { "message": "Email address already taken." }) login(request, user) return HttpResponseRedirect(reverse("index")) else: return render(request, "mail/register.html")
خب اول توابع مورد نیاز رو import کردیم بعد از اون تابع index رو تعریف کردیم که میگه اگر user وارد شده بود فایل inbox.html رو برگردونه. اگر هم وارد نشده بود صفحه لاگین رو بیاره.
حالا تابع compose رو برای فرستادن ایمیل تعریف کردیم و داخلش گفتیم ایمیلی که فرستاده شده، کسی که اون ایمیل رو فرستاده و کسی که اون ایمیل رو دریافت میکنه داخل دیتابیس ذخیره کنه. بعد هم متن Email Sent Successfully رو با فرمت json بر میگردونه.
بعد تابع mailbox رو تعریف کردیم که داخلش گفتیم mailbox مورد نظر (مثل inbox, sent, archived) رو load کنه و مقادیر اون رو بصورت json برگردونه.
حالا تابع email رو تعریف کردیم که هر mail رو بر اساس primary key اون mail بصورت json بر میگردونه.
سه تا تابع بعدی هم مربوط به login, register و logout کاربر میشن.
خب حالا بریم سراغ فایل models.py.
فایل models.py رو باز کنین و مقادیر زیر رو داخلش قرار بدین:
from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): pass class Email(models.Model): user = models.ForeignKey( "User", on_delete=models.CASCADE, related_name="emails") sender = models.ForeignKey( "User", on_delete=models.PROTECT, related_name="emails_sent") recipients = models.ManyToManyField("User", related_name="emails_received") subject = models.CharField(max_length=255) body = models.TextField(blank=True) timestamp = models.DateTimeField(auto_now_add=True) read = models.BooleanField(default=False) archived = models.BooleanField(default=False) def serialize(self): return { "id": self.id, "sender": self.sender.email, "recipients": [user.email for user in self.recipients.all()], "subject": self.subject, "body": self.body, "timestamp": self.timestamp.strftime("%b %d %Y, %I:%M %p"), "read": self.read, "archived": self.archived } def __str__(self): return f"From: {self.sender}, Sub: {self.subject}"
خب توی فایل models.py اول کلاس Email رو تعریف کردیم و داخلش چند تا فیلد تعریف کردیم.
فیلد sender مربوط به کسی که ایمیل رو فرستاده میشه هست، فیلد recipients مربوط به کسی ایمیل رو دریافت هست.
فیلد subject مربوط به subject اون ایمیل میشه.
فیلد body هم مربوط به body اون ایمیل میشه.
فیلد timestamp هم مربوط زمانی که اون ایمیل فرستاده شده هست.
فیلد read هم مربوط به این هستش آیا اون ایمیل خونده شده یا نه؟
فیلد archived هم مربوط به این هستش که آیا کاربر اون ایمیل رو آرشیو کرده یا نه.
تابع serialize هم برای برای اینه که تمام فیلد های اون دیتابیس رو بصورت مرتب شده به ما برگردونه.
خب حالا ما که این همه مقادیر ایمیل ها، mailbox ها و... رو برگردوندیم باید باهاشون چی کار کنیم؟؟؟
توی بخش بعدی منتظرش باشین :)))
امیدوارم براتون مفید بوده باشه D: