نحوه ایجاد یک برنامه وب با استفاده از Flask در پایتون 3
مقدمه
Flask یک چارچوب وب کوچک و سبک برای پایتون است که ابزار ها و ویژگی های مفیدی را ارائه می دهد که ایجاد برنامه های کاربردی وب در پایتون را آسان تر می کند. این به توسعه دهندگان انعطاف پذیری میدهد و چارچوبی در دسترس تر برای توسعه دهندگان جدید است، زیرا میتوانید به سرعت یک برنامه وب را تنها با استفاده از یک فایل پایتون بسازید. Flask همچنین توسعه پذیر است و ساختار راهنمای خاصی را اجبار نمی کند یا قبل از شروع به کد پیچیده دیگ بخار (boilerplate) یا کد های تکراری نیاز ندارد.
به عنوان بخشی از این آموزش، از جعبه ابزار Bootstrap برای استایل یا سبک دادن به برنامه خود استفاده می کنید تا از نظر بصری جذاب تر باشد. Bootstrap به شما کمک می کند تا صفحات وب واکنش گرا (Responsive) را در برنامه وب خود بگنجانید تا در مرورگر های تلفن همراه نیز بدون نوشتن کد HTML، CSS و جاوا اسکریپت خود برای دستیابی به این اهداف، به خوبی کار کند. جعبه ابزار به شما این امکان را می دهد که روی یادگیری نحوه عملکرد Flask تمرکز کنید.
Flask از موتور الگو Jinja (Jinja template engine) برای ساخت صفحات HTML پویا با استفاده از مفاهیم آشنای پایتون مانند متغیر ها، حلقه ها، لیست ها و غیره استفاده می کند. شما از این الگو ها به عنوان بخشی از این پروژه استفاده خواهید کرد.
در این آموزش، یک وبلاگ کوچک وب با استفاده از Flask و SQLite در پایتون 3 می سازید. کاربران برنامه می توانند تمام پست های موجود در پایگاه داده شما را مشاهده کنند و روی عنوان یک پست کلیک کنند تا محتوای آن را با قابلیت افزودن پست جدید به پایگاه داده و ویرایش یا حذف پست موجود مشاهده کنند.
پیش نیاز ها
قبل از شروع به دنبال کردن این راهنما، به موارد زیر نیاز دارید:
• یک محیط برنامه نویسی محلی پایتون 3، آموزش پراکندگی خود را در نحوه نصب و راه اندازی یک محیط برنامه نویسی محلی برای سری پایتون 3 برای ماشین محلی خود دنبال کنید. در این آموزش ما راهنمای پروژه خود را flask_blog می نامیم.
• درک مفاهیم پایتون 3، مانند انواع داده ها، عبارات شرطی، حلقه ها، توابع و سایر مفاهیم از این قبیل. اگر با پایتون آشنایی ندارید، مقاله نحوه کد نویسی در سری پایتون 3 را بررسی کنید.
مرحله 1 – نصب Flask
در این مرحله، محیط پایتون خود را فعال کرده و Flask را با استفاده از نصب کننده بسته pip نصب میکنید. اگر قبلا محیط برنامه نویسی خود را فعال نکرده اید، مطمئن شوید که در فهرست پروژه خود (flask_blog) هستید و از دستور زیر برای فعال کردن محیط استفاده کنید:
- $ source env/bin/activate
هنگامی که محیط برنامه نویسی شما فعال شد، درخواست شما اکنون یک پیشوند env خواهد داشت که ممکن است به صورت زیر باشد:
(env)sammy@localhost:$
این پیشوند نشان می دهد که محیط env در حال حاضر فعال است، که ممکن است بسته به نحوه نامگذاری شما در هنگام ایجاد نام دیگری داشته باشد.
توجه: میتوانید از Git، که یک سیستم کنترل نسخه است، برای مدیریت مؤثر و پیگیری فرآیند توسعه پروژه خود استفاده کنید. برای یادگیری نحوه استفاده از Git، ممکن است بخواهید مقاله مقدمه ای بر استفاده و شاخه های نصب Git را بررسی کنید.
اگر از Git استفاده می کنید، ایده خوبی است که فهرست env که جدید ایجاد شده در فایل .gitignore خود نادیده بگیرید تا از ردیابی فایل های غیر مرتبط با پروژه خودداری کنید.
اکنون بسته های پایتون را نصب می کنید و کد پروژه خود را از سیستم نصب اصلی پایتون جدا می کنید. شما این کار را با استفاده از pip و python انجام خواهید داد.
برای نصب Flask دستور زیر را اجرا کنید:
(env)sammy@localhost:$ pip install flask
پس از اتمام نصب، دستور زیر را برای تایید نصب اجرا کنید:
(env)sammy@localhost:$ python -c “import flask; print(flask.__version__)”
شما از رابط خط فرمان python با گزینه -c برای اجرای کد پایتون استفاده می کنید. سپس بسته flask را با import flask; وارد می کنید. سپس نسخه Flask را که از طریق متغیر flask.__version__ ارائه می شود چاپ کنید.
خروجی شماره نسخه مشابه زیر خواهد بود:
Output
1.1.2
شما پوشه پروژه که یک محیط مجازی است را ایجاد کرده اید و Flask را نصب کرده اید. اکنون آماده هستید تا به راه اندازی برنامه پایه خود ادامه دهید.
مرحله 2 – ایجاد یک برنامه پایه
اکنون که محیط برنامه نویسی خود را تنظیم کرده اید، شروع به استفاده از Flask خواهید کرد. در این مرحله، یک برنامه وب کوچک در داخل یک فایل پایتون ایجاد میکنید و آن را برای راه اندازی سرور اجرا میکنید که برخی از اطلاعات را در مرورگر نمایش میدهد.
در پوشه flask_blog خود، فایلی به نام hello.py را برای ویرایش باز کنید، از nano یا ویرایشگر متن دلخواه خود استفاده کنید:
(env)sammy@localhost:$ nano hello.py
این فایل hello.py به عنوان یک نمونه جزئی از نحوه رسیدگی به درخواست های HTTP عمل می کند. در داخل آن، هدف flask را وارد میکنید و تابعی ایجاد میکنید که پاسخ HTTP را برمیگرداند. کد زیر را داخل hello.py بنویسید:
from flask import Flask
app = Flask(__name__)
@app.route(‘/’)
def hello():
return ‘Hello, World!’
در بلوک کد قبلی، ابتدا هدف Flask را از بسته Flask وارد می کنید. سپس از آن برای ایجاد نمونه برنامه Flask خود با نام app استفاده می کنید. شما متغیر ویژه __name__ را که نام ماژول فعلی پایتون را در خود جای داده است، رد می کنید. از آن برای نشان دادن نمونه ای که در آن قرار دارد استفاده می شود -زیرا Flask مسیر هایی را در پشت صحنه تنظیم می کند به همین دلیل به این نیاز دارید.
هنگامی که نمونه app را ایجاد می کنید، از آن برای رسیدگی به درخواست های وب در حال ورود و ارسال پاسخ به کاربر استفاده می کنید. @app.route یک دکوراتور (آراینده) است که یک تابع معمولی پایتون را به یک تابع نمای Flask تبدیل میکند، که مقدار بازگشتی تابع را به یک پاسخ HTTP تبدیل میکند تا توسط مشتری HTTP، مانند مرورگر وب، نمایش داده شود. شما مقدار ‘/’ را به @app.route() می دهید تا نشان دهد که این تابع به درخواست های وب برای URL / که URL اصلی است، پاسخ می دهد. تابع نمای hello() رشته ‘Hello, World!’ را به عنوان پاسخ برمی گرداند.
ذخیره کنید و فایل را ببندید.
برای اجرای برنامه وب خود، ابتدا به Flask می گویید که با متغیر محیطی FLASK_APP کجا برنامه را پیدا کند (فایل hello.py در مورد شما):
(env)sammy@localhost:$ export FLASK_APP=hello
سپس آن را در حالت توسعه با متغیر محیطی FLASK_ENV اجرا کنید:
(env)sammy@localhost:$ export FLASK_ENV=development
در نهایت، برنامه را با استفاده از دستور flask run اجرا کنید:
(env)sammy@localhost:$ flask run
پس از اجرای برنامه، خروجی چیزی شبیه به این خواهد بود:
Output
* Serving Flask app “hello” (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 813-894-335
خروجی قبلی دارای چندین اطلاعات می باشد، مانند:
• نام برنامه ای که در حال اجرا هستید.
• محیطی که برنامه در آن اجرا می شود.
• Debug mode: on حالت اشکال زدایی: روشن نشان می دهد که اشکال زدای Flask در حال اجرا است. این در هنگام توسعه مفید است زیرا در صورت بروز مشکل به ما پیام های خطای دقیقی می دهد که عیب یابی را آسان تر میکند.
• برنامه به صورت محلی در URL http://127.0.0.1:5000/ اجرا می شود، 127.0.0.1 نشان دهنده IP localhost (میزبان محلی) دستگاه شما است و :5000 شماره پورت است.
یک مرورگر باز کنید و http://127.0.0.1:5000/ را تایپ کنید، رشته Hello, World! را به عنوان پاسخ دریافت خواهید کرد، این تأیید می کند که برنامه شما با موفقیت در حال اجرا می باشد.
اخطار Flask از یک سرور وب ساده برای ارائه برنامه ما در یک محیط توسعه استفاده می کند، که همچنین به این معنی است که اشکال زدا Flask در حال اجرا است تا پیدا کردن خطا ها را آسان تر کند. این سرور توسعه نباید در استقرار تولید استفاده شود. برای اطلاعات بیشتر به صفحه Deployment Options در مستندات Flask مراجعه کنید، همچنین می توانید این آموزش استقرار Flask را بررسی کنید.
اکنون می توانید سرور توسعه را در پایانه (terminal) در حال اجرا رها کنید و پنجره پایانه دیگری را باز کنید. به پوشه پروژه که hello.py در آن قرار دارد بروید، محیط مجازی (virtual environment) را فعال کنید، متغیرهای محیط FLASK_ENV و FLASK_APP را تنظیم کنید و به مراحل بعدی برویید. (این دستورات قبلا در این مرحله فهرست شده اند.)
توجه: هنگام باز کردن یک پایانه جدید، مهم است که محیط مجازی را فعال کنید و متغیر های محیط FLASK_ENV و FLASK_APP را تنظیم کنید.
در حالی که سرور توسعه یک برنامه Flask از قبل در حال اجرا است، امکان اجرای یک برنامه Flask دیگر با همان دستور flask run وجود ندارد. این به این دلیل است که flask run به طور پیش فرض از شماره پورت 5000 استفاده میکند و پس از گرفتن آن، اجرای برنامه دیگری امکان پذیر نمی شود، بنابراین خطایی مشابه زیر دریافت خواهید کرد:
Output
OSError: [Errno 98] Address already in use
برای حل این مشکل، یا سروری که در حال حاضر در حال اجراست را از طریق CTRL+C متوقف کنید، سپس دوباره flask run را اجرا کنید، یا اگر میخواهید هر دو را هم زمان اجرا کنید، میتوانید مثلا یک شماره پورت متفاوت به آرگومان -p ارسال کنید. برای اجرای برنامه دیگری در پورت 5001 از دستور زیر استفاده کنید:
(env)sammy@localhost:$ flask run -p 5001
شما اکنون یک برنامه وب کوچک Flask دارید. شما برنامه خود را اجرا کرده اید و اطلاعات را در مرورگر وب نمایش داده شده اند. در مرحله بعد، از فایل های HTML در برنامه خود استفاده خواهید کرد.
مرحله 3 – استفاده از الگو های HTML
در حال حاضر برنامه شما فقط یک پیام ساده و بدون HTML نمایش می دهد. برنامه های کاربردی وب عمدتا از HTML برای نمایش اطلاعات برای بازدیدکنندگان استفاده میکنند، بنابراین شما روی گنجاندن فایل های HTML در برنامه خود کار خواهید کرد که میتوانند در مرورگر وب نمایش داده شوند.
Flask تابع کمکی render_template() را ارائه می دهد که امکان استفاده از موتور الگو Jinja را فراهم می کند. این کار مدیریت HTML را با نوشتن کد HTML خود در فایل های .html و همچنین استفاده از منطق در کد های HTML را آسان تر میکند. شما از این فایل های HTML (الگو ها) برای ساختن تمام صفحات برنامه خود استفاده خواهید کرد، مانند صفحه اصلی که در آن پست های وبلاگ فعلی را نمایش می دهید، صفحه پست وبلاگ، صفحه ای که کاربر می تواند یک پست جدید اضافه کند و غیره.
در این مرحله، برنامه اصلی Flask خود را در یک فایل جدید ایجاد خواهید کرد.
ابتدا، در پوشه flask_blog خود، از nano یا ویرایشگر مورد علاقه خود برای ایجاد و ویرایش فایل app.py خود استفاده کنید. این همه کد هایی را که برای ایجاد برنامه وبلاگ نویسی استفاده می کنید نگه می دارد:
(env)sammy@localhost:$ nano app.py
در این فایل جدید، شما هدف Flask را برای ایجاد یک برنامه کاربردی نمونه Flask مانند قبل وارد خواهید کرد. همچنین تابع کمکی render_template() را وارد میکنید که به شما امکان می دهد فایل های الگو HTML موجود در پوشه الگو هایی را که می خواهید ایجاد کنید، پردازش کنید. این فایل دارای یک عملکرد نمایش واحد است که مسئول رسیدگی به درخواست ها به مسیر اصلی / است. محتوا زیر را اضافه کنید:
from flask import Flask, render_template
app = Flask(__name__)
@app.route(‘/’)
def index():
return render_template(‘index.html’)
تابع نمایی index() نتیجه فراخوانی (calling) render_template() را با index.html به عنوان آرگومان بر می گرداند، این به render_template() می گوید که به دنبال فایلی به نام index.html در پوشه templates بگردد. هم پوشه و هم فایل هنوز وجود ندارند، اگر برنامه را در این مرحله اجرا کنید با خطا مواجه می شوید. با این وجود آن را اجرا خواهید کرد، که با این استثنا که معمولا با آن مواجه می شوید آشنا هستید. سپس با ایجاد پوشه و فایل مورد نیاز، آن را برطرف خواهید کرد.
فایل را ذخیره کرده و از آن خارج شوید.
سرور توسعه را در پایانه دیگر خود که برنامه hello را با CTRL+C اجرا می کند، متوقف کنید.
قبل از اجرای برنامه، مطمئن شوید که مقدار متغیر محیطی FLASK_APP را به درستی مشخص کرده اید، زیرا دیگر از برنامه hello استفاده نمی کنید:
(env)sammy@localhost:$ export FLASK_APP=app
(env)sammy@localhost:$ flask run
با باز کردن http://127.0.0.1:5000/ در مرورگر خود، صفحه اشکال زدا به شما اطلاع می دهد که الگوی index.html پیدا نشد. خط اصلی کد که مسئول این خطا بوده، هایلایت می شود. در این مورد، خط اصلی کد return render_template(‘index.html’) می باشد.
اگر روی این خط کلیک کنید، اشکال زدا کد بیشتری را نشان می دهد تا زمینه بیشتری برای حل مشکل داشته باشید.
برای رفع این خطا، دایرکتوری (فهرست راهنما) به نام templates در دایرکتوری flask_blog خود ایجاد کنید. سپس داخل آن فایلی به نام index.html را برای ویرایش باز کنید:
(env)sammy@localhost:$ mkdir templates
(env)sammy@localhost:$ nano templates/index.html
سپس کد HTML زیر را در index.html اضافه کنید:
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<title>FlaskBlog</title>
</head>
<body>
<h1>Welcome to FlaskBlog</h1>
</body>
</html>
فایل را ذخیره کنید و از مرورگر خود برای رفتن دوباره به http://127.0.0.1:5000/ استفاده کنید یا صفحه را نوسازی یا رفرش کنید. این بار مرورگر باید متنWelcome to FlaskBlog را در یک تگ <h1> نمایش دهد.
علاوه بر پوشه templates، برنامه های وب Flask معمولا دارای یک پوشه static برای میزبانی فایل های ایستا مانند فایل های CSS، فایل های جاوا اسکریپت و تصاویری که برنامه ها استفاده میکنند هستند.
شما می توانید یک فایل شیوه نامه style.css ایجاد کنید تا CSS را به برنامه خود اضافه کنید. ابتدا، یک دایرکتوری به نام static در دایرکتوری اصلی flask_blog خود ایجاد کنید:
(env)sammy@localhost:$ mkdir static
سپس دایرکتوری دیگری به نام css در داخل دایرکتوری ایستا ایجاد کنید تا فایل های .css را میزبانی کند. این معمولا برای سازماندهی فایل های ایستا در پوشه های اختصاصی انجام میشود، به این ترتیب، فایل های جاوا اسکریپت معمولا در یک دایرکتوری به نام js قرار میگیرند، تصاویر در فهرستی به نام images (یا img) و غیره قرار میگیرند. دستور زیر دایرکتوری css را در دایرکتوری static ایجاد می کند:
(env)sammy@localhost:$ mkdir static/css
سپس یک فایل style.css را در داخل دایرکتوری css برای ویرایش باز کنید:
(env)sammy@localhost:$ nano static/css/style.css
قانون CSS زیر را به فایل style.css خود اضافه کنید:
h1 {
border: 2px #eee solid;
color: brown;
text-align: center;
padding: 10px;
}
کد CSS یک حاشیه اضافه می کند، رنگ را به قهوه ای تغییر می دهد، متن را در مرکز قرار می دهد و کمی حاشیه گذاری یا لایه گذاری (padding) به تگ های <h1> اضافه می کند. فایل را ذخیره کرده و ببندید.
سپس فایل الگوی index.html را برای ویرایش باز کنید:
(env)sammy@localhost:$ nano templates/index.html
پیوندی به فایل style.css در قسمت <head> فایل الگوی index.html اضافه می کنید:
. . .
<head>
<meta charset=”UTF-8″>
<link rel=”stylesheet” href=”{{ url_for(‘static’, filename= ‘css/style.css’) }}”>
<title>FlaskBlog</title>
</head>
. . .
در اینجا شما از تابع کمکی url_for() برای ایجاد مکان مناسب فایل استفاده می کنید. آرگومان اول مشخص می کند که شما در حال پیوند دادن به یک فایل ایستا هستید و آرگومان دوم مسیر فایل داخل دایرکتوری ایستا است.
فایل را ذخیره کنید و ببندید.
پس از رفرش کردن صفحه فهرست برنامه خود، متوجه خواهید شد که متن Welcome to FlaskBlog اکنون به رنگ قهوه ای، در مرکز، و در داخل یک حاشیه قرار گرفته است.
میتوانید از زبان CSS برای استایل دادن به برنامه استفاده کنید و با استفاده از طراحی خود آن را جذاب تر کنید. با این حال، اگر طراح وب نیستید یا با CSS آشنایی ندارید، میتوانید از جعبه ابزار Bootstrap استفاده کنید، که مؤلفه هایی با کاربری آسان را برای استایل کردن برنامه شما فراهم میکند. در این پروژه از Bootstrap استفاده خواهیم کرد.
شاید حدس زده باشید که ساختن یک الگو HTML دیگر به معنای تکرار بیشتر کد های HTML است که قبلا در الگوی index.html نوشته اید. شما می توانید با کمک یک فایل الگوی پایه، که تمام فایل های HTML شما که از این فایل الگوی پایه به ارث می برند، از تکرار کد های غیر ضروری جلوگیری کنید. برای اطلاعات بیشتر به الگوی وراثت در Jinja مراجعه کنید. برای ایجاد یک الگوی پایه، ابتدا یک فایل به نام base.html در دایرکتوری templates خود ایجاد کنید:
(env)sammy@localhost:$ nano templates/base.html
کد زیر را در الگوی base.html خود تایپ کنید:
<!doctype html>
<html lang=”en”>
<head>
<!– Required meta tags –>
<meta charset=”utf-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1, shrink-to-fit=no”>
<!– Bootstrap CSS –>
<link rel=”stylesheet” href=”https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css” integrity=”sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T” crossorigin=”anonymous”>
<title>{% block title %} {% endblock %}</title>
</head>
<body>
<nav class=”navbar navbar-expand-md navbar-light bg-light”>
<a class=”navbar-brand” href=”{{ url_for(‘index’)}}”>FlaskBlog</a>
<button class=”navbar-toggler” type=”button” data-toggle=”collapse” data-target=”#navbarNav” aria-controls=”navbarNav” aria-expanded=”false” aria-label=”Toggle navigation”>
<span class=”navbar-toggler-icon”></span>
</button>
<div class=”collapse navbar-collapse” id=”navbarNav”>
<ul class=”navbar-nav”>
<li class=”nav-item active”>
<a class=”nav-link” href=”#”>About</a>
</li>
</ul>
</div>
</nav>
<div class=”container”>
{% block content %} {% endblock %}
</div>
<!– Optional JavaScript –>
<!– jQuery first, then Popper.js, then Bootstrap JS –>
<script src=”https://code.jquery.com/jquery-3.3.1.slim.min.js” integrity=”sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo” crossorigin=”anonymous”></script>
<script src=”https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js” integrity=”sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1″ crossorigin=”anonymous”></script>
<script src=”https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js” integrity=”sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM” crossorigin=”anonymous”></script>
</body>
</html>
پس از اتمام ویرایش، فایل را ذخیره کرده و ببندید.
اکثر کد های موجود در بلوک قبلی کد HTML استاندارد هستند و کد مورد نیاز برای Bootstrap می باشند. تگ های <meta> اطلاعاتی را برای مرورگر وب ارائه میکنند، تگ <link> فایلهای Bootstrap CSS را پیوند میدهد، و تگ های <script> پیوند هایی به کد جاوا اسکریپت هستند که برخی از ویژگی های اضافی Bootstrap را ارائه می دهند، برای اطلاعات بیشتر به مستندات Bootstrap مراجعه کنید.
با این حال، قسمت های هایلایت شده زیر مختص ماشین الگوی Jinja است:
• {% block title %} {% endblock %}: بلوکی که به عنوان جایگاه دار (placeholder) برای عنوان یا تیتر عمل میکند، بعدا از آن در الگو های دیگر برای هر بار دادن عنوان دستی (دلخواه) برای هر صفحه در برنامه خود بدون بازنویسی کل بخش <head> استفاده میکنید.
• {{ url_for(‘index’)}}: فراخوانی تابعی که URL تابع نمایی index() را برمی گرداند. این با فراخوانی url_for() قبلی که برای پیوند دادن یک فایل CSS ایستا استفاده میکردید متفاوت است، زیرا فقط یک آرگومان میگیرد که نام تابع نمایی است و به جای یک فایل ایستا به مسیر مرتبط با تابع پیوند میدهد.
• {% block content %} {% endblock %}: بلوک دیگری که با محتوایی جایگزین میشود که بسته به الگوی فرزند (الگو هایی که از base.html به ارث می برند) آن را لغو میکند.
اکنون که یک الگوی پایه دارید، می توانید با استفاده از وراثت از آن بهره ببرید. فایل index.html را باز کنید:
(env)sammy@localhost:$ nano templates/index.html
سپس محتوای آن را با کد زیر جایگزین کنید:
{% extends ‘base.html’ %}
{% block content %}
<h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
{% endblock %}
در این نسخه جدید از الگوی index.html، از تگ {% extends %} برای ارث بردن از الگوی base.html استفاده میکنید. سپس آن را از طریق جایگزین کردن بلوک content در الگوی پایه با آن چه که در داخل بلوک content در بلوک کد قبلی است، گسترش دهید.
این بلوک content حاوی یک تگ <h1> با متن Welcome to FlaskBlog در داخل یک بلوک title است که به نوبه خود بلوک title اصلی را در الگوی base.html با متن Welcome to FlaskBlog جایگزین می کند. به این ترتیب، میتوانید از تکرار دوبار یک متن اجتناب کنید، زیرا هم به جای عنوان صفحه و هم به جای عنوانی که در زیر نوار پیمایش به ارث رسیده از الگوی پایه ظاهر میشود، کار میکند.
وراثت الگو همچنین به شما این امکان را می دهد که از کد HTML که در الگو های دیگر دارید (در این مورد base.html) استفاده مجدد کنید، بدون این که نیاز به تکرار آن در هر بار باشد.
فایل را ذخیره کرده و ببندید و صفحه فهرست را در مرورگر خود رفرش کنید. صفحه خود را با یک نوار پیمایش و عنوان استایل شده می بینید.
شما از قالب های HTML و فایل های ثابت (ایستا) در Flask استفاده کرده اید. شما همچنین از Bootstrap برای اصلاح ظاهر صفحه خود و یک الگوی پایه برای جلوگیری از تکرار کد استفاده کردید. در مرحله بعد، پایگاه داده ای را راه اندازی خواهید کرد که داده های برنامه شما را ذخیره می کند.
مرحله 4 – راه اندازی پایگاه داده
در این مرحله، یک پایگاه داده برای ذخیره داده ها، یعنی پست های وبلاگ برنامه خود، راه اندازی می کنید. همچنین پایگاه داده را با چند ورودی نمونه پر خواهید کرد.
شما از یک فایل پایگاه داده SQLite برای ذخیره داده های خود استفاده خواهید کرد زیرا ماژول sqlite3، که ما از آن برای تعامل با پایگاه داده استفاده خواهیم کرد، به سادگی در کتابخانه استاندارد پایتون موجود است. برای اطلاعات بیشتر در مورد SQLite، این آموزش را بررسی کنید.
ابتدا به این دلیل که داده ها در SQLite در جدول ها و ستون ها ذخیره می شوند و از آن جایی که داده های شما به صورت عمده از پست های وبلاگ تشکیل شده است، ابتدا باید جدولی به نام posts با ستون های لازم ایجاد کنید. شما یک فایل .sql ایجاد خواهید کرد که حاوی دستورات SQL برای ایجاد جدول posts با چند ستون است. سپس از این فایل برای ایجاد پایگاه داده استفاده خواهید کرد.
فایلی به نام schema.sql را در دایرکتوری flask_blog خود باز کنید:
(env)sammy@localhost:$ nano schema.sql
دستورات SQL زیر را داخل این فایل تایپ کنید:
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
title TEXT NOT NULL,
content TEXT NOT NULL
);
فایل را ذخیره کرده و ببندید.
اولین دستور SQL، DROP TABLE IF EXISTS posts; است، این کار هر جدولی را که از قبل به نام posts نامیده میشود حذف میکند تا شما دچار سردرگمی نشوید. توجه داشته باشید که هر زمان که از این دستورات SQL استفاده می کنید، تمام محتوایی که در پایگاه داده دارید حذف می شود، بنابراین مطمئن شوید که تا زمانی که این آموزش را به پایان نرسانید، محتوای مهمی را در برنامه وب ننویسید و نتیجه نهایی را آزمایش کنید. در مرحله بعد، CREATE TABLE posts برای ایجاد جدول posts با ستون های زیر استفاده می شود:
• id: یک عدد صحیح که یک کلید اصلی را نشان می دهد، برای هر ورودی (که یک پست وبلاگ است) یک مقدار منحصر به فرد توسط پایگاه داده به آن اختصاص می یابد.
• created: زمانی که پست وبلاگ در آن ایجاد شد. NOT NULL نشان دهنده این است که این ستون نباید خالی باشد و مقدار DEFAULT، همان مقدار CURRENT_TIMESTAMP می باشد، که زمانی است که پست به پایگاه داده اضافه شده است. درست مانند id، نیازی به تعیین مقدار برای این ستون ندارید، زیرا به طور خودکار پر می شود.
• title: عنوان پست
• content: محتوای پست.
اکنون که یک طرح SQL در فایل schema.sql دارید، از آن برای ایجاد پایگاه داده با استفاده از یک فایل پایتون استفاده خواهید کرد که یک فایل پایگاه داده SQLite .db ایجاد می کند. فایلی به نام init_db.py را در دایرکتوری flask_blog با استفاده از ویرایشگر دلخواه خود باز کنید:
(env)sammy@localhost:$ nano init_db.py
سپس کد زیر را اضافه کنید:
import sqlite3
connection = sqlite3.connect(‘database.db’)
with open(‘schema.sql’) as f:
connection.executescript(f.read())
cur = connection.cursor()
cur.execute(“INSERT INTO posts (title, content) VALUES (?, ?)”,
(‘First Post’, ‘Content for the first post’)
)
cur.execute(“INSERT INTO posts (title, content) VALUES (?, ?)”,
(‘Second Post’, ‘Content for the second post’)
)
connection.commit()
connection.close()
ابتدا ماژول sqlite3 را وارد کنید و سپس یک اتصال به یک فایل پایگاه داده به نام database.db باز کنید که پس از اجرای فایل پایتون ایجاد می شود. سپس از تابع open() برای باز کردن فایل schema.sql استفاده کنید. سپس محتویات آن را با استفاده از متد executescript() که چندین دستور SQL را همزمان اجرا میکند، که نیز باعث ایجاد جدول posts می شود، اجرا کنید. شما یک هدف Cursor ایجاد می کنید که به شما امکان می دهد از متد execute() آن برای اجرای دو عبارت SQL INSERT برای اضافه کردن دو پست وبلاگ به جدول posts خود استفاده کنید. در نهایت، تغییرات را انجام دهید و اتصال را بندید.
فایل را ذخیره کرده و ببندید و سپس با استفاده از دستور python آن را در پایانه اجرا کنید:
(env)sammy@localhost:$ python init_db.py
پس از اتمام اجرای فایل، فایل جدیدی به نام database.db در دایرکتوری flask_blog شما ظاهر می شود. این بدان معنی است که شما با موفقیت پایگاه داده خود را راه اندازی کرده اید.
در مرحله بعد، پست هایی را که در پایگاه داده خود درج کرده اید بازیابی کرده و در صفحه اصلی برنامه خود نمایش دهید.
مرحله 5 – نمایش همه پست ها
اکنون که پایگاه داده خود را راه اندازی کرده اید، اکنون می توانید تابع نمایی index() را برای نمایش تمام پست هایی که در پایگاه داده خود دارید تغییر دهید.
فایل app.py را باز کنید تا تغییرات زیر را انجام دهید:
(env)sammy@localhost:$ nano app.py
برای اولین تغییر، ماژول sqlite3 را در بالای فایل وارد خواهید کرد:
import sqlite3
from flask import Flask, render_template
در مرحله بعد، یک تابع ایجاد می کنید که یک اتصال پایگاه داده ایجاد می کند و آن را برمی گرداند. آن را مستقیما پس از واردات اضافه کنید:
. .
from flask import Flask, render_template
def get_db_connection():
conn = sqlite3.connect(‘database.db’)
conn.row_factory = sqlite3.Row
return conn
این تابع get_db_connection() یک اتصال به فایل پایگاه داده database.db باز می کند و سپس ویژگی row_factory را روی sqlite3.Row قرار می دهد تا بتوانید به ستون ها دسترسی مبتنی بر نام داشته باشید. این بدان معناست که اتصال پایگاه داده سطر هایی (row) را برمی گرداند که مانند دیکشنری های معمولی پایتون عمل می کنند. در نهایت، این تابع، هدف اتصال conn را که برای دسترسی به پایگاه داده استفاده می کنید، برمی گرداند.
پس از تعریف تابع get_db_connection()، تابع index() را به شکل زیر تغییر دهید:
@app.route(‘/’)
def index():
conn = get_db_connection()
posts = conn.execute(‘SELECT * FROM posts’).fetchall()
conn.close()
return render_template(‘index.html’, posts=posts)
در این نسخه جدید تابع index()، ابتدا یک اتصال پایگاه داده را با استفاده از تابع get_db_connection() که قبلا تعریف کرده بودید باز می کنید. سپس یک پرس و جوی SQL را برای انتخاب همه ورودی ها از جدول posts اجرا می کنید. شما متد fetchall() را برای واکشی تمام ردیف های نتیجه پرس و جو پیاده سازی میکنید، این کار فهرستی از پست هایی را که در مرحله قبل در پایگاه داده درج کردهاید، باز میگرداند.
اتصال پایگاه داده را با استفاده از متد close() می بندید و نتیجه پردازش الگوی index.html را برمی گردانید. شما همچنین هدف posts را به عنوان آرگومان ارسال می کنید که حاوی نتایجی است که از پایگاه داده به دست آورده اید، این به شما امکان می دهد تا به پست های وبلاگ در قالب الگوی index.html دسترسی داشته باشید.
با انجام این تغییرات، فایل app.py را ذخیره کرده و ببندید.
اکنون که پست هایی را که از پایگاه داده واکشی کرده و به الگوی index.html منتقل کرده اید، می توانید از حلقه for برای نمایش هر پست در صفحه فهرست خود استفاده کنید. فایل index.html را باز کنید:
(env)sammy@localhost:$ nano templates/index.html
سپس، آن را به شکلی تغییر دهید تا همانند زیر دیده شود:
{% extends ‘base.html’ %}
{% block content %}
<h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
{% for post in posts %}
<a href=”#”>
<h2>{{ post[‘title’] }}</h2>
</a>
<span class=”badge badge-primary”>{{ post[‘created’] }}</span>
<hr>
{% endfor %}
{% endblock %}
در اینجا، نحو {% for post in posts %} یک Jinja for (برای) حلقه است، که شبیه به یک پایتون for (برای) حلقه است به جز اینکه باید بعدا با نحو {% endfor %} بسته شود. شما با استفاده از این نحو به هر مورد که در لیست posts است که توسط تابع index() در خط return render_template(‘index.html’, posts=posts) منتقل شده است، تکرار می کنید. در داخل این for حلقه، شما عنوان پست را، تحت عنوان <h2> در داخل یک برچسب <a> نمایش می دهد (شما بعدا از این برچسب برای پیوند دادن هر پست به صورت جداگانه استفاده خواهید کرد).
شما عنوان را با استفاده از دلیمیتر (تعیین کننده) متغیر لفظی(دقیق) ( {{ … }} ) نمایش می دهید. به یاد داشته باشید که post یک هدف مانند فرهنگ لغت خواهد شد، بنابراین شما می توانید به عنوان پست با post[‘title’] دسترسی داشته باشید. شما همچنین تاریخ ایجاد پست را با استفاده از همان روش نمایش می دهید.
هنگامی که شما ویرایش فایل را به اتمام رساندید، ذخیره کرده و ببندید. سپس به صفحه فهرست در مرورگر خود بروید. دو پست اضافه شده به پایگاه داده در صفحه خود را خواهید دید.
اکنون که تابع نمایی index() را برای نمایش همه پست هایی که در پایگاه داده در صفحه اصلی برنامه خود دارید تغییر داده اید، به نمایش هر پست در یک صفحه خواهید پرداخت و به کاربران اجازه میدهید به هر پست به صورت جداگانه بپیوندند.
مرحله 6 – نمایش یک پست
در این مرحله، یک مسیر Flask جدید با یک تابع نمایی و یک الگوی HTML جدید برای نمایش یک پست وبلاگ جداگانه با شناسه (ID) آن ایجاد خواهید کرد.
در پایان این مرحله، http://127.0.0.1:5000/1 URL صفحه ای خواهد بود که اولین پست را نمایش می دهد (زیرا دارای شناسه 1 می باشد).
URL http://127.0.0.1:5000/ ID، پست را با شماره ID مربوطه در صورت وجود نشان می دهد.
برای ویرایش، app.py را باز کنید:
(env)sammy@localhost:$ nano app.py
از آن جایی که بعدا در این پروژه باید یک پست وبلاگ را با ID آن از پایگاه داده در چندین مکان دریافت کنید، یک تابع مستقل به نام get_post() ایجاد خواهید کرد. میتوانید با ارسال ID آن را فرا بخوانید و پست وبلاگ مرتبط با ID ارائه شده را دریافت کنید، یا اگر پست وبلاگ وجود نداشت، Flask را مجبور کنید با پیام 404 Not Found پاسخ دهد.
برای پاسخ دادن با صفحه 404، باید تابع abort() را از کتابخانه Werkzeug که به همراه Flask در بالای فایل نصب شده بود، وارد کنید:
import sqlite3
from flask import Flask, render_template
from werkzeug.exceptions import abort
سپس تابع get_post() را درست بعد از تابع get_db_connection() که در مرحله قبل ایجاد کرده اید، اضافه کنید:
def get_db_connection():
conn = sqlite3.connect(‘database.db’)
conn.row_factory = sqlite3.Row
return conn
def get_post(post_id):
conn = get_db_connection()
post = conn.execute(‘SELECT * FROM posts WHERE id = ?’,
(post_id,)).fetchone()
conn.close()
if post is None:
abort(404)
return post
این تابع جدید دارای یک آرگومان post_id است که تعیین میکند کدام پست وبلاگ را برگرداند.
در داخل تابع، از تابع get_db_connection() برای باز کردن یک اتصال پایگاه داده و اجرای یک پرس و جو SQL برای دریافت پست وبلاگ مرتبط با مقدار post_id داده شده استفاده می کنید. شما متد fetchone() را برای به دست آوردن نتیجه اضافه می کنید و آن را در متغیر post ذخیره می کنید و سپس اتصال را می بندید. اگر متغیر post، مقدار None را داشته باشد، به این معنی می باشد که هیچ نتیجه ای در پایگاه داده پیدا نشد، از تابع abort() که قبلا وارد کرده بودید برای پاسخ با یک کد خطای 404 استفاده می کنید و تابع عملکرد اجرا را به پایان می رساند. با این حال، اگر پستی پیدا شد، مقدار متغیر post را برمی گردانید. سپس تابع نمایی زیر را در انتهای فایل app.py اضافه کنید:
@app.route(‘/<int:post_id>’)
def post(post_id):
post = get_post(post_id)
return render_template(‘post.html’, post=post)
در این تابع نمایی جدید، یک قانون متغیر <int:post_id> را اضافه میکنید تا مشخص کنید که قسمت بعد از اسلش (/) یک عدد صحیح مثبت (که با مبدل intمشخص شده است) باشد که باید در تابع نمایی خود به آن دسترسی داشته باشید. Flask این را تشخیص می دهد و مقدار آن را به کلمه کلیدی آرگومان post_id تابع نمایی post() شما می دهد. سپس از تابع get_post() برای دریافت پست وبلاگ مرتبط با ID مشخص شده استفاده میکنید و نتیجه را در متغیر post ذخیره میکنید، که آن را به یک الگوی post.html که به زودی ایجاد خواهید کرد، منتقل میکنید.
فایل app.py را ذخیره کنید و یک فایل الگوی جدید post.html را برای ویرایش باز کنید:
(env)sammy@localhost:$ nano templates/post.html
کد زیر را در فایل post.html جدید تایپ کنید. این شبیه به فایل index.html خواهد بود، با این تفاوت که علاوه بر نمایش محتوای پست، فقط یک پست را نمایش می دهد:
{% extends ‘base.html’ %}
{% block content %}
<h2>{% block title %} {{ post[‘title’] }} {% endblock %}</h2>
<span class=”badge badge-primary”>{{ post[‘created’] }}</span>
<p>{{ post[‘content’] }}</p>
{% endblock %}
شما بلوک title را که در الگوی base.html تعریف کردهاید اضافه میکنید تا عنوان صفحه منعکس کننده عنوان پست باشد که در یک عنوان <h2> همزمان نمایش داده میشود.
ذخیره کنید و فایل را ببندید.
اکنون میتوانید به URL های زیر بروید تا دو پستی را که در پایگاه داده خود دارید مشاهده کنید، همراه با صفحه ای که به کاربر میگوید پست وبلاگ درخواستی پیدا نشد (زیرا تا کنون پستی با شماره ID 3 وجود ندارد) :
http://127.0.0.1:5000/1http://127.0.0.1:5000/2http://127.0.0.1:5000/3
با بازگشت به صفحه فهرست، عنوان هر پست را به صفحه مربوطه خود پیوند می دهید. این کار را با استفاده از تابع url_for() انجام خواهید داد. ابتدا الگوی index.html را برای ویرایش باز کنید:
(env)sammy@localhost:$ nano templates/index.html
سپس مقدار مشخصه href را از # به
{{ url_for(‘post’, post_id=post[‘id’]) }} تغییر دهید تا حلقه for دقیقا به شکل زیر باشد:
{% for post in posts %}
<a href=”{{ url_for(‘post’, post_id=post[‘id’]) }}”>
<h2>{{ post[‘title’] }}</h2>
</a>
<span class=”badge badge-primary”>{{ post[‘created’] }}</span>
<hr>
{% endfor %}
در اینجا، ‘post’را به تابع url_for() به عنوان اولین آرگومان ارسال می کنید. این نام تابع نمایی post() است و از آن جایی که آرگومان post_id را می پذیرد، شما مقدار post[‘id’] را به آن می دهید. تابع url_for()، URL مناسب برای هر پست را بر اساس ID آن برمی گرداند.
ذخیره کرده و فایل را ببندید.
پیوند های موجود در صفحه فهرست اکنون مطابق انتظار عمل خواهند کرد. با این کار، اکنون ساخت بخشی از برنامه که مسئول نمایش پست های وبلاگ در پایگاه داده شما است را به پایان رسانده اید. در مرحله بعد، توانایی ایجاد، ویرایش و حذف پست های وبلاگ را به برنامه خود اضافه خواهید کرد.
مرحله 7 – اصلاح پست ها
اکنون که نمایش پست های وبلاگ موجود در پایگاه داده در برنامه وب خود را به پایان رسانده اید، باید به کاربران برنامه خود اجازه دهید پست های وبلاگ جدید بنویسند و آنها را به پایگاه داده اضافه کنند، پست های موجود را ویرایش کنند و موارد غیر ضروری را حذف کنند.
ایجاد یک پست جدید
تا این مرحله، شما برنامه ای دارید که پست ها را در پایگاه داده شما نمایش میدهد، اما هیچ راهی برای افزودن پست جدید ارائه نمی دهد، مگر اینکه مستقیما به پایگاه داده SQLite متصل شوید و یک پست را به صورت دستی اضافه کنید. در این بخش، صفحه ای ایجاد میکنید که میتوانید با ارائه عنوان و محتوای آن، یک پست در آن ایجاد کنید.
فایل app.py را برای ویرایش باز کنید:
(env)sammy@localhost:$ nano app.py
ابتدا موارد زیر را از چارچوب Flask وارد خواهید کرد:
• هدف request درخواست جهانی برای دسترسی به داده های درخواست ورودی که از طریق یک فرم HTML ارسال می شود.
• تابع url_for() برای تولید URL.
• تابع flash() برای نمایان کردن یک پیام در هنگامی که یک درخواست پردازش شده است.
• تابع redirect() برای هدایت مشتری به مکان دیگر.
واردات (imports) را مانند زیر به فایل خود اضافه کنید:
import sqlite3
from flask import Flask, render_template, request, url_for, flash, redirect
from werkzeug.exceptions import abort
تابع flash() پیام های نمایان شده (فلش) را در قسمت مرورگر مشتری ذخیره می کند که نیاز به تنظیم یک کلید مخفی دارد. این کلید مخفی برای ایمن سازی نشست ها (sessions) استفاده می شود که به Flask اجازه می دهد اطلاعات را از یک درخواست به درخواست دیگر به خاطر بسپارد، مانند انتقال از صفحه پست جدید به صفحه فهرست. کاربر می تواند به اطلاعات ذخیره شده در نشست دسترسی داشته باشد، اما نمی تواند آن را تغییر دهد مگر اینکه کلید مخفی را داشته باشد، بنابراین هرگز نباید به کسی اجازه دسترسی به کلید مخفی خود را بدهید. برای اطلاعات بیشتر به مستندات Flask برای نشست ها مراجعه کنید.
برای تنظیم یک کلید مخفی، یک پیکربندی SECRET_KEY از طریق هدف app.config به برنامه خود اضافه می کنید. قبل از تعریف تابع نمایی index() آن را مستقیما به دنبال تعریف app اضافه کنید:
app = Flask(__name__)
app.config[‘SECRET_KEY’] = ‘your secret key’
@app.route(‘/’)
def index():
conn = get_db_connection()
posts = conn.execute(‘SELECT * FROM posts’).fetchall()
conn.close()
return render_template(‘index.html’, posts=posts)
به یاد داشته باشید که کلید مخفی باید یک رشته تصادفی طولانی باشد.
پس از تنظیم یک کلید مخفی، یک تابع نمایی ایجاد می کنید که یک الگو را نمایش می دهد که فرمی را نشان می دهد که می توانید برای ایجاد یک پست وبلاگ جدید پر کنید. این تابع جدید را در پایین فایل اضافه کنید:
@app.route(‘/create’, methods=(‘GET’, ‘POST’))
def create():
return render_template(‘create.html’)
این یک مسیر /create ایجاد می کند که هر دو درخواست GET و POST را می پذیرد. درخواست های GET به طور پیش فرض پذیرفته می شوند. همچنین برای پذیرش درخواست های POST، که توسط مرورگر هنگام ارسال فرم ها ارسال میشوند، یک tuple (ساختار داده ای چند بخشی) با انواع درخواست های پذیرفته شده را به آرگومان methods تزئینکننده @app.route() ارسال میکنید.
ذخیره کنید و فایل را ببندید.
برای ایجاد الگو، فایلی به نام create.html در پوشه templates خود باز کنید:
(env)sammy@localhost:$ nano templates/create.html
کد زیر را داخل این فایل جدید اضافه کنید:
{% extends ‘base.html’ %}
{% block content %}
<h1>{% block title %} Create a New Post {% endblock %}</h1>
<form method=”post”>
<div class=”form-group”>
<label for=”title”>Title</label>
<input type=”text” name=”title”
placeholder=”Post title” class=”form-control”
value=”{{ request.form[‘title’] }}”></input>
</div>
<div class=”form-group”>
<label for=”content”>Content</label>
<textarea name=”content” placeholder=”Post content”
class=”form-control”>{{ request.form[‘content’] }}</textarea>
</div>
<div class=”form-group”>
<button type=”submit” class=”btn btn-primary”>Submit</button>
</div>
</form>
{% endblock %}
اکثر این کد ها HTML استاندارد هستند. یک کادر ورودی برای عنوان پست، یک قسمت متنی برای محتوای پست و یک دکمه برای ارسال فرم نمایش داده می شود.
مقدار ورودی عنوان پست {{ request.form[‘title’] }} است و ناحیه متن دارای مقدار {{ request.form[‘content’] }} است، این کار به گونه ای انجام می شود که اگر مشکلی پیش آمد داده هایی که وارد می کنید گم نشوند. به عنوان مثال، اگر یک پست طولانی بنویسید و فراموش کردید که آن را عنوان کنید، پیامی نمایش داده می شود که به شما اطلاع می دهد که عنوان لازم است. این بدون از دست دادن پستی که نوشته اید اتفاق میافتد زیرا در هدف جهانی request که در الگو های خود به آن دسترسی دارید ذخیره میشود.
اکنون، با اجرای سرور توسعه، از مرورگر خود برای جهت یابی به مسیر /create استفاده کنید:
http://127.0.0.1:5000/create
این فرم یک درخواست POST را به تابع نمایی create() شما ارسال می کند. با این حال، هنوز کدی برای رسیدگی به درخواست POST در تابع وجود ندارد، بنابراین پس از پر کردن فرم و ارسال آن، هیچ اتفاقی نمیافتد.
هنگام ارسال فرم، درخواست POST دریافتی را رسیدگی خواهید کرد. این کار را در داخل تابع نمایی create() انجام خواهید داد. شما می توانید به طور جداگانه درخواست POST را با بررسی مقدار request.method رسیدگی کنید. هنگامی که مقدار آن روی ‘POST’ تنظیم می شود، به این معنی است که درخواست، یک درخواست POST است، سپس به استخراج داده های ارسالی، تأیید اعتبار و درج آن در پایگاه داده خود ادامه می دهید.
فایل app.py را برای ویرایش باز کنید:
(env)sammy@localhost:$ nano app.py
تابع نمایی create() را طوری تغییر دهید که دقیقا به شکل زیر باشد:
@app.route(‘/create’, methods=(‘GET’, ‘POST’))
def create():
if request.method == ‘POST’:
title = request.form[‘title’]
content = request.form[‘content’]
if not title:
flash(‘Title is required!’)
else:
conn = get_db_connection()
conn.execute(‘INSERT INTO posts (title, content) VALUES (?, ?)’,
(title, content))
conn.commit()
conn.close()
return redirect(url_for(‘index’))
return render_template(‘create.html’)
در عبارت if شما اطمینان خواهید داشت که کد زیر فقط زمانی اجرا میشود که درخواست، یک درخواست POST از طریق مقایسه request.method == ‘POST’ باشد. سپس عنوان و محتوای ارسال شده را از هدف request.form استخراج می کنید که به شما امکان دسترسی به داده های فرم موجود در درخواست را می دهد. در صورت عدم ارائه عنوان، شرط if not title (عدم وجود عنوان) محقق می شود و پیامی به کاربر نشان می دهد که عنوان نیاز است. از طرف دیگر، اگر عنوان ارائه شده باشد، یک اتصال با تابع get_db_connection() باز میکنید و عنوان و محتوای دریافتی را در جدول posts وارد میکنید.
سپس تغییرات را در پایگاه داده انجام دهید و اتصال را ببندید. پس از افزودن پست وبلاگ به پایگاه داده، مشتری را با استفاده از تابع redirect() به صفحه فهرست هدایت میکنید و URL تولید شده توسط تابع url_for() را با مقدار ‘index’ به عنوان آرگومان ارسال میکنید.
ذخیره کنید و فایل را ببندید.
اکنون با استفاده از مرورگر وب خود به مسیر /create بروید:
http://127.0.0.1:5000/create
فرم را با عنوان دلخواه و مقداری محتوا پر کنید. پس از ارسال فرم، پست جدید را در صفحه فهرست مشاهده خواهید کرد.
در نهایت، پیام های نمایان شده را نمایش می دهید و پیوندی به نوار پیمایش در الگوی base.html اضافه میکنید تا به این صفحه جدید دسترسی آسان داشته باشید. فایل الگو را باز کنید:
(env)sammy@localhost:$ nano templates/base.html
فایل را با افزودن یک تگ <li> جدید به دنبال پیوند About در داخل تگ <nav>
ویرایش کنید. سپس یک حلقه loop for جدید را مستقیما بالای بلوک content (محتوا) اضافه کنید تا پیام های نمایان شده در زیر نوار پیمایش نمایش داده شود. این پیام ها در تابع ویژه get_flashed_messages() Flask موجود هستند:
<nav class=”navbar navbar-expand-md navbar-light bg-light”>
<a class=”navbar-brand” href=”{{ url_for(‘index’)}}”>FlaskBlog</a>
<button class=”navbar-toggler” type=”button” data-toggle=”collapse” data-target=”#navbarNav” aria-controls=”navbarNav” aria-expanded=”false” aria-label=”Toggle navigation”>
<span class=”navbar-toggler-icon”></span>
</button>
<div class=”collapse navbar-collapse” id=”navbarNav”>
<ul class=”navbar-nav”>
<li class=”nav-item”>
<a class=”nav-link” href=”#”>About</a>
</li>
<li class=”nav-item”>
<a class=”nav-link” href=”{{url_for(‘create’)}}”>New Post</a>
</li>
</ul>
</div>
</nav>
<div class=”container”>
{% for message in get_flashed_messages() %}
<div class=”alert alert-danger”>{{ message }}</div>
{% endfor %}
{% block content %} {% endblock %}
</div>
ذخیره کنید و فایل را ببندید. نوار پیمایش اکنون یک آیتم New Post (پست جدید) دارد که به مسیر /create پیوند می دهد.
ویرایش یک پست
برای اینکه یک وبلاگ به روز باشد، باید بتوانید پست های موجود خود را ویرایش کنید. این بخش شما را از طریق ایجاد یک صفحه جدید در برنامه خود راهنمایی می کند تا فرآیند ویرایش یک پست را ساده تر کنید.
ابتدا یک مسیر جدید به فایل app.py اضافه می کنید. تابع نمایی آن ID را دریافت می کند که باید ویرایش شود، URL با فرمت / post_id /edit با متغیر post_id، ID پست خواهد بود. فایل app.py را برای ویرایش باز کنید:
(env)sammy@localhost:$ nano app.py
سپس تابع نمایی edit() زیر را در انتهای فایل اضافه کنید. ویرایش یک پست موجود مشابه ایجاد یک پست جدید است، بنابراین این تابع نمایی مشابه تابع نمایی create() خواهد بود:
@app.route(‘/<int:id>/edit’, methods=(‘GET’, ‘POST’))
def edit(id):
post = get_post(id)
if request.method == ‘POST’:
title = request.form[‘title’]
content = request.form[‘content’]
if not title:
flash(‘Title is required!’)
else:
conn = get_db_connection()
conn.execute(‘UPDATE posts SET title = ?, content = ?’
‘ WHERE id = ?’,
(title, content, id))
conn.commit()
conn.close()
return redirect(url_for(‘index’))
return render_template(‘edit.html’, post=post)
پستی که ویرایش می کنید توسط URL تعیین می شود و Flask شماره ID را از طریق آرگومان id به تابع edit() می دهد. شما این مقدار را به تابع get_post() اضافه می کنید تا پست مرتبط با ID ارائه شده را از پایگاه داده دریافت کنید. داده های جدید در یک درخواست POST ارائه می شوند که در داخل شرط if request.method == ‘POST’ مدیریت می شود.
درست مانند زمانی که یک پست جدید ایجاد می کنید، ابتدا داده ها را از هدف request.form استخراج می کنید، سپس اگر عنوان یک مقدار خالی باشد، پیامی را نمایان میکنید، در غیر این صورت، اتصال پایگاه داده را باز می کنید. سپس جدول posts را با تنظیم عنوان جدید و محتوای جدید به روز می کنید که ID پست در پایگاه داده با ID ای که در URL بود برابر است.
در مورد درخواست GET، شما یک الگوی edit.html را ارائه می دهید که در متغیر post که مقدار برگشتی تابع get_post() را نگه می دارد، عبور می کند. از این برای نمایش عنوان و محتوای موجود در صفحه ویرایش استفاده خواهید کرد.
فایل را ذخیره کرده و ببندید، سپس یک الگوی جدید edit.html ایجاد کنید:
(env)sammy@localhost:$ nano templates/edit.html
کد زیر را داخل این پوشه جدید وارد کنید:
{% extends ‘base.html’ %}
{% block content %}
<h1>{% block title %} Edit “{{ post[‘title’] }}” {% endblock %}</h1>
<form method=”post”>
<div class=”form-group”>
<label for=”title”>Title</label>
<input type=”text” name=”title” placeholder=”Post title”
class=”form-control”
value=”{{ request.form[‘title’] or post[‘title’] }}”>
</input>
</div>
<div class=”form-group”>
<label for=”content”>Content</label>
<textarea name=”content” placeholder=”Post content”
class=”form-control”>{{ request.form[‘content’] or post[‘content’] }}</textarea>
</div>
<div class=”form-group”>
<button type=”submit” class=”btn btn-primary”>Submit</button>
</div>
</form>
<hr>
{% endblock %}
ذخیره کنید و فایل را ببندید.
این کد از الگوی مشابهی به جز نحو های
{{ request.form[‘title’] or post[‘title’] }}
و {{ request.form[‘content’] or post[‘content’] }} پیروی می کند. این داده های ذخیره شده در درخواست را در صورت وجود نشان می دهد، در غیر این صورت داده های متغیر post را که به الگوی حاوی داده های پایگاه داده فعلی ارسال شده است، نمایش میدهد. اکنون برای ویرایش پست اول به URL زیر بروید:
http://127.0.0.1:5000/1/edit
یک صفحه ویرایش “پست اول” خواهید دید.
پست را ویرایش کنید و فرم را ارسال کنید، سپس مطمئن شوید که پست به روز شده است.
اکنون باید پیوندی اضافه کنید که به صفحه ویرایش برای هر پست در صفحه فهرست اشاره می کند. فایل الگوی index.html را باز کنید:
فایل را ویرایش دهید تا کاملا مشابه زیر باشد:
{% extends ‘base.html’ %}
{% block content %}
<h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
{% for post in posts %}
<a href=”{{ url_for(‘post’, post_id=post[‘id’]) }}”>
<h2>{{ post[‘title’] }}</h2>
</a>
<span class=”badge badge-primary”>{{ post[‘created’] }}</span>
<a href=”{{ url_for(‘edit’, id=post[‘id’]) }}”>
<span class=”badge badge-warning”>Edit</span>
</a>
<hr>
{% endfor %}
{% endblock %}
ذخیره کنید و فایل را ببندید.
در اینجا شما یک تگ <a> برای پیوند دادن به تابع نمایی edit() اضافه میکنید، و از مقدار post[‘id’] برای پیوند دادن به صفحه ویرایش هر پست با پیوند Edit عبور میکنید.
حذف یک پست
گاهی اوقات یک پست دیگر نیازی به در دسترس عموم بودن ندارد، به همین دلیل است که عملکرد حذف یک پست بسیار مهم است. در این مرحله شما قابلیت حذف را به اپلیکیشن خود اضافه خواهید کرد.
ابتدا، یک مسیر ID /delete جدید مشابه تابع نمایی edit() که درخواست های POST را می پذیرد، اضافه می کنید. تابع نمایی delete() جدید شما ID پستی را که باید از URL حذف شود دریافت می کند. فایل app.py را باز کنید:
تابع نمایی زیر را در انتهای فایل اضافه کنید:
@app.route(‘/<int:id>/delete’, methods=(‘POST’,))
def delete(id):
post = get_post(id)
conn = get_db_connection()
conn.execute(‘DELETE FROM posts WHERE id = ?’, (id,))
conn.commit()
conn.close()
flash(‘”{}” was successfully deleted!’.format(post[‘title’]))
return redirect(url_for(‘index’))
این تابع نمایی فقط درخواست های POST را می پذیرد. این بدان معناست که رهیابی به مسیر / ID /delete در مرورگر شما با خطا مواجه می شود زیرا مرورگر های وب به طور پیش فرض درخواست های GET را انجام می دهند.
با این حال، می توانید از طریق فرمی که درخواست POST را در ID پستی که می خواهید حذف کنید ارسال می کند، به این مسیر دسترسی پیدا کنید. تابع مقدار ID را دریافت می کند و از آن برای دریافت پست از پایگاه داده با تابع get_post() استفاده می کند.
سپس یک اتصال پایگاه داده باز می کنید و یک دستور DELETE FROM SQL را برای حذف پست اجرا می کنید. شما تغییر را در پایگاه داده انجام می دهید و اتصال را می بندید همزمان یک پیام به کاربر اطلاع می دهد که پست با موفقیت حذف شده است و آنها را به صفحه فهرست هدایت می کند.
توجه داشته باشید که شما یک فایل الگو را ارائه نمی دهید، زیرا فقط یک دکمه Delete (حذف) را به صفحه ویرایش اضافه می کنید.
فایل الگوی edit.html را باز کنید:
(env)sammy@localhost:$ nano templates/edit.html
سپس تگ <form> زیر را بعد از تگ <hr> و مستقیما قبل از خط {% endblock %} اضافه کنید:
<hr>
<form action=”{{ url_for(‘delete’, id=post[‘id’]) }}” method=”POST”>
<input type=”submit” value=”Delete Post”
class=”btn btn-danger btn-sm”
onclick=”return confirm(‘Are you sure you want to delete this post?’)”>
</form>
{% endblock %}
شما از متد confirm() برای نمایش پیام تایید قبل از ارسال درخواست استفاده خواهید کرد.
اکنون دوباره به صفحه ویرایش یک پست وبلاگ بروید و سعی کنید آن را حذف کنید:
http://127.0.0.1:5000/ 1 /edit
در پایان این مرحله، کد منبع پروژه شما مانند کد موجود در این صفحه خواهد بود. اکنون با استفاده از این، کاربران برنامه شما می توانند پست های جدید بنویسند و آنها را به پایگاه داده اضافه کنند؛ پست های موجود را ویرایش و حذف کنند./
دیدگاهتان را بنویسید