از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
ادغام H2 با پایتون و فلاسک
سرفصلهای مطلب
معرفی
H2 یک سرور پایگاه داده سبک وزن است که به زبان جاوا نوشته شده است. می توان آن را در برنامه های جاوا جاسازی کرد یا به عنوان یک سرور مستقل اجرا کرد.
در این آموزش دلیل آن را بررسی می کنیم H2 می تواند گزینه خوبی برای پروژه های شما باشد. همچنین روش ادغام را یاد خواهیم گرفت H2 با پایتون با ساخت یک ساده فلاسک API.
ویژگی های H2
H2 با در نظر گرفتن عملکرد ساخته شده است.
“H2 ترکیبی از: سریع، پایدار، آسان برای استفاده، و ویژگی ها.
با اینکه H2 برجسته است، عمدتاً به این دلیل که می تواند در برنامه های جاوا جاسازی شود، ویژگی های جالبی دارد که در نسخه سرور آن نیز اعمال می شود. بیایید برخی از آنها را در ادامه ببینیم.
اندازه و عملکرد
را .شیشه فایل مورد استفاده برای نسخه سرور حدود 2 مگابایت است. ما میتوانیم آن را از H2 سایت، همراه با اسکریپت ها و اسناد اضافی. اگر ما در Maven Central جستجو کنیم، می توانیم دانلود کنید .شیشه فایل روی خودش.
H2 عملکرد در نسخه تعبیه شده آن می درخشد. با این حال، معیار رسمی نشان می دهد که نسخه مشتری-سرور آن نیز چشمگیر است.
پایگاه های داده درون حافظه و رمزگذاری
پایگاه داده های درون حافظه پایدار نیستند. تمام داده ها در حافظه ذخیره می شوند، بنابراین سرعت به شدت افزایش می یابد.
را H2 سایت توضیح می دهد که پایگاه داده های In-Memory به ویژه هنگام نمونه سازی یا هنگام استفاده از پایگاه داده های فقط خواندنی مفید هستند.
رمزگذاری یکی دیگر از ویژگی های مفید برای محافظت از داده ها در حالت استراحت است. پایگاه های داده را می توان با رمزگذاری کرد AES-128 الگوریتم
سایر ویژگی های مفید
H2 همچنین یک حالت کلاستر، توانایی اجرای چندین سرور و اتصال آنها به یکدیگر را فراهم می کند. نوشته ها انجام می شود روی همه سرورها به طور همزمان، در حالی که خواندن از اولین سرور در کلاستر انجام می شود.
H2 شگفتی برای سادگی آن چندین ویژگی مفید را ارائه می دهد و تنظیم آن آسان است.
بیایید شروع کنیم H2 سرور در حال آماده سازی برای بخش های زیر:
$ java -cp ./h2-1.4.200.jar org.h2.tools.Server -tcp -tcpAllowOthers -tcpPort 5234 -baseDir ./ -ifNotExists
استدلال هایی که با tcp
برقراری ارتباط با سرور را ifNotExists
آرگومان اجازه می دهد تا پایگاه داده در هنگام دسترسی به آن برای اولین بار ایجاد شود.
توضیحات API و نمودار کلی
فرض کنید در حال نوشتن یک API برای ثبت تمام سیارات فراخورشیدی هستیم که تا به امروز پیدا شده اند. سیارات فراخورشیدی سیاراتی هستند که خارج از منظومه شمسی ما یافت می شوند و به دور ستارگان دیگر می چرخند.
اگر هنوز با ایجاد API های REST آشنا نیستید، راهنمای کامل ما برای ساخت API های REST با Spring Boot را بخوانید!
این ساده ماست تعریف API، یک CRUD برای یک منبع:
این تعریف به همراه بقیه کدهایی که در ادامه خواهیم دید در این موجود است مخزن GitHub.
برنامه ما در پایان این آموزش به این صورت خواهد بود:
در سمت چپ نمودار، API Client را می بینیم. آن کلاینت می تواند تابع “امتحانش کن” باشد ویرایشگر Swagger، یا هر مشتری دیگری مانند Postman یا cURL.
در طرف دیگر ما پیدا می کنیم H2 سرور پایگاه داده در حال اجرا روی پورت TCP 5234
همانطور که در بالا توضیح داده شد.
در نهایت، برنامه ما در وسط از سه فایل پایتون تشکیل شده است. اولین مورد را خواهد داشت فلاسک برنامه ای که به تمام درخواست های REST API پاسخ می دهد. تمام نقاط پایانی که در تعریف بالا توضیح دادیم به این فایل اضافه خواهند شد.
فایل دوم دارای توابع ماندگاری است که به پایگاه داده برای اجرای عملیات CRUD با استفاده از JayDeBeApi
بسته بندی
در نهایت، فایل سوم حاوی طرحی است که نشان دهنده منبعی است که API مدیریت می کند Exoplanet
. ما استفاده خواهیم کرد Marshmallow
بسته ای برای نشان دادن آن طرح. دو مورد اول python فایل ها از این طرح برای نمایش منابع و ارسال آنها به یکدیگر استفاده می کنند.
بیایید با فایل persistence شروع کنیم.
طرحواره پایگاه داده
برای ذخیره منبع Exoplanet در یک H2 ابتدا باید توابع اصلی CRUD را بنویسیم. بیایید با نوشتن ایجاد پایگاه داده شروع کنیم. ما استفاده می کنیم JayDeBeApi بسته دسترسی به پایگاه داده از طریق JDBC:
import jaydebeapi
def initialize():
_execute(
("CREATE TABLE IF NOT EXISTS exoplanets ("
" id INT PRIMARY KEY AUTO_INCREMENT,"
" name VARCHAR NOT NULL,"
" year_discovered SIGNED,"
" light_years FLOAT,"
" mass FLOAT,"
" link VARCHAR)"))
def _execute(query, returnResult=None):
connection = jaydebeapi.connect(
"org.h2.Driver",
"jdbc:h2:tcp://localhost:5234/exoplanets",
("SA", ""),
"../h2-1.4.200.jar")
cursor = connection.cursor()
cursor.execute(query)
if returnResult:
returnResult = _convert_to_schema(cursor)
cursor.close()
connection.close()
return returnResult
را initialize()
تابع به دلیل توابع کمکی بعد از آن به اندازه کافی ساده است. اگر جدول سیارات فراخورشیدی از قبل وجود نداشته باشد، میسازد. این تابع باید قبل از اینکه API ما شروع به دریافت درخواست کند، اجرا شود. بعداً خواهیم دید که این کار را با کجا انجام دهیم فلاسک.
را _execute()
تابع شامل رشته اتصال و اعتبار برای دسترسی به سرور پایگاه داده است. برای این مثال ساده تر است، اما در مورد امنیت جا برای بهبود وجود دارد. میتوانیم اعتبارنامههایمان را در جای دیگری ذخیره کنیم، مثلاً متغیرهای محیطی.
همچنین، ما مسیر را به H2 فایل jar به connect()
روش، زیرا دارای درایوری است که باید به آن وصل شویم H2 – org.h2.Driver
.
رشته اتصال JDBC به پایان می رسد /exoplanets
. این بدان معنی است که هنگام اتصال برای اولین بار یک پایگاه داده تماس می گیرد exoplanets
ایجاد خواهد شد.
شاید متوجه شده باشید _execute()
می تواند نتیجه پرس و جو SQL را با استفاده از _convert_to_schema()
تابع. حالا بیایید ببینیم که این تابع چگونه کار می کند.
مارشمالو طرحواره ها و توابع پایگاه داده CRUD
برخی از پرس و جوهای SQL نتایج جدولی، به ویژه SELECT
بیانیه. JayDeBeApi آن نتایج را به صورت لیستی از تاپل ها قالب بندی می کند. به عنوان مثال، برای طرحی که در قسمت آخر تعریف شده است، می توانیم نتیجه ای شبیه به این داشته باشیم:
>>> connection = jaydebeapi.connect(...
>>> cursor = connection.cursor()
>>> cursor.execute("SELECT * FROM exoplanets")
>>> cursor.fetchall()
((1, 'Sample1', 2019, 4.5, 1.2, 'http://sample1.com'))
هیچ چیز ما را از مدیریت نتایج در این قالب و در نهایت بازگرداندن آن به مشتری API باز نمی دارد. اما با نگاه به آینده می دانیم که استفاده خواهیم کرد فلاسک، بنابراین خوب است که از قبل نتایج را در قالبی که Flask توصیه می کند برگردانید.
به طور خاص، ما استفاده خواهیم کرد Flask-RESTful برای تسهیل استفاده از مسیرهای API. اون بسته توصیه می کند برای استفاده مارشمالو برای تجزیه درخواست ها این مرحله امکان عادی سازی اشیاء را فراهم می کند. به این ترتیب میتوانیم ویژگیهای ناشناخته را کنار بگذاریم و مثلاً خطاهای اعتبارسنجی را برجسته کنیم.
بیایید ببینیم کلاس Exoplanet چگونه به نظر می رسد تا بتوانیم بیشتر بحث کنیم:
from marshmallow import Schema, fields, EXCLUDE
class ExoplanetSchema(Schema):
id = fields.Integer(allow_none=True)
name = fields.Str(required=True, error_messages={"required": "An exoplanet needs at least a name"})
year_discovered = fields.Integer(allow_none=True)
light_years = fields.Float(allow_none=True)
mass = fields.Float(allow_none=True)
link = fields.Url(allow_none=True)
class Meta:
unknown = EXCLUDE
تعریف ویژگی ها آشنا به نظر می رسد. این همان طرحواره پایگاه داده، از جمله تعریف فیلدهای مورد نیاز است. همه فیلدها دارای نوعی هستند که اعتبار سنجی پیش فرض را تعریف می کند. به عنوان مثال link
فیلد به عنوان یک URL تعریف می شود، بنابراین رشته ای که شبیه URL نیست معتبر نخواهد بود.
پیامهای خطای خاص نیز میتوانند در اینجا گنجانده شوند، مانند اعتبارسنجی برای a name
.
برای این پروژه مثال، میخواهیم تمام فیلدهای ناشناختهای را که مشتریان API ممکن است به اشتباه ارسال کنند، کنار بگذاریم یا حذف کنیم. این امر در Meta
کلاس تو در تو
حالا می توانیم از load()
و loads()
مارشمالو روش هایی برای تبدیل و اعتبارسنجی منابع ما
اکنون که با آن آشنا شدیم مارشمالو، می توانیم توضیح دهیم که چیست _convert_to_schema()
میکند:
def _convert_to_schema(cursor):
column_names = (record(0).lower() for record in cursor.description)
column_and_values = (dict(zip(column_names, record)) for record in cursor.fetchall())
return ExoplanetSchema().load(column_and_values, many=True)
که در JayDeBeApi، نام ستون ها در ذخیره می شود description
فیلد مکان نما، در حالی که داده ها را می توان با استفاده از fetchall()
روش. ما از درک لیست در دو خط اول استفاده کردیم تا نام ستون ها و مقادیر و zip()
برای ادغام آنها
خط آخر نتیجه ادغام شده را می گیرد و آنها را به ExoplanetSchema
اشیاء که فلاسک می تواند بیشتر process.
حالا که توضیح دادیم _execute()
تابع و ExoplanetSchema
کلاس، بیایید تمام توابع پایگاه داده CRUD را ببینیم:
def get_all():
return _execute("SELECT * FROM exoplanets", returnResult=True)
def get(Id):
return _execute("SELECT * FROM exoplanets WHERE id = {}".format(Id), returnResult=True)
def create(exoplanet):
count = _execute("SELECT count(*) AS count FROM exoplanets WHERE name LIKE '{}'".format(exoplanet.get("name")), returnResult=True)
if count(0)("count") > 0:
return
columns = ", ".join(exoplanet.keys())
values = ", ".join("'{}'".format(value) for value in exoplanet.values())
_execute("INSERT INTO exoplanets ({}) VALUES({})".format(columns, values))
return {}
def update(exoplanet, Id):
count = _execute("SELECT count(*) AS count FROM exoplanets WHERE id = {}".format(Id), returnResult=True)
if count(0)("count") == 0:
return
values = ("'{}'".format(value) for value in exoplanet.values())
update_values = ", ".join("{} = {}".format(key, value) for key, value in zip(exoplanet.keys(), values))
_execute("UPDATE exoplanets SET {} WHERE id = {}".format(update_values, Id))
return {}
def delete(Id):
count = _execute("SELECT count(*) AS count FROM exoplanets WHERE id = {}".format(Id), returnResult=True)
if count(0)("count") == 0:
return
_execute("DELETE FROM exoplanets WHERE id = {}".format(Id))
return {}
همه توابع عمدتاً پرس و جوهای SQL هستند، اما create()
و update()
سزاوار توضیح بیشتر است
را INSERT
دستور SQL می تواند ستون و مقادیر جدا شده را در فرم دریافت کند INSERT INTO table (column1Name) VALUES ('column1Value')
. ما می توانیم استفاده کنیم join()
تابعی برای ادغام تمام ستون ها و جدا کردن آنها با کاما و انجام کاری مشابه برای پیوستن به تمام مقادیری که می خواهیم درج کنیم.
را UPDATE
دستور SQL کمی پیچیده تر است. شکل آن است UPDATE table SET column1Name = 'column1Value'
. بنابراین ما نیاز به جایگزینی کلیدها و مقادیر داشتیم و این کار را با استفاده از آن انجام دادیم zip()
تابع.
همه این توابع برمی گردند None
وقتی مشکلی وجود دارد بعداً وقتی با آنها تماس می گیریم باید آن مقدار را بررسی کنیم.
بیایید تمام توابع پایگاه داده را ذخیره کنیم روی فایل خودش persistence.py
، بنابراین می توانیم هنگام فراخوانی توابع مقداری متن اضافه کنیم، مانند این:
import persistence
persistence.get_all()
REST API با فلاسک
اکنون که یک لایه برای انتزاع دسترسی به پایگاه داده نوشتیم، آماده نوشتن REST API هستیم. ما استفاده خواهیم کرد فلاسک و Flask-RESTful بسته هایی که تعریف ما را تا حد امکان آسان می کند. همانطور که قبلا یاد گرفتیم، ما نیز استفاده خواهیم کرد مارشمالو برای اعتبارسنجی منابع
Flask-RESTful نیاز به تعریف یک کلاس برای هر منبع API دارد، در مورد ما Exoplanet
فقط منبع سپس می توانیم آن منبع را با مسیری مانند زیر مرتبط کنیم:
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class Exoplanet(Resource):
api.add_resource(Exoplanet, "/exoplanets", "/exoplanets/<int:Id>")
تمام مسیرهای ما از این طریق، /exoplanets
و /exoplanets/<int:Id>
به کلاسی که ما تعریف کردیم هدایت می شود.
به عنوان مثال GET /exoplanets
نقطه پایانی با روشی به نام پاسخ داده می شود get()
درون Exoplanet
کلاس چون ما هم داریم GET /exoplanet/<Id>
نقطه پایانی، آن get()
متد باید یک پارامتر اختیاری به نام داشته باشد Id
.
بیایید کل کلاس را ببینیم تا این را بهتر درک کنیم:
from flask import request
from flask_restful import Resource, abort
from marshmallow import ValidationError
import persistence
class Exoplanet(Resource):
def get(self, Id=None):
if Id is None:
return persistence.get_all()
exoplanet = persistence.get(Id)
if not exoplanet:
abort(404, errors={"errors": {"message": "Exoplanet with Id {} does not exist".format(Id)}})
return exoplanet
def post(self):
try:
exoplanet = ExoplanetSchema(exclude=("id")).loads(request.json)
if not persistence.create(exoplanet):
abort(404, errors={"errors": {"message": "Exoplanet with name {} already exists".format(request.json("name"))}})
except ValidationError as e:
abort(405, errors=e.messages)
def put(self, Id):
try:
exoplanet = ExoplanetSchema(exclude=("id")).loads(request.json)
if not persistence.update(exoplanet, Id):
abort(404, errors={"errors": {"message": "Exoplanet with Id {} does not exist".format(Id)}})
except ValidationError as e:
abort(405, errors=e.messages)
def delete(self, Id):
if not persistence.delete(Id):
abort(404, errors={"errors": {"message": "Exoplanet with Id {} does not exist".format(Id)}})
افعال HTTP باقی مانده به همان روش پردازش می شوند GET
، با روش های با نام post()
، put()
و delete()
.
همانطور که قبلاً گفتیم، خطاهای منطقی هنگام دسترسی به پایگاه داده باعث بازگشت توابع می شود None
. این خطاها در صورت نیاز در اینجا ثبت می شوند.
همچنین، استثناهایی که خطاهای اعتبارسنجی را نشان میدهند، توسط مارشمالو، بنابراین آن خطاها نیز ضبط می شوند و به همراه یک خطای بازگشت مناسب به کاربر بازگردانده می شوند.
نتیجه
H2 یک سرور پایگاه داده مفید، کارآمد و آسان برای استفاده است. اگرچه این یک بسته جاوا است، اما می تواند به عنوان یک سرور مستقل نیز اجرا شود، بنابراین می توانیم از آن در پایتون با JayDeBeApi
بسته بندی
در این آموزش ما یک برنامه ساده CRUD را برای نشان دادن روش دسترسی به پایگاه داده و اینکه کدام توابع در دسترس هستند تعریف کردیم. پس از آن یک REST API با آن تعریف کردیم فلاسک و Flask-RESTful.
اگرچه چندین مفهوم به دلیل اختصار حذف شده است، مانند احراز هویت و صفحه بندی، این آموزش مرجع خوبی برای شروع استفاده است. H2 در ما فلاسک پروژه ها.
(برچسبها به ترجمه)# python
منتشر شده در 1403-01-16 18:08:03