از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
راهنمای Flask-MongoEngine در پایتون
سرفصلهای مطلب
معرفی
ساختن یک برنامه وب تقریباً همیشه به معنای پرداختن به داده های یک پایگاه داده است. بسته به پایگاه داده های مختلفی برای انتخاب وجود دارد روی ترجیح شما
در این راهنما، ما باید به روش ادغام یکی از محبوب ترین پایگاه داده های NoSQL نگاهی بیندازیم – MongoDB – با میکروفریمورک Flask.
در این راهنما، روش ادغام MongoDB با Flask با استفاده از یک کتابخانه محبوب را بررسی خواهیم کرد – MongoEngineو به طور خاص، لفاف آن – Flask-MongoEngine.
از طرف دیگر، می توانید MongoDB را با Flask-PyMongo ادغام کنید.
Flask-MongoEngine
MongoEngine یک ODM (نقشهنگار سند شی) که کلاسهای پایتون (مدلها) را به اسناد MongoDB نگاشت میکند و ایجاد و دستکاری اسناد را به صورت برنامهنویسی مستقیماً از کد ما آسان میکند.
راه اندازی و پیکربندی
برای بررسی برخی از ویژگی های MongoEngine، یک API فیلم ساده ایجاد می کنیم که به ما امکان می دهد عملیات CRUD را انجام دهیم. روی Movie
نمونه ها
برای شروع، اجازه دهید Flask را نصب کنیم اگر قبلاً آن را ندارید:
$ pip install flask
در مرحله بعد، ما به یک نمونه MongoDB نیاز داریم، MongoDB یک نمونه ابری را فراهم می کند – MongoDB Atlas – که می توانیم به صورت رایگان از آن استفاده کنیم، با این حال، از یک نمونه نصب شده محلی استفاده خواهیم کرد. دستورالعملهای دریافت و نصب MongoDB را میتوانید در این قسمت پیدا کنید اسناد رسمی.
و با انجام این کار، ما همچنین می خواهیم کتابخانه Flask-MongoEngine را نصب کنیم:
$ pip install flask-mongoengine
اتصال به یک نمونه پایگاه داده MongoDB
اکنون که Flask و Flask-MongoEngine را نصب کرده ایم، باید برنامه Flask خود را با یک نمونه MongoDB متصل کنیم.
ما با وارد کردن Flask و Flask-MongoEngine به برنامه خود شروع خواهیم کرد:
from flask import Flask
from flask_mongoengine import MongoEngine
سپس، می توانیم شی برنامه Flask را ایجاد کنیم:
app = Flask(__name__)
که ما از آن برای مقداردهی اولیه a استفاده خواهیم کرد MongoEngine
هدف – شی. اما قبل از اینکه مقداردهی اولیه انجام شود، به نمونه MongoDB خود نیاز داریم.
این مرجع یک کلید در است app.config
که مقدار آن یک فرهنگ لغت حاوی پارامترهای اتصال است:
app.config('MONGODB_SETTINGS') = {
'db':'db_name',
'host':'localhost',
'port':'27017'
}
ما همچنین میتوانیم یک URI اتصال ارائه کنیم:
app.config('MONGODB_SETTINGS') = {
'host':'mongodb://localhost/db_name'
}
با انجام تنظیمات، اکنون می توانیم a را مقداردهی اولیه کنیم MongoEngine
هدف – شی:
db = MongoEngine(app)
ما همچنین می توانیم استفاده کنیم init_app()
روش از MongoEngine
شی برای مقداردهی اولیه:
db = MongoEngine()
db.init_app(app)
هنگامی که پیکربندی و مقداردهی اولیه انجام شد، می توانیم برخی از ویژگی های شگفت انگیز MongoEngine را بررسی کنیم.
ایجاد کلاس های مدل
به عنوان یک ODM، MongoEngine از کلاس های پایتون برای نمایش اسناد در پایگاه داده ما استفاده می کند.
MongoEngine انواع مختلفی از کلاس های اسناد را ارائه می دهد:
- سند
- EmbeddedDocument
- Dynamic Document
- DynamicEmbeddedDocument
سند
این نشان دهنده سندی است که مجموعه خود را در پایگاه داده دارد که با ارث بردن از آن ایجاد شده است mongoengine.Document
یا از ما MongoEngine
نمونه، مثال (db.Document
):
class Movie(db.Document):
title = db.StringField(required=True)
year = db.IntField()
rated = db.StringField()
director = db.ReferenceField(Director)
cast = db.EmbeddedDocumentListField(Cast)
poster = db.FileField()
imdb = db.EmbeddedDocumentField(Imdb)
MongoEngine همچنین کلاسهای اضافی را ارائه میکند که نوع دادههایی را که فیلدهای یک سند باید بگیرند و تأیید میکنند و اصلاحکنندههای اختیاری برای اضافه کردن جزئیات یا محدودیتهای بیشتر به هر فیلد ارائه میکند.
نمونه هایی از فیلدها عبارتند از:
StringField()
برای مقادیر رشتهIntField()
برای مقادیر intListField()
برای یک لیستFloatField()
برای مقادیر ممیز شناورReferenceField()
برای ارجاع به اسناد دیگرEmbeddedDocumentField()
برای اسناد جاسازی شده و غیرهFileField()
برای ذخیره فایل ها (بیشتر روی این بعدا)
همچنین می توانید اصلاح کننده هایی را در این زمینه ها اعمال کنید، مانند:
required
default
unique
primary_key
و غیره.
با تنظیم هر یک از اینها به True
، آنها به طور خاص در آن زمینه اعمال خواهند شد.
EmbeddedDocument
این نشان دهنده سندی است که مجموعه خود را در پایگاه داده ندارد، اما در سند دیگری جاسازی شده است، با ارث بردن از EmbeddedDocument
کلاس:
class Imdb(db.EmbeddedDocument):
imdb_id = db.StringField()
rating = db.DecimalField()
votes = db.IntField()
Dynamic Document
این سندی است که فیلدهای آن به صورت پویا و با بهرهگیری از ماهیت پویا MongoDB اضافه میشوند.
مانند انواع دیگر اسناد، MongoEngine
کلاسی را برای DynamicDocument
:
class Director(db.DynamicDocument):
pass
DynamicEmbeddedDocument
این همه خواص از DynamicDocument
و EmbeddedDocument
class Cast(db.DynamicEmbeddedDocument):
pass
از آنجایی که ما ساخت تمام کلاس های داده خود را به پایان رساندیم، زمان آن رسیده است که برخی از ویژگی های MongoEngine را شروع کنیم.
دسترسی به اسناد
MongoEngine پرس و جو از پایگاه داده ما را بسیار آسان می کند، ما می توانیم تمام فیلم های موجود در پایگاه داده را به این صورت دریافت کنیم.
from flask import jsonify
@app.route('/movies')
def get_movies():
movies = Movie.objects()
return jsonify(movies), 200
اگر درخواست GET را به این آدرس ارسال کنیم:
localhost:5000/movies/
این همه فیلم ها را به عنوان یک لیست JSON برمی گرداند:
(
{
"_id": {
"$oid": "600eb604b076cdbc347e2b99"
},
"cast": (),
"rated": "5",
"title": "Movie 1",
"year": 1998
},
{
"_id": {
"$oid": "600eb604b076cdbc347e2b9a"
},
"cast": (),
"rated": "4",
"title": "Movie 2",
"year": 1999
}
)
هنگامی که با نتایج بزرگ از پرس و جوهایی مانند این سروکار دارید، باید آنها را کوتاه کنید و به کاربر نهایی اجازه دهید به آرامی موارد بیشتری را در صورت نیاز بارگذاری کند.
Flask-MongoEngine به ما اجازه می دهد تا نتایج را به راحتی صفحه بندی کنیم:
@app.route('/movies')
def get_movies():
page = int(request.args.get('page',1))
limit = int(request.args.get('limit',10))
movies = Movie.objects.paginate(page=page, per_page=limit)
return jsonify((movie.to_dict() for movie in movies.items)), 200
این Movie.objects.paginate(page=page, per_page=limit)
برمی گرداند a Pagination
شی که شامل لیست فیلم های موجود در آن است .items
ملک، با تکرار از طریق ملک، فیلم های خود را دریافت می کنیم روی انتخاب شده page:
(
{
"_id": {
"$oid": "600eb604b076cdbc347e2b99"
},
"cast": (),
"rated": "5",
"title": "Back to The Future III",
"year": 1998
},
{
"_id": {
"$oid": "600fb95dcb1ba5529bbc69e8"
},
"cast": (),
"rated": "4",
"title": "Spider man",
"year": 2004
},
...
)
گرفتن یک سند
ما می توانیم یک تک را بازیابی کنیم Movie
نتیجه با ارسال id به عنوان پارامتر به Movie.objects()
روش:
@app.route('/movies/<id>')
def get_one_movie(id: str):
movie = Movie.objects(id=id).first()
return jsonify(movie), 200
Movie.objects(id=id)
مجموعه ای از تمام فیلم هایی که id
مطابق با پارامتر و first()
اولی را برمی گرداند Movie
اگر چندین مورد وجود داشته باشد، در مجموعه queryset قرار دارد.
اگر درخواست GET را به این آدرس ارسال کنیم:
localhost:5000/movies/600eb604b076cdbc347e2b99
به این نتیجه خواهیم رسید:
{
"_id": {
"$oid": "600eb604b076cdbc347e2b99"
},
"cast": (),
"rated": "5",
"title": "Back to The Future III",
"year": 1998
}
برای بیشتر موارد استفاده، ما میخواهیم a را مطرح کنیم 404_NOT_FOUND
اگر هیچ سندی با سند ارائه شده مطابقت نداشته باشد، خطا می کند id
. Flask-MongoEngine ما را تحت پوشش خود قرار داده است first_or_404()
و get_or_404()
مجموعه پرسش های سفارشی:
@app.route('/movies/<id>')
def get_one_movie(id: str):
movie = Movie.objects.first_or_404(id=id)
return movie.to_dict(), 200
ایجاد/ذخیره اسناد
MongoEngine ایجاد اسناد جدید با استفاده از مدل های ما را بسیار آسان می کند. تنها کاری که باید انجام دهیم این است که با save()
روش روی نمونه کلاس مدل ما به شرح زیر است:
@app.route('/movies/', methods=("POST"))
def add_movie():
body = request.get_json()
movie = Movie(**body).save()
return jsonify(movie), 201
**body
بسته بندی را باز می کند body
فرهنگ لغت به Movie
شیء به عنوان پارامترهای نامگذاری شده به عنوان مثال اگر body = {"title": "Movie Title", "year": 2015}
، سپس Movie(**body)
معادل است Movie(title="Movie Title", year=2015)
اگر این درخواست را به localhost:5000/movies/
:
$ curl -X POST -H "Content-Type: application/json" \
-d '{"title": "Spider Man 3", "year": 2009, "rated": "5"}' \
localhost:5000/movies/
سند را ذخیره و برمی گرداند:
{
"_id": {
"$oid": "60290817f3918e990ba24f14"
},
"cast": (),
"director": {
"$oid": "600fb8138724900858706a56"
},
"rated": "5",
"title": "Spider Man 3",
"year": 2009
}
ایجاد اسناد با EmbeddedDocuments
برای افزودن یک سند جاسازی شده، ابتدا باید سندی را برای جاسازی ایجاد کنیم، سپس آن را به فیلد مناسب در مدل فیلم خود اختصاص دهیم:
@app.route('/movies-embed/', methods=("POST"))
def add_movie_embed():
imdb = Imdb(imdb_id="12340mov", rating=4.2, votes=7.9)
body = request.get_json()
movie = Movie(imdb=imdb, **body).save()
return jsonify(movie), 201
اگر این درخواست را ارسال کنیم:
$ curl -X POST -H "Content-Type: application/json"\
-d '{"title": "Batman", "year": 2016, "rated": "yes"}'\
localhost:5000/movies-embed/
این سند جدید اضافه شده را با سند جاسازی شده برمی گرداند:
{
"_id": {
"$oid": "601096176cc65fa421dd905d"
},
"cast": (),
"imdb": {
"imdb_id": "12340mov",
"rating": 4.2,
"votes": 7
},
"rated": "yes",
"title": "Batman",
"year": 2016
}
ایجاد اسناد پویا
از آنجایی که هیچ فیلدی در مدل تعریف نشده است، باید هر مجموعه دلخواه از فیلدها را به شی سند پویا خود ارائه دهیم.
شما می توانید هر تعداد فیلد را در اینجا قرار دهید، از هر نوع. حتی لازم نیست انواع فیلدها بین چندین سند یکسان باشد.
چند راه برای رسیدن به این هدف وجود دارد:
-
میتوانیم شی سند را با تمام فیلدهایی که میخواهیم اضافه کنیم، ایجاد کنیم، گویی درخواستی مانند آنچه تاکنون انجام دادهایم:
@app.route('/director/', methods=('POST')) def add_dir(): body = request.get_json() director = Director(**body).save() return jsonify(director), 201
-
میتوانیم ابتدا شی را ایجاد کنیم، سپس فیلدها را با استفاده از علامت نقطه اضافه کنیم و پس از اتمام کار، متد ذخیره را فراخوانی کنیم:
@app.route('/director/', methods=('POST')) def add_dir(): body = request.get_json() director = Director() director.name = body.get("name") director.age = body.get("age") director.save() return jsonify(director), 201
-
و در نهایت، می توانیم از پایتون استفاده کنیم
setattr()
روش:@app.route('/director/', methods=('POST')) def add_dir(): body = request.get_json() director = Director() setattr(director, "name", body.get("name")) setattr(director, "age", body.get("age")) director.save() return jsonify(director), 201
در هر صورت، ما می توانیم هر مجموعه ای از فیلدها را به عنوان یک اضافه کنیم DynamicDocument
پیاده سازی هیچ کدام را خودش تعریف نمی کند.
اگر درخواست POST را به localhost:5000/director/
:
$ curl -X POST -H "Content-Type: application/json"\
-d '{"name": "James Cameron", "age": 57}'\
localhost:5000/director/
این منجر به:
{
"_id": {
"$oid": "6029111e184c2ceefe175dfe"
},
"age": 57,
"name": "James Cameron"
}
به روز رسانی اسناد
برای به روز رسانی یک سند، سند دائمی را از پایگاه داده بازیابی می کنیم، فیلدهای آن را به روز می کنیم و آن را فراخوانی می کنیم update()
روش روی شی تغییر یافته در حافظه:
@app.route('/movies/<id>', methods=('PUT'))
def update_movie(id):
body = request.get_json()
movie = Movie.objects.get_or_404(id=id)
movie.update(**body)
return jsonify(str(movie.id)), 200
بیایید یک درخواست به روز رسانی ارسال کنیم:
$ curl -X PUT -H "Content-Type: application/json"\
-d '{"year": 2016}'\
localhost:5000/movies/600eb609b076cdbc347e2b9a/
این شناسه سند به روز شده را برمی گرداند:
"600eb609b076cdbc347e2b9a"
همچنین میتوانیم بسیاری از اسناد را بهطور همزمان با استفاده از آن بهروزرسانی کنیم update()
روش. ما فقط از پایگاه داده برای اسنادی که قصد به روز رسانی آنها را داریم، با توجه به شرایطی، پرس و جو می کنیم و روش به روز رسانی را فراخوانی می کنیم روی Queryset حاصل:
@app.route('/movies_many/<title>', methods=('PUT'))
def update_movie_many(title):
body = request.get_json()
movies = Movie.objects(year=year)
movies.update(**body)
return jsonify((str(movie.id) for movie in movies)), 200
بیایید یک درخواست به روز رسانی ارسال کنیم:
$ curl -X PUT -H "Content-Type: application/json"\
-d '{"year": 2016}'\
localhost:5000/movies_many/2010/
با این کار فهرستی از شناسههای اسناد بهروز شده را نشان میدهد:
(
"60123af478a2c347ab08c32b",
"60123b0989398f6965f859ab",
"60123bfe2a91e52ba5434630",
"602907f3f3918e990ba24f13",
"602919f67e80d573ad3f15e4"
)
حذف اسناد
بسیار شبیه به update()
روش، delete()
متد یک شی را بر اساس حذف می کند روی آن id
رشته:
@app.route('/movies/<id>', methods=('DELETE'))
def delete_movie(id):
movie = Movie.objects.get_or_404(id=id)
movie.delete()
return jsonify(str(movie.id)), 200
البته، از آنجایی که ممکن است تضمینی نداشته باشیم که یک شی با شناسه داده شده در پایگاه داده وجود دارد، از آن استفاده می کنیم get_or_404()
روش بازیابی آن، قبل از فراخوانی delete()
.
بیایید یک درخواست حذف ارسال کنیم:
$ curl -X DELETE -H "Content-Type: application/json"\
localhost:5000/movies/600eb609b076cdbc347e2b9a/
این منجر به:
"600eb609b076cdbc347e2b9a"
همچنین میتوانیم بسیاری از اسناد را به طور همزمان حذف کنیم. برای انجام این کار، از پایگاه داده اسنادی را که میخواهیم حذف کنیم پرس و جو میکنیم و سپس آن را فراخوانی میکنیم delete()
روش روی Queryset حاصل
برای مثال برای حذف همه فیلمهای ساخته شده در یک سال خاص، کاری شبیه به زیر انجام میدهیم:
@app.route('/movies/delete-by-year/<year>/', methods=('DELETE'))
def delete_movie_by_year(year):
movies = Movie.objects(year=year)
movies.delete()
return jsonify((str(movie.id) for movie in movies)), 200
بیایید یک درخواست حذف ارسال کنیم و همه ورودیهای فیلم سال را حذف کنیم 2009
:
$ curl -X DELETE -H "Content-Type: application/json" localhost:5000/movies/delete-by-year/2009/
این منجر به:
(
"60291fdd4756f7031638b703",
"60291fde4756f7031638b704",
"60291fdf4756f7031638b705"
)
کار با فایل ها
ایجاد و ذخیره فایل ها
MongoEngine ارتباط با MongoDB GridFS را برای ذخیره و بازیابی فایل ها بسیار آسان می کند. MongoEngine از طریق خود به این امر دست می یابد FileField()
.
بیایید نگاهی به روش آپلود فایل در MongoDB GridFS با استفاده از MongoEngine بیندازیم:
@app.route('/movies_with_poster', methods=('POST'))
def add_movie_with_image():
image = request.files('file')
movie = Movie(title = "movie with poster", year=2021)
movie.poster.put(image, filename=image.filename)
movie.save()
return jsonify(movie), 201
بیایید از بلوک بالا خط به خط عبور کنیم:
- ابتدا یک تصویر از کلید دریافت می کنیم
file
که درrequest.files
- بعد یک را ایجاد می کنیم
Movie
هدف – شی - برخلاف سایر فیلدها، ما نمی توانیم مقداری را به the اختصاص دهیم
FileField()
با استفاده از عملگر انتساب معمولی، در عوض، ما از آن استفاده خواهیم کردput()
روش ارسال تصویر ما اینput()
متد فایلی را که قرار است آپلود شود (این باید یک شی فایل مانند یا یک جریان بایت باشد)، نام فایل و ابرداده اختیاری را به عنوان آرگومان می گیرد. - برای ذخیره فایل خود، با شماره تماس می گیریم
save()
روش روی شی فیلم، طبق معمول. - را برمی گردانیم
movie
شی با یک شناسه ارجاع به تصویر:
{
"_id": {
"$oid": "60123e4d2628f541032a0900"
},
"cast": (),
"poster": {
"$oid": "60123e4d2628f541032a08fe"
},
"title": "movie with poster",
"year": 2021
}
همانطور که از پاسخ JSON می بینید، فایل در واقع به عنوان یک سند جداگانه MongoDB ذخیره می شود و ما فقط یک مرجع پایگاه داده به آن داریم.
بازیابی فایل ها
یک بار ما put()
یک فایل به a FileField()
، ما میتوانیم read()
هنگامی که یک شی حاوی آن فیلد را داشته باشیم، آن را به حافظه بازگردانیم. بیایید نگاهی به روش بازیابی فایل ها از اسناد MongoDB بیندازیم:
from io import BytesIO
from flask.helpers import send_file
@app.route('/movies_with_poster/<id>/', methods=('GET'))
def get_movie_image(id):
movie = Movie.objects.get_or_404(id=id)
image = movie.poster.read()
content_type = movie.poster.content_type
filename = movie.poster.filename
return send_file(
BytesIO(image),
attachment_filename=filename,
mimetype=content_type), 200
بیایید نگاهی به آنچه در بخشها انجام میشود بیندازیم:
- ما سند فیلم حاوی یک تصویر را بازیابی کردیم.
- سپس تصویر را به صورت رشته ای از بایت ها در قسمت ذخیره کردیم
image
متغیر، نام فایل و نوع محتوا را دریافت کرد و آنها را در آن ذخیره کردfilename
وcontent_type
متغیرها - با استفاده از Flask’s
send_file()
به روش helper سعی می کنیم فایل را برای کاربر ارسال کنیم اما از آنجایی که تصویر یک استbytes
شی، ما یک دریافت می کنیمAttributeError: 'bytes' object has no attribute 'read'
مانندsend_file()
منتظر یک شیء فایل مانند است، نه بایت. - برای حل این مشکل از
BytesIO()
کلاس ازio
ماژول برای رمزگشایی شی بایت به یک شی فایل مانند کهsend_file()
می تواند ارسال کند.
حذف فایل ها
حذف اسناد حاوی فایل ها، فایل را از GridFS حذف نمی کند، زیرا آنها به عنوان اشیاء جداگانه ذخیره می شوند.
برای حذف اسناد و فایل های همراه آنها، ابتدا باید فایل را قبل از حذف سند حذف کنیم.
FileField()
الف را نیز فراهم می کند delete()
روشی که می توانیم به سادگی آن را از پایگاه داده و سیستم فایل حذف کنیم، قبل از اینکه خود شیء را حذف کنیم:
@app.route('/movies_with_poster/<id>/', methods=('DELETE'))
def delete_movie_image(id):
movie = Movie.objects.get_or_404(id=id)
movie.poster.delete()
movie.delete()
return "", 204
نتیجه
MongoEngine یک رابط پایتونیک نسبتا ساده اما پر از ویژگی برای تعامل با MongoDB از یک python نرم افزار و Flask-MongoEngine ادغام MongoDB را در برنامه های Flask ما آسان تر می کند.
در این راهنما، برخی از ویژگی های MongoEngine و پسوند Flask آن را بررسی کرده ایم. ما یک CRUD API ساده ایجاد کردهایم و از MongoDB GridFS برای ذخیره، بازیابی و حذف فایلها با استفاده از MongoEngine استفاده کردهایم. در این راهنما، برخی از ویژگیهای MongoEngine و پسوند Flask آن را بررسی کردهایم. ما یک CRUD API ساده ایجاد کردهایم و از MongoDB GridFS برای ذخیره، بازیابی و حذف فایلها با استفاده از MongoEngine استفاده کردهایم.
(برچسبها به ترجمه)# python
منتشر شده در 1403-01-12 08:32:04