آموزش سریع فلسک در پایتون (روز 13 قرار گرفت)

سلام وقتتون بخیر! امیدوارم حالتون عالی باشه. توی این مجموعه آموزشی میخوایم با هم فلسک کار کنیم. این آموزش‌ها نمیدونم چند قسمت میشه ولی همشون رو میذارم توی یه لیست که بتونید راحت‌تر بهشون دسترسی پیدا کنید. توی این مجموعه آموزشی میخوایم فلسک یاد بگیریم. فلسک یه فریمورک پایتون هستش برای توسعه وب که وبسایت‌های بزرگ و معروفی ازش استفاده میکنن مثلا پینترست، نتفلیکس، توییچ و... پس اگر فلسک رو بتونید خوب و حرفه‌ای یاد بگیرین میتونید باهاش کارای بزرگی بکنید!

این مجموعه آموزشی یه پیشنیاز داره، شما باید پایتون رو بلد باشین! یعنی از صفر تا شی‌گرایی. اگر دوست داشتین پایتون رو اصولی و کامل یاد بگیرین بهتون دوره کامل پایتون (کلیک کنید) رو پیشنهاد میکنم.


روز اول: نصب و راه‌اندازی

برای اولین روز ما نیاز داریم که فلسک رو نصب کنیم. امیدوارم که پایتون و VsCode (یا حداقل یه کدادیتور دیگه) رو نصب داشته باشین. بعدش این مراحل رو انجام بدین:

یک: ما اول از همه باید یه محیط مجازی بسازیم. پس توی ترمینال بنویسید:

python -m venv venv

اون venv دومی اسم محیط مجازیتون هست؛ میتونید هر چیزی که دوست داشتین بذارین. ولی به نظرم دست نزنید!
دو: بعد از اینکه محیط مجازی رو ساختین باید فعالش بکنید. با توجه به سیستم‌عاملتون یکی از این دستورات رو بایستی بزنید:

linux and mac: source venv/bin/activate
windows: ./venv/Scripts/activate

سه: حالا باید فلسک رو نصب کنید. که سه روش داریم. روش عادی اینه که بنویسید:

pip install flask

اگر به مخازن pypi دسترسی ندارین میتونید از یه mirror ایرانی استفاده کنید. به این شکل:

pip install -i https://mirror-pypi.runflare.com/simple flask

اگر بازم نشد (یا مثلا اینترنت نداشتین!) میتونید آفلاین نصب کنید. چطوری؟ اول از سایت آی کد آکادمی دانلود کنید (ببخشید یه کم قدیمیه!) و پوشه رو اکسترکت کنید و با ترمینال برین داخلش و بنویسید:

pip install --no-index --find-links=. flask

خب تبریک میگم! شما تونستین فلسک رو نصب کنید! اگر خواستین تست کنید که فلسک نصب شده یا نه توی ترمینال بنویسید:

flask --version

اگر نسخه فلسک نصب شده رو بهتون نشون داد، یعنی فلسک نصب شده و همه چی آرومه ما چقدر خوشبختیم :)


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز دوم: مثال سلام دنیا!

اگر فلسک رو توی محیط مجازی نصب کردین، محیط مجازی رو فعال کنید و یه پوشه بسازین و توش یه فایل (مثلا به اسم app.py) با ویرایشگر کدتون باز کنید. امروز میخوایم اولین مثال رو ببینیم! توی برنامهنویسی همیشه اولین مثال، مثال معروف سلام دنیا هستش! یعنی کاری کنیم که توی اون پلتفرمی که داریم توش کد مینویسیم، عبارت سلام دنیا رو ببینیم. پس اول از همه باید فلسک رو ایمپورت کنیم:

from flask import Flask 

بعدش باید یه اپ (یه شی از کلاس Flask) بسازیم. پس فعلا حفظی طور بنویسید:

app = Flask(__name__)

توی فلسک به مسیرهای مختلف یک وبسایت میگن route و ما برای تعریف اولین مسیر باید از دکوراتوری به همین اسم استفاده کنیم:

@app.route("/")

اون / یعنی صفحه اول وبسایت؛ کلا اینطوری حفظ کنید که مسیرها توی فلسک با / شروع میشن. خب اگر جلوش هیچی نباشه میشه اولین صفحه وبسایت. زیر همین دکوراتور تابعی که میخواین توی صفحه اول call بشه رو باید بنویسید. من مینویسم:

def home():
    return "Salam Donya"

و بعدش باید چک کنیم که آیا این ماژول (این فایل پایتونی) داره مستقیم اجرا میشه؟

if __name__ == "__main__":
    ...

حالا اگر اینطوریه پس باید برنامه رو اجرا کنیم. پس به جای اون سه نقطهها بنویسید:

app.run()

و حالا برین توی ترمینال بنویسید:

python app.py

اگر اسم فایلتون app.py نیست بدیهیه که باید اسم مال خودتون رو بنویسید! حالا توی ترمینال یه آدرسی نوشته که 127.0.0.1 و... داره! اونو کپی کنید توی مرورگر و باید مقدار Salam Donya رو توی صفحه اول ببینید. اگر دیدین یعنی دیری ری دین! مثال سلام دنیا رو با موفقیت اجرا کردین. برای امروز بسه. روز بعد بیشتر یاد میگیریم :)


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز سوم: سلام دنیا پرو پلاس!

روز دوم که مثال سلام دنیا رو اجرا کردیم، یه دستوری زدیم به اسم .run() همین الان بهتره بدونید که توی این دستور میشه این پارامترها رو تنظیم کرد:

app.run(
debug=True,
host="127.0.0.1",
port=5000,
)

هاست و پورت که مشخصه (ولی خب اینا رو ننویسید فعلا!) ولی دیباگ خیلی مهمه. دیباگ اگر True باشه. هر تغییری توی کد به وجود میارین سریع شناسایی میشه و نیاز نیست که برنامه رو از اجرا دربیارین و دوباره اجرا کنید، فقط کافیه صفحه رو ریلود کنید. همچنین اگر دیباگ True باشه، خطا اگر بگیرین بهتر و بیشتر راهنماییتون میکنه.

حالا بیاین مثال سلام دنیا رو یکم پیشرفتهتر کنیم! اول که میتونید از تگهای HTML استفاده کنید مثلا:

def home():
    return "<center><h1>Salam Donya</h1></center>"

اینو اگر اجرا کنید میبینید که سلام دنیا بزرگتر شده و اومده وسط صفحه! نکته بعدی اینکه ما میتونیم دو تا مسیر رو بدیم به یه تابع! یعنی کاربر دو جا رفت، بازم همین تابع اجرا بشه. ببینید:

@app.route("/")
@app.route("/home")
def home():
    return "<center><h1>Salam Donya</h1></center>"

الان کاربر اگر بره توی این دو مسیر، یه چیز میبینه:

https:127.0.0.1/
https:127.0.0.1/home/

حالا میخوایم وبسایت ما یه مسیر دیگه داشته باشه که بتونیم قیمت دلار رو توش ببینیم! برای این کار اول از همه باید پکیج قیمت رو نصب کنیم. اگر اینترنتها اوکی هستش بنویسید:

pip install gheymat

اما اگر اختلال و محدودیت وجود داره از اینجا پکیج قیمت رو دانلود کنید و بعدش اکسترکت کنید و برین داخل پوشه و بنویسید:

pip install --no-index --find-links=. gheymat

پ.ن: جهت شوآف این پکیج رو من نوشتم (خخ)

بعدش بالای فایل app.py اینو ایمپورت کنید. به این شکل:

from gheymat.currency import USD

حالا یه صفحه جدید بسازین:

@app.route("/dollar")

بعدش تابع رو بنویسید:

def get_usd():
    price = USD(toman=True, beauty=True)
    return f"price of dollar in toman: {price}"

و همین! کاری نداریم که پکیج من چطوری کار میکنه! خیلی هم مهم نیست و اصلا بحث این آموزش نیست. فقط بدونید که اون بیوتی رو اگر True بذارین قیمت دلار رو سه تا سه تا جدا میکنه و خواناییش بهتره! و برای کسایی که یکم زیادی تازهکار هستن باید بگم که این تابع و مسیرش باید قبل از اون شرط if main==و ... باشه ها...

حالا اگر برنامه رو اجرا کنید و برین به /dollar میبینید که عه! قیمت دلار رو زد! بسه :) بریم روز چهارم...


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز چهارم: کار با route ها..!

امروز میخوایم یکم بیشتر با route ها یا همون مسیرهای وبسایت توی فلسک کار کنیم. ما در واقع دو نوع مسیر داریم! مسیرهای معمولی و مسیرهایی که مبدل دارن! حالا مبدل چیه؟ مبدل یه چیزیه که ما مینویسیم و کاربر ورودی میده (توی آدرس) و اون تبدیل میشه به ورودی! برای همون بهش میگن مبدل.

در مورد مسیرهای معمولی ما مثال دیدیم ازش. ولی یه نکتهای میخوام بگم که جدیده. اینو ببینید:

@app.route("/about", methods=['GET','POST'])
def about():
    return "<h1>programmer: ali heydari</h1>"

بلی! ما میتونیم متدها رو تعیین بکنیم. مثلا اگر متد رو فقط POST بذاریم دیگه نمیشه اون صفحه رو آدرسش رو وارد کرد و رفت داخلش! در مورد متدها بعدا بیشتر صحبت میکنیم ولی این متدها (GET و POST) شیوههای مختلف درخواست زدن به مسیرها هستن. GET برای دیدن محتوای وب استفاده میشه و POST برای ارسال اطلاعات به سرور. البته الان خیلی ناقص توضیح دادم ولی تا همینجا اینو داشته باشین بعدا میرسیم بهش...

مسیرهای مبدل، گفتیم مسیرهایی هستن که کاربر میتونه توش ورودی بزنه. مثلا فرض کنید که میخوایم توی یه مسیر، اسم کاربر رو بگیریم که بعد بتونیم بهش سلام کنیم! ببینید:

@app.route("/hi/<user>")
def hi(user):
    return f"<h1>hi to {user}</h1>"

اون <user> که نوشتیم همون مبدل ماست. مثلا کاربر باید وارد کنه:

https://127.0.0.1/hi/ali

اگر اون اسم رو پر نکنید خطا میگیرین!

اگر نوع مبدل رو ننویسیم (مثل الان) رشته گرفته میشه. اما اگر بخوایم عدد بگیریم یا چیز دیگهای باید نوع مبدل رو هم انتخاب کنیم. اینطوری:

<int:id>
<string:name>
<slug:address>

فعلا همینا یادم میاد! اگر چیز دیگهای توی داکیومنت فلسک پیدا کردم اینجا اضافه میکنم. (خدایا اینترنت رو وصل کن، الهی آمین!)

حالا بیاین یه مثال هم بزنیم. مثلا دو تا عدد بگیریم و ضرب و تقسیم و جمع و تفریقش رو نشون بدیم! اینطوری میشه:

@app.route("/math/<int:n1>/<int:n2>/")
def math(n1,n2):
    return f"{n1}+{n2}={n1+n2}<br>{n1}-{n2}={n1-n2}<br>"

بقیهشو خودتون اضافه کنید! تگ <br> هم میره خط بعدی..

نکته خیلی مهم توی مبدلها اینه که هر چی اسمشون رو میذاریم، همون اسم باید ورودی تابع باشه. مثلا این غلطه و خطا میده:

@app.route("/hi/<user>")
def hi(name):
    return f"<h1>hi to {name}</h1>"

فعلا تا همینجا سیخ سیخ کنید و برنامههای مختلف بنویسید تا برسیم به روز پنجم :)


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز پنجم: کار با تمپلیت‌ها

امروز میخوایم یاد بگیریم چطور میشه به جای اینکه یه رشته رو return کنیم، بیایم و یه صفحه وب رو به کاربر نشون بدیم. برای اینکار باید در کنار app.py (یا اسم برنامهتون) یه پوشه بسازین به اسم templates و توش یه صفحه وب درست کنید مثلا اینطوری:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MyWebsite</title>
</head>
<body>
    <center>
        <h1>This is my website</h1>
        <h2>Programmer: mr robot</h2>
        <p>this is another text just for fun!</p>
    </center>
</body>
</html>

اسمشو بذارین home.html و حالا میخوایم این صفحه رو وصل کنیم به مسیر اصلی وبسایت. باید تا الان فهمیده باشین به فایلهای html توی فلسک (و البته جنگو!) میگن تمپلیت! و برای نشون دادن تمپلیتها یه تابعی هست توی فلسک به اسم render_template که باید ایمپورتش کنید:

from flask import Flask, render_template

و اینطوری میشه ازش استفاده کرد:

return render_template("home.html")

یعنی مثلا اگر چنین کدی توی app.py داشته باشین:

from flask import Flask, render_template
app = Flask(__name__)

@app.route("/")
def home():
    return render_template("home.html")

if __name__ == "__main__":
    app.run(debug=True)

و کنار همین فایل یه پوشه به اسم templates داشته باشین ( به اون s آخرش دقت کنید) بعدش اگر این فایل رو باز کنید توی صفحه اول وبسایت میبینید که فایل home.html نمایش داده میشه! خیلی زیبا شد نه؟


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز ششم: ارسال داده به تمپلیت

وقتی از تمپلیت استفاده نمیکردیم خیلی راحت میشد دیتا رو با یه استرینگ با f-string مخلوط کرد و به کاربر نشون داد. اما حالا چطور میشه؟! حالا که داریم از تمپلیتها استفاده میکنیم؟ اینجا ما باید از موتور jinja2 استفاده کنیم. جینجا یه موتور تمپلیت هستش که ما میتونیم باهاش داخل تگهای html کد بنویسیم! و ارتباط بین بکاند و فرانتاند رو برقرار کنیم. مثال دیروز یادتونه؟ یه مسیر خیلی ساده داشتیم:

@app.route("/")
def home():
    return render_template("home.html")

بیاین به این تغییرش بدین:

@app.route("/")
def home():
    return render_template("home.html", name="ali")

اینجا ما یه متغیر به نام name و با مقدار ali ارسال کردیم به home.html... حالا اگر صفحه رو رفرش کنید هیچ تغییری حس نمیکنید! خب بایدم نکنید! چون هنوز ازش استفاده نکردیم... توی jinja2 برای نشون دادن مقدار یک متغیر از {{}} استفاده میکنیم. مثلا توی تمپلیت دیروز اگر بخوایم اون name رو استفاده کنیم اینطوریه:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MyWebsite</title>
</head>
<body>
    <center>
        <h1>Hello to {{ name }}.</h1>
        <h2>Programmer: mr robot</h2>
        <p>this is another text just for fun!</p>
    </center>
</body>
</html>

خط 10 رو دقت کنید. حالا اگر همه چی رو ذخیره کنید و برنامه رو اجرا کنید میبینید که توی صفحه اصلی به مقدار اون متغیری که ساختین سلام میکنه! اگر یه وقت خواستین یه چیز دیگه ارسال کنید اینطوریه:

return render_template("home.html", name="ali", age=27)

اونوقت میتونیم از {{ age }} هم استفاده کنیم. (راستی این فاصلهها که میذارم برای قشنگیه! تاثیری توی کد نداره!

پس تا الان فهمیدیم که توی render_template سمت چپی، اسمی هستش که باید توی تمپلیت استفاده کنیم و سمت راستی مقداری هستش که توی بخش بکاند اعتبار داره. پس اینو ببینید:

name = "ali
return render_template("home.html", name=name, age=27)

توی render_template اون name سمت چپی، چیزیه که ساختیم تا توی تمپلیت ازش استفاده کنیم و name سمت راستی داریم میگیم که مقدارش مساوی با مقدار متغیر name توی بکاند باشه. امیدوارم گیج نشده باشین! حالا اگر شدینم که دیگه کار از کار گذشته! بعدا درست میشه...!


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز هفتم: حلقه و شرط در تمپلیت

جینجا فقط برای نشون دادن دادهها توی تمپلیت نیست. بلکه میتونیم توش حلقه یا شرط بنویسیم! مثلا اگر به تمپلیت یه لیست بفرستیم چی میشه؟! ببینید:

@app.route("/")
def home():
    names = ["ali","reza","amir"]
    return render_template("home.html", names=names)

حالا آیا درسته ما توی تمپلیت بنویسیم:

<h1>Hello {{ names }}</h1>

؟ نه دیگه! اینطوری خود لیست رو میاره میذاره جلوی Hello و این زشته! خیلی زشته. خیلی خیلی زشته! برای همین باید یه حلقه بنویسیم. دستورات (مثل حلقه و شرط) با {% %} نوشته میشن. مثلا حلقه اینطوریه:

{% for item in items %}
    do something..!
{% endfor %}

برای اون مثال لیست names اینطوری میشه:

{% for name in names %}
    <h3>Hello {{ name }}</h3>
{% endfor %}

حواستون به اون endfor باشه. شرط هم همینطوریه. مثلا میتونیم بگیم اگر لیست خالی نبود این حلقه اجرا بشه. اگر لیست خالی بود بگه هیچی توی لیست نیست! فقط بازم یادتون نره برای شرط باید endif بنویسیم.

{% if names %}
{% for name in names %}
    <h3>Hello {{ name }}</h3>
{% endfor %}
{% else %}
    <h3>hichi nist.</h3>
{% endif %}

حالا بپرین برین توی کد و لیست رو خالی کنید. بعدش میبینید که میگه توش هیچی نیست! اینم از شرط و حلقه. با همینا خوش باشین فعلا تا بریم به روز هشتم...


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز هشتم: ارسال دیکشنری به تمپلیت

آموزشهای قبلی متغیر و لیست رو ارسال کردیم به تمپلیت. رفتار عجیب غریبی هم ندیدیم. منظورم اینه که متغیر یا لیست اونور (تمپلیت) هم به همون شکل استفاده میشد. اما اگر ما یه دیکشنری رو بفرستیم به سوی تمپلیت، اونور این دیکشنری به حالت یه شی در نظر گرفته میشه که یه سری اتربیوتها داره. یعنی چی؟ مثلا اینو ببینید:

@app.route("/")
def home():
    data = {"name": "ali", "age": 27}
    return render_template("home.html", person=data)

یه دیکشنری ساختیم به اسم data و گفتیم توی template اگر گفتیم person منظورمون همون چیزمیزای داخل data هستش. حالا توی تمپلیت اگر بخوایم به کلید name توی دیکشنری اشاره کنیم باید از . (دات) استفاده کنیم. شبیه شیگرایی توی پایتون میشه. مثلا ببینید:

<body>
    <center>
        <h1>This is my website</h1>
        <h2>Programmer: {{ person.name }}</h2>
        {% if person.age < 18 %}
            <h3>zire sene ghanoni!</h3>
        {% else %}
            <h3>balaye sene ghanoni!</h3>
        {% endif %}
    </center>
</body>

دیدین؟ مثلا person.name یا person.age و از این سوسول بازیا. درس امروز تمومه فقط میخوام یه نکتهای رو بگم. سعی کنید همیشه کدها رو بنویسید! یه بار خودتون همونو بنویسید. یا یکم تغییر بدین و بنویسید. با خودتون نگین "چشمی دارم نگاه میکنم دیگه! نیازی به اجرا کردن نیست. کار میکنه!" بنویسید! به من اعتماد کنید و بنویسید.. بعدا ازم تشکر میکنید!


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز نهم: پروژه سازنده فاکتور!

خب میرسیم به روز نهم! امروز میخوایم یه پروژه بسازیم! یه پروژه که خریدهای ما رو از یه فایل متنی میخونه و برامون فاکتور قابل چاپ میسازه! ما یه فایل متنی داریم به اسم buys.txt که محتواش اینطوریه:

Chips-40000
Drink-60000
Laptop-210000000

حالا یه فایل پایتونی داریم که اول از همه فلسک رو توش ایمپورت میکنیم و یه app میسازیم:

from flask import Flask, render_template

app = Flask(__name__)

بعدش یه تابع میخوایم که فایلی که بهش میدیم رو باز کنه و محتویاتش رو به شکل دیکشنری دربیاره:

def create_dict(filename):
    with open(filename, encoding="utf-8") as f:
        data = {
            k.strip(): v.strip()
            for k, v in (line.split("-") for line in f if line.strip())
        }

    return data

این پایتون پایه هستش! امیدوارم بلد باشین. حالا مسیر اصلی رو بسازین و توش فایل buys رو بدین به این تابع و خروجی رو بفرستین به تمپلیت:

@app.route("/")
def home():
    data = create_dict("buys.txt")
    prices = [int(price) for price in data.values()]
    total = sum(prices)
    return render_template("home.html", data=data, total=total)

if __name__ == "__main__":
    app.run(debug=True)

یه کار اضافه هم کردیم. اومدیم جمع تمام محصولات رو هم فرستادیم و همچنین دستورات اجرایی فایل پایتون رو گذاشتیم. حالا توی تمپلیت یه جدول میسازیم (جدول ساختن توی html خیلی آسونه بخونید درموردش) و به ازای آیتمهایی که توی data وجود داره یه ردیف میسازیم و محتویات رو قرار میدیم:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MyWebsite</title>
</head>
<body>
    <center>
        <h1>Thanks for buy</h1>
        <hr>
        <table border=1>
        <thead>
            <tr>
                <th>Product</th>
                <th>Price</th>
            </tr>
        </thead>
        <tbody>
            {% for key, value in data.items() %}
            <tr>
                <td>{{ key }}</td>
                <td>{{ value }}</td>
            </tr>
            {% endfor %}
        </tbody>
        <tfoot>
            <tr>
                <td colspan="2">Total Price: {{ total }}</td>
            </tr>
        </tfoot>
    </table>

    <button ="window.print();">Print</button>

    </center>
</body>
</html>

پایین جدول هم جمع کل رو گذاشتیم. همچنین یه دکمه ساختیم که روش اگر کاربر کلیک کنه، میاد که اون فاکتور رو چاپ کنه یا خروجی pdf بگیره! تگهای HTML رو خیلی توضیح نمیدم چون خیلی واضحه که چی هستن. یا خودتون یکم دستکاری کنید میفهمید یه تگ چیکار میکرده و... امیدوارم که با این پروژه هر چیزی که تا الان یاد گرفتیم رو مرور کرده باشین.


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز دهم: ارث بری در تمپلیت

تصور کنید یه فایل html داریم، این فایل html یه بخش هدر داره، یه بخش منو، یه بخش فوتر، یه بخش و... این بخش‌ها تقریبا توی اکثر صفحات تکرار میشه و شایسته نیست (اوهع!) که هی اینا رو کپی پیست کنیم. بهتره اینا رو یه جایی بنویسیم و هر بار که خواستیم ازشون استفاده کنیم. زیبا میشه نه؟ خوشبختانه اینو میشه پیاده‌سازی کرد. با دستور block و extends. ببینید این صفحه اصلی سایت اگر هست:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MyWebsite</title>
</head>
<body>
    <center>
        <h1>Hello to {{ name }}.</h1>
        <h2>Programmer: mr robot</h2>
        <p>this is another text just for fun!</p>
    </center>
</body>
</html>

میایم یه صفحه میسازیم به اسم base.html و چیزایی رو توش میذاریم که قراره هی تکرار بشن و چیزایی که قراره تغییر کنن رو توی {% block name %} میذاریم:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    {% block content %}{% endblock %}
</body>
</html>

و بعد توی صفحه اصلی میایم اینو وارد میکنیم (با دستور extends) و چیزایی که قراره توی block ها بذاریم رو جایگزین میکنیم. مثلا توی صفحه اصلی:

{% extends 'base.html' %}

{% block title %}Home Page{% endblock %}

{% block content %}
<center>
        <h1>Hello to {{ name }}.</h1>
        <h2>Programmer: mr robot</h2>
        <p>this is another text just for fun!</p>
</center>
{% endblock %}

به اون دستور extends دقت کنید! مثل import توی پایتون هستش. حالا اگر بخوایم یه صفحه دیگه داشته باشیم:

{% extends 'base.html' %}

{% block title %}About Page{% endblock %}

{% block content %}
<center>
        <p>this is another page</p>
</center>
{% endblock %}

اینم از این. خوش باشید تا روز بعدی!


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز یازدهم: فایل‌های استاتیک

امروز میخوام بهتون یاد بدم چطوری میشه عکس، فایل‌های CSS/JS رو توی فایل HTML آدرس دهی کرد. اول از همه باید بیاین توی پوشه ریشه (root) پروژه تون کنار پوشه templates یه پوشه بسازین به اسم static و بعدش داخل اون پوشه چند پوشه جدا images، css، js و ... بسازین. حالا اگر توی تمپلیت قرار باشه به فایل css وصل بشه، در حالت عادی آدرس اینطوریه:

<link rel="stylesheet" href="css/style.css">

اگر بخوایم توی فلسک آدرس دهی کنیم، یه تابعی هست توی jinja به اسم url_for که میاد آدرس رو برای ما میسازه. نحوه استفاده‌اش اینطوریه:

<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">

برای فایل‌های جاوا اسکریپت یا عکس هم به همین ترتیب میشه استفاده کرد. مثلا برای عکس اگر داریم:

<img src="images/image.jpg">

میشه:

<img src="{{ url_for('static', filename='images/image.jpg') }}">

خب اینم از این! خوش باشین تا بعد...


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز دوازدهم: ریکوئست‌ GET در فلسک

کاربری که داره با سایت شما کار میکنه، دائم درخواست (request) ارسال میکنه و پاسخ (response) میگیره. پاسخ که مشخصه به هر حال یه صفحه وبی، یه پیغامی چیزی بهش نشون داده میشه. در مورد درخواست، ما دو نوع درخواست داریم، GET و POST که امروز میخوایم با GET کار کنیم.

درخواست با متد GET: توی این متد کاربر اطلاعاتی که قراره برای ما بفرسته رو توی URL میفرسته. مثلا فرض کنید یه مسیر داریم که میخوایم اسم کاربر رو بگیریم. اینو میشد با مبدل‌ها توی روز چهارم یاد گرفتیم اما اینبار میخوایم مسیر سایت ما اینطوری باشه:

https://127.0.0.1:5000/greet/?name=ali

توی متد GET اگر بخوایم پارامتری ارسال بشه باید اول یه ؟ بذاریم و بعدش پارامترها رو به شکل key=value ارسال کنیم. برای دریافتش توی بخش فلسک از request.args.get استفاده میکنیم البته باید request رو هم ایمپورت کرده باشیم:

from flask import Flask, request
...
@app.route("/greet", methods=['GET']) # method ekhtiarie
def greet():
    name = request.args.get("name")
    if name:
        return f'Salam {name}'
    else:
        return 'Salam User'

حالا اگر برین این مسیر و چیزی ارسال نکنید، خب name دریافت نمیشه و میگه سلام مهمان اما اگه این پارامتر رو ارسال بکنید به اون اسمی که دادین سلام میکنه. این روش ارسال اطلاعات، امن نیست. چون همه چی توی URL دیده میشه. برای همین از این روش فقط برای مواقعی ارسال میشه که درخواست شامل اطلاعات حساس نباشه. مثلا فرض کنید یه سایت فروشگاهی داریم، کاربر میخواد محدوده قیمت رو مشخص کنه، برند رو مشخص کنه و... حالا این URL رو برای یه دوست دیگه‌اش میفرسته که با همون شرایط، محصولات رو ببینه. اینها همه با متد GET هست. همچنین توی بخش فرم‌ها توی HTML ما میتونیم متد ارسال اطلاعات فرم رو GET بذاریم و بعدش اطلاعات توی URL ارسال میشن. مثلا این فرم رو ببینید:

<form action="/search" method="GET">
    <label for="min_price">min price: </label>
    <input type="number" name="min_price" id="min_price" required><br><br>
    <label for="max_price">max price: </label>
    <input type="number" name="max_price" id="max_price" required><br><br>
    <button type="submit">search</button>
</form>

البته امیدوارم HTML رو تا حدی بلد باشین ولی اینجا دو تا فیلد ساختیم که اسماشون به ترتیب min_price و max_price هستش و وقتی کاربر روی دکمه submit کلیک کنه اینا با متد GET ارسال میشن به مسیر /search و بعد توی فلسک میتونیم اینطوری دریافت کنیم:

@app.route('/search', methods=['GET'])
def search():
    min_price = request.args.get('min_price')
    max_price = request.args.get('max_price')
    return f'search beyne {min_price} ta {max_price}'

اینو فعلا کار کنید تا بعدش بریم سراغ متد POST، جایی که اطلاعات حساس ارسال میشن...


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز سیزدهم: ریکوئست POST در فلسک

روز قبل با متد GET آشنا شدیم و گفتیم که ارسال درخواست با این متد برای مواقعی هست که اطلاعات حساس ارسال نمیشه. امروز میخوایم با POST کار کنیم. توی ریکوئست با متد POST دیگه دیتاها توی URL ارسال نمیشن و توی بدنه ارسال میشن به بک‌اند برای همین مناسب ارسال اطلاعات حساس هستش. مثلا فرم لاگین، فرم ثبت سفارش، فرم ثبت‌نام و... متد GET چون اطلاعات توی URL ارسال میشد، میتونستیم فرم نداشته باشیم اما برای استفاده از متد POST باید حتما یه فرم داشته باشیم. مثلا اینطوری ( برای کوتاه‌تر شدن فقط بخش body رو گذاشتم):

<body> 
    <h1>Login</h1> 
    <form action="/login" method="post"> 
        <label for="username">Username:</label><br> 
        <input type="text" id="username" name="username"><br><br> 

        <label for="password">Password:</label><br> 
        <input type="password" id="password" name="password"><br><br> 

        <button type="submit">Login</button> 
    </form> 
</body>

میبینید که متد post هستش (حروف کوچیک بنویسید هم کار میکنه) حالا اگر بخوایم توی فلسک username و password رو بگیریم، باید از reuqest.form استفاده کنیم (بازم دقت کنید که import شده باشه) و مقدار name این input ها رو بدیم.

from flask import Flask, request
...
@app.route('/login', method='POST') 
    def login(): 
        username = request.form.get('username') 
        password = request.form.get('password') 

        if username and password: 
            return f'Login successful for user: {username}' 
        else: 
            return 'Username and password are required.'

البته اینو بگم که لاگین کردن اینطوری انجام نمیشه! چون خیلی ناامنه. بعدا اینو توی بخش احراز هویت یاد میگیریم. فعلا فقط میخوایم ببینیم چطوری میشه اطلاعات بین فرانت‌اند و بک‌اند رد و بدل بشه...

حالا که متدها ارسال درخواست رو شناختیم، شاید براتون سوال شده باشه که آیا میشه یه مسیر، هم درخواست POST قبول بکنه و هم GET؟ بله میشه. اینطوریه که ما اول باید نوع درخواست رو چک کنیم. مثلا برای همین مسیر لاگین:

from flask import Flask, request, render_template
...
@app.route('/login', method='POST') 
    def login(): 
        if request.method == 'POST':
            username = request.form.get('username') 
            password = request.form.get('password') 

            if username and password: 
                return f'Login successful for user: {username}' 
            else: 
                return 'Username and password are required.'
        else:
            return render_template('login.html')

و بدین ترتیب میتونیم بگیم که اگر کاربر رفته بود توی url آدرس مسیر لاگین رو نوشته بود (یعنی متد GET بود) بیا و صفحه لاگین رو نشون بده اما اگر فرم لاگین رو پر کرده بود و روی دکمه سابمیت کلیک کرده بود (یعنی متد POST بود) بیا و اطلاعات فرم رو بگیر و پردازش کن...


حمایت از این مجموعه آموزشی 💖
این مجموعه آموزشی به رایگان در اختیار شما قرار داده شده ولی اگر دوست داشتین همیشه میتونید از من حمایت کنید. با خریدن یه قهوه برام! لینک حمایت مالی از آقای ربات (40 هزار تومان به بالا)


روز چهاردهم به زودی..