اذهب إلى المحتوى

سامح أشرف

الأعضاء
  • المساهمات

    2934
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    56

كل منشورات العضو سامح أشرف

  1. يمكنك أن تستخدم التابع filter والذي يعيد مصفوفة جديدة تحتوي على بعض العناصر المطابقة للشروط، وهنا مثال بسيط: let books = [ [1,"Start with why","Simon Sinek",80.0,13], [2,"But how do it know","J. Clark Scott",59.9,22], [3,"Clean Code","Robert Cecil Martin",50.0,5], [4,"Zero to One","Peter Thiel",47,12], [5,"You don't know JS","Kyle Simpson",39.9,9] ]; // البحث عن الكتاب الذي يحمل الاسم Clean Code books.filter(book => book[1] == "Clean Code"); // [[3, 'Clean Code', 'Robert Cecil Martin', 50, 5]] // البحث عن الكتب التي لديها سعر أقل من 50 books.filter(book => book[3] < 50); // [[4, 'Zero to One', 'Peter Thiel', 47, 12], [5, "You don't know JS", 'Kyle Simpson', 39.9, 9]] // البحث عن كتب المؤلف Kyle Simpson books.filter(book => book[2] == "Kyle Simpson"); // [[5, "You don't know JS", 'Kyle Simpson', 39.9, 9]] يمكنك القراءة أكثر حول التابع filter وكيفية إستخدامه من خلال موسوعة حسوب من هنا.
  2. إن كان لديك مقطع فيديو (وليكن باسم video.mp4) فيمكنك أن تستخرج منه الصور بإستخدام مكتبة cv2 في بايثون، بالشكل التالي: import cv2 vidcap = cv2.VideoCapture('video.mp4') success,image = vidcap.read() count = 0 while success: cv2.imwrite("frame%d.jpg" % count, image) success,image = vidcap.read() print('Read a new frame: ', success) count += 1 يقوم الكود السابق بإستخراج كل الفريمات Frames من مقطع الفيديو ويقوم بحفظ كل صور بصيفة jpg، قد تكون هذه الطريقة بطيئة وتستهلك الكثير من مساحة التخزين بسبب وجود الكثير من الصور، لذلك يمكنك إستخدام الكود التالي الذي يقوم بإستخراج صورة واحدة من كل 30 صورة (ويمكن التحكم في هذا الرقم): import cv2 cap = cv2.VideoCapture('video.mp4') count = 0 while cap.isOpened(): ret, frame = cap.read() if ret: cv2.imwrite('frame{:d}.jpg'.format(count), frame) count += 30 # i.e. at 30 fps, (في الغالب تحتوي الثانية الواحدة على 30 لقطة frame) cap.set(cv2.CAP_PROP_POS_FRAMES, count) else: cap.release() break أما بالنسبة لنشر الصور فعليك البحث عن API خاص بالمنصة التي تريد النشر فيها، فعلى سبيل المثال إن أردت النشر على فيسبوك فعليك البحث عن Facebook API ، حيث تختلف المتطلبات من منصة إلى أخرى ولكن ستكون الفكرة واحدة بينهم، وستجد في الغالب أن المنصة توفر مكتبة لكي تستخدمها وتسمح لك بالنشر (أو القيام بأمور أخرى مختلفة) بسهولة.
  3. تحتاج إلى تعلم بعض الأدوات مثل لغة برمجة تستمح لك بالقيام بهذه الأمور، وفي الغالب يتم إستخدام لغة بايثون Python نظرًا لسهولتها وسرعة تعلمها، أيضًا تحتاج أن تتعلم بعض الأساسيات في التعامل مع الشبكة وكيفية إرسال طلبات requests من خلال لغة البرمجة، كيفية تحميل المواقع بإستخدام بايثون أو كيفية تحميل صورة معينة إلى الجهاز على سبيل المثال، وفي الغالب يتم إستعمال مكتبة requests للقيام بهذا الأمر حيث توفر سهولة كبيرة في التعامل مع هذه الطلبات. أيضًا يمكنك تعلم كيفية التحكم بالمتصفح من خلال لغة البرمجة، على سبيل المثال تجعل المتصفح يذهي إلى موقع جوجل ويكتب جملة معينة في مربع البحث ثم يضغظ على زر البحث ويطبع في سطر الأوامر النتائج التي حصل عليها من جوجل، ويمكن القيام بهذا الأمر بإستخدام مكتبة selenium وهي مشهورة للغاية في هذا المجال. ملاحظة: يسمى هذا المجال بمجال سحب البيانات من الإنترنت Web Scraping أيضًا في كثير من الأحيان ستضطر إلى البحث عن واجهة برمجية API خاصة بالتطبيق أو الموقع الذي تريد القيام فيه ببعض الأمور، فعلى سبيل المثال إن أردت أن تقوم ببرمجة بووت للنشر على أحد المجموعات في تليجرام Telegram فعليك أن تقرأ توثيق Telegram APIs الذي يشرح لك كيفية عمل برامج تستخدم التطبيق وتقوم بالنشر فيه أو القيام بأمور أخرى مختلفة. في دورة علوم الحاسوب يتم شرح كل الأساسيات التي تحتاجها للبدء في تعلم هذه الأمور، حيث يتم شرح لغة بايثون من الصفر وكذلك البرمجة الكائنية والخوارزميات وهياكل البيانات وغيرها من الأمور وكذلك يتم شرح ما هي الطلبات requests وكيف يقوم المتصفح بإرسال الطلبات إلى الخوادم servers ليحصل على رد response (في الغالب يكون كود HTML)، لذلك ستكون هذه الدورة مفيدة لك للغاية قبل تعلم الأمور المذكورة أعلاة.
  4. يمكنك القيام بهذا الأمر يدويًا كما وضح شرف الدين في إجابته، كما تستطيع أن تستخدم حزمة مخصصة لهذا الأمر مثل react-i18next والتي تختص في إضافة ميزة تعدد اللغات إلى تطبيقات React و React Native بشكل سهل، عليك أن تقوم بتثبيت الحزمة في البداية من خلال npm: npm install react-i18next i18next --save الآن يمكنك أن تستعمل الحزمة بشكل بسيط كما في المثال التالي: import React from "react"; import ReactDOM from "react-dom"; // إستدعاء المكتبة وبعض الدوال منها import i18n from "i18next"; import { useTranslation, initReactI18next } from "react-i18next"; i18n .use(initReactI18next) // passes i18n down to react-i18next .init({ // هنا يتم وضع الترجمات // يمكنك أن تقوم بوضعهم في ملف json وإستدعائه هنا resources: { en: { translation: { "Welcome to React": "Welcome to React and react-i18next" } }, fr: { translation: { "Welcome to React": "Bienvenue à React et react-i18next" } }, lng: "en", fallbackLng: "en", }); function App() { const { t } = useTranslation(); return <h2>{t('Welcome to React')}</h2>; } // append app to dom ReactDOM.render( <App />, document.getElementById("root") ); وتستطيع الإطلاع على سؤال مشابهة عن كيفية تغير اللغة في هذه الحزمة من هنا: يمكنك الإطلاع على مزيد من الأمثلة من خلال موقع الحزمة الرسمي react.i18next
  5. إذا كان لديك صور في تصميم في Figma فيمكنك أن تقوم بإستخراجها من خلال تحديدها أولًا ثم ستجد قائمة Export في أسفل اليمين كما في الصورة التالية، قم بالضغط على علامة + ثم أختر حجم وصيغة الصورة وفي النهاية أضغط على Export وستجد أن الصورة تم تنزيلها لديك: يمكنك أيضًا أن تقوم بإستخراج أكثر من صورة في نفس الوقت من خلال تحديد الصور والقيام بنفس الخطوات والضغط على Export Layers وسيتم تحميل ملف مضغوط يحتوي على كل الصور المُحددة سابقًا:
  6. قم بالضغط على زر الواي فاي الموجود في أسفل يمين الصورة لديك ليتم تشغيل الواي فاي مرة أخرى. إن لم يعمل، قم بفتح الإعداداا Settings ثم قسم الشبكة والإنترنت Network & Internet ومن القائمة الجانبية إختر Wifi ثم قم بتفعيل الواي فاي، كما في الصورة: أيضًا قد يكون لديك زر في الحاسوب الخاص بك مخصص لإغلاق الواي فاي وتشغيله وعليك أن تقوم بالضغط عليه، لاحظ الزر في الصورة التالية:
  7. يجب تعديل كود HTML ليتم السماح برفع أكثر من ملف بالشكل التالي: <input name="avatar" type="file" multiple /> أيضًا يجب تعديل كود Multer ليقوم بإستقبال أكثر من ملف بالشكل التالي: app.post('/add-product', upload.array('avatar', 12), function (req, res, next) { // req.files is array of `avatar` files // req.body will contain the text fields, if there were any }) ملاحظة يصبح الكائن الذي يحتوي على معلومات الصور باسم req.files وليس req.file وذلك لأنه يمكن أن يحتوي الآن على أكثر من صورة. وفي حالة أردت أن ترفع الصور من خلال أكثر من حقل فيمكنك أن تستعمل upload.feilds على النحو التالي: const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }]) app.post('/add-product', cpUpload, function (req, res, next) { // يمكن الوصول إلى معلومات الصور بالشكل التالي // req.files['avatar'][0] -> File // req.files['gallery'] -> Array مصفوفة من الصور }) الأمر الأخير هو أنه يجب تعديل الـ Schema في النموذج model ليتم تخزين مصفوفة من النصوص array of string بدلًا من نص واحد string: const productSchema = new Schema({ avatar: [{ type: String }] }); ملاحظة: قد ترغب في تغير اسم الحقل ليكون avatars أو شيء آخر يعبر عن وجود أكثر من صورة بدلًا من avatar فقط. ملاحظة: يرجى إضافة الشيفرات بمحرر الشيفرات وليس كصور
  8. بداية من الإصدار 0.7 في فلاسك Flask تم إضافة الخاصية __version__ والتي تحتوي على رقم الإصدار الحالي (المثبت لديك): >>> import flask >>> flask.__version__ '1.1.2' >>> إن كنت تعمل على إصدار أقدم من 0.7 فسوف يسبب الكود السابق خطأ AttributeError لأن الخاصية لم تكن موجودة بعد حينها، لكن يمكنك أن تقوم بإستخدام المكتبية pkg_resources لمعرفة إصدار فلاسك Flask لديك: >>> import pkg_resources >>> pkg_resources.get_distribution('flask').version '0.6.1' ملاحظة: الطريقة السابقة تعمل مع كل الإصدارات ولكن قد تحتاج إلى تنفيذ الأمر التالي إن لم تجد المكتبة pkg_resources لديك: pip install setuptools طريقة أخرى وهي إستخدام الامر freeze والذي يقوم بعرض كل المكتبات المثبتة لديك وإصداراتها: pip freeze وإن كنت تستعمل ليتنكس فيمكنك أن تعرض إصدار مكتبة فلاسك Flask فقط بهذا الشكل: pip freeze | grep flask أيضًا تستطيع أن تستخدم الأمر flask (إن كان يعمل لديك) وسيعرض لك إصدار بايثون وفلاسك وكذلك Werkzeug: flask --version
  9. قد يكون سبب هذه المشكلة هو المتصفح نفسه وليس فلاسك Flask وللتأكد من هذا الأمر حاول أن تقوم بتجربة المشروع بإستخدام متصفح مختلف فإذا تم تحميل الملفات بشكل صحيح وتحتوي على آخر التحديثات، فيجب أن تقوم بحذف الملفات المؤقتة من متصفح الويب الخاص بك من خلال أحد هذه الطرق (تختلف حسب نظام التشغيل لديك): ويندوز: Ctrl+F5 ماك: Cmd+Shift+R أو Cmd+Opt+R لينكس: Ctrl+Shift+R أيضًا تستطيع تغير اسم ملف JavaScript وسيقوم المتصفح بإعادة تحميله مرة أخرى بأحدث التعديلات عليه. يمكنك أيضًا أن تضيف متغير إلى رابط الملف كمعامل URL بالشكل التالي: script.js?some_variable=file_timestamp حيث تقوم بتغير قيمة المعامل file_timestamp بإستخدام فلاسك Flask في القالب بأي رقم عشوائي Random وحينها سيقوم المتصفح بإعادة تحميل الملف كل مرة، على النحو التالي: def last_updated_timestamp(folder): return str(max(os.path.getmtime(os.path.join(root_path, f)) for root_path, dirs, files in os.walk(folder) for f in files)) @app.route('/') def index(): return render_template('index.html', timestamp=last_updated_timestamp('./static')) # في القالب <script type="text/javascript" src="/static/script.js?u={{ timestamp }}"></script> وستكون النتيحة بالشكل التالي: <script type="text/javascript" src="/static/script.js?u=1641149029.12"></script> حل آخر وهو إخبار المتصفح بألا يقوم بحفظ الملفات لأكثر من فترة معينة من خلال تحديد الخاصية cache_control.max_age بعدد ثواني معينة بالشكل التالي: @app.route('/api/v1/users/') def get_users(): data = {"name": "sameh"} response = jsonify(data) response.cache_control.max_age = 60 * 60 * 24 # يوم واحد بالثواني return response بهذا الشكل لن يقوم المتصفح بحفظ الملفات الثابتة (ملفات CSS/JS/JSON .. إلخ) لفترة أطول من يوم واحد.
  10. لتشغيل دالة في الخلفية (في thread مختلفة) تحتاج إلى إستعمال المكتبة threading بالشكل التالي: import time import threading from flask import Flask app = Flask(__name__) @app.route('/start') def start_handler(): # هذه الدالة ستعمل في الخلفية للقيام ببعض المهام def handle_sub_work(): for i in range(20): print(i, time.time()) time.sleep(1) # تشغيل Thread جديد threading.Thread(target=handle_sub_work).start() return "started" app.run(debug=True) بهذا الشكل سوف تعمل الدالة handle_sub_work في خيط Thread جديد، ولن يحتاج العميل الإنتظار لكي تنتهي هذه الدالة من العمل حتى يحصل على الطلب. ملاحظة: الدالة handle_sub_work تعمل في Thread جديد لذلك ليس لديها أي وصول إلى الكائن request الحالي، ولكن يمكن حل هذه المشكلة من خلال copy_current_request_context بالشكل التالي: @app.route('/start') def start_handler(): @copy_current_request_context def handle_sub_work(): for i in range(20): print(i, time.time()) print(request.url) # لتتأكد من إمكانية الوصول إلى الكائن request الحالي time.sleep(1) threading.Thread(target=handle_sub_work).start() return "started"
  11. يجب تشغيل التطبيق وتحديد أن عنوان المضيف host بعنوان 0.0.0.0 على النحو التالي: if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) بهذا الشكل يمكنك أن تقوم بتشغيل المشروع على الشبكة المحلية، فعلى سبيل المثال إن كان الجهاز لديه العنوان: 192.168.X.X فيمكنك تشغيل المشروع http://192.168.X.X:5000 كما يمكنك تشغيل المشروع من خلال الأمر flask: flask run --host=0.0.0.0 --port=5000 كما إن كنت تستخدم جدار ناري firewall للحماية فعليك أن تسمح بتشغيل المنفذ 5000 من خلال الأمر التالي: sudo ufw allow 5000
  12. يمكن إضافة الخاصية _class (لاحظ علامة _ في نهاية الكلمة لأن الكلمة class محجوزة في بايثون) {{ form.email(class_="css-class-here") }} وستكون النتيجة بهذا الشكل: <input class="css-class-here" id="email" name="email" type="text" value=""> كما يمكنك أن تقوم بإضافة أي خاصية HTML إلى الحقل من خلال تمرير كائن إلى المعامل render_kw بالشكل التالي: email = EmailField('Email', render_kw={'class': 'css-class-here', 'style': 'background:red;'}) <input class="css-class-here" id="email" name="email" type="text" value="" style="background:red;">
  13. تستطيع أن تقوم بتمرير الرسائل بإستخدام معاملات عنوان URL (تسمى URL parameter) بالشكل التالي: from flask import session, url_for def foo(): messages = json.dumps({"title":"hello world"}) # تحويل الكائن إلى نص return redirect(url_for('hello', messages=messages)) @app.route('/hello') def hello(): messages = request.args['messages'] # لإستعادة الرسائل من الدالة url_for() return render_template("hello.html", messages=json.loads(messages)) أو يمكنك أن تستعمل الجلسة session لتخزين قيمة message في cookie ثم إستخراج قيمة message من داخل هذه الـ cookie في الدالة hello بالشكل التالي: from flask import session, url_for def foo(): messages = json.dumps({"title":"hello world"}) # تحويل الكائن إلى نص session['messages'] = messages # تخزينه في الـ session return redirect(url_for('hello')) @app.route('/hello') def hello(): messages = session['messages'] # لإستعادة الرسائل من الـ session return render_template("hello.html", messages=json.loads(messages))
  14. يمكنك أن تقوم بعرض أي رقم float بخانتين فقط بعد العلامة العشرية من خلال إستعمال الدالة format، بالشكل التالي: {{'%0.2f'| format(result|float)}}% أو من خلال إستخدام علامة % كما في الكود التالي: {{'%0.2f' % result|float}}% أيضًا تستطيع إستعمال المُرشح round لتقريب الرقم بالشكل التالي: {{ result|round }} وتستطيع تحديد كيف ستتم عملية التقريب من خلال تمرير معاملات إلى المرشح round بالشكل التالي: {{ result|round(1, 'common', ) }} المعامل الأول هو مقدار الدقة precision وقيمته الإفتراضية هي 0، بينما المعامل الثاني هو كيف ستتم عملية التقريب "ceil" (التقريب إلى الرقم الأعلى) أم "floor" (التقريب إلى الرقم الأقل) أم "common" (التقريب الرياضي العادي).
  15. تستطيع إستخدام التابع query.one والذي يقوم بإرجاع نتيجة واحدة فقط، وفي حالة وجود أكثر من نتيجة سوف يقوم برفع استثناء MultipleResultsFound أما إذا لم يتم العثور على أي نتائج فسوف يقوم برفع استثناء NoResultFound، ويمكن تطبيق هذه الفكرة من خلال جملة Try .. except، على النحو التالي: from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import MultipleResultsFound try: user = session.query(User).one() return jsonify(result) except MultipleResultsFound, e: return "more than one" except NoResultFound, e: return "no results found" بهذا الشكل يمكنك تنفيذ ما تريد عندما يوجد نتيجة واحدة فقط أو يوجد عدد أكبر من النتائج أو لا يوجد نتائج على الإطلاق.
  16. يوفر فلاسك Flask الخاصية endpoint في الكائن request وهي مسئولة عن حفظ اسم الدالة التي يتم تنفيذها عند زيارة المسار، انظر الكود التالي: from flask import Flask, request app = Flask(__name__) @app.route("/") def foo(): return request.endpoint # foo app.run(debug=True) عند زيارة المسار / سوف يتم إرجاع اسم الدالة "foo". يمكنك أيضًا أن تقوم بإستخدام المكتبة inspect للحصول على اسم الدالة الحالية، على النحو التالي: import inspect @app.route("/") def foo2(): return inspect.currentframe().f_code.co_name عند زيارة المسار / سوف يتم إرجاع اسم الدالة "foo2".
  17. إستخدم التابع Query.first للحصول على صف واحد فقط وليس مجموعة من الصفوف بالشكل التالي: users = session.query(user.name).filter(and_(user.email == email, user.password == password_hash)).one() وتستطيع أيضًا أن تستعمل التابع Query.one_or_none والذي يقوم بإرجاع نتيجة واحدة فقط أو None في حالة لم يتم العثور على نتيجة مطابقة في قاعدة البيانات: users = session.query(user.name).filter(and_(user.email == email, user.password == password_hash)).one_or_none()
  18. يوفر فلاسك Flask إمكانية الوصول إلى المسار الحالي من خلال إستخدام الكائن request، حيث يحتوي على الخاصية path التي تحمل المسار الحالي: from flask import Flask, request @app.route("/users/") @app.route("/show-users/") def show_users(): return request.path في الكود السابق سوف يتم عرض المسار المستخدم للوصول إلى الدالة show_users أيضًا يمكنك أن تستعمل url_rule بطريقة مشابهة، على النحو التالي: from flask import Flask, request @app.route("/users/") @app.route("/show-users/") def show_users(): return str(request.url_rule) وسوف يؤدي هذا الكود نفس الغرض.
  19. لكي يتم إضافة التدوينات في الأقسام المحددة، تحتاج إلى تعديل الدالة lastPosts و الدالة createLastPosts وكذلك تحتاج إلى إنشاء مصفوفة عامة global بالشكل التالي: var IDs = []; function lastPosts(json) { var ID = IDs.shift(); // للحصول على أول عنصر في المصفوفة وحذفه من المصفوفة الأصلية // ... var printall = document.getElementById(ID); printall.innerHTML += printArticle; } function createLastPosts(url, count, printId) { IDs.push(printId); // لإضافة عنصر جديد إلى المصفوفة // ... } الآن يمكنك أن تقوم بتشغيل الدالة createLastPosts أكثر من مرة وسوف يتم إضافة التدوينات في الأماكن المحددة: <div class="container"> <div class="wrapper"> <div class="content"> <div id="demo1" class="show-sidebar grid grid-3"></div> <div id="demo2" class="show-sidebar grid grid-3"></div> <div id="demo3" class="show-sidebar grid grid-3"></div> </div> </div> </div> <script> createLastPosts('https://mo-222.blogspot.com', '1', 'demo1'); createLastPosts('https://mo-222.blogspot.com', '2', 'demo2'); createLastPosts('https://mo-222.blogspot.com', '3', 'demo3'); </script> طريقة أفضل لكن الطريقة السابقة متوقفة على ترتيب تنفيذ السكريبتات في المتصفح ولا يمكننا أن نضمن أن يتم تنفيذهم بالترتيب (قد يقوم المتصفح بتنفيذ السكريبتات حسب سرعة تحميل كل سكريبت) وبالتالي يمكن أن نجد أن التدوينات يتم إضافتها في أماكن عشوائية، ولحل هذه المشكلة يمكن أن تقوم بتجربة طريقة مختلفة عن إستخدام مصفوفة عامة، حيث نقوم بإضافة خاصية باسم data-position في كل عنصر script وتحمل id الخاص بالعنصر الذي سيتم إضافة التدوينات فيه، بالشكل التالي: function lastPosts(json) { // للحصول على الخاصية data-position من السكريبت الحالي (الذي قام بإستدعاء هذه الدالة) var ID = document.currentScript.getAttribute('data-position') // ... var printall = document.getElementById(ID); printall.innerHTML += printArticle; } } function createLastPosts(url, count, printId) { // ... ثم يتم إستدعاء الدالة createLastPosts بنفس الطريقة: <div class="container"> <div class="wrapper"> <div class="content"> <div id="demo1" class="show-sidebar grid grid-3"></div> <div id="demo2" class="show-sidebar grid grid-3"></div> <div id="demo3" class="show-sidebar grid grid-3"></div> </div> </div> </div> <script> createLastPosts('https://mo-222.blogspot.com', '1', 'demo1'); createLastPosts('https://mo-222.blogspot.com', '2', 'demo2'); createLastPosts('https://mo-222.blogspot.com', '3', 'demo3'); </script> الملف بعد تعديله: last-post.html
  20. سكراتش مخصص لتعليم الأساسيات البرمجية وهو بسيط للغاية ويحتوي على معظم ما تحتويه لغات البرمجة العادية، وهو مهم للغاية إن كنت مبتدئ في البرمجة بشكل عام، كما أنك ستحصل على بعض المفاهيم الإضافية مثل كيفية إضافة الأحداث Events وإضافة أكواد إلى كائنات مختلفة وكيفية التفاعل فيما بينها وعمل ألعاب بسيطة، بالإضافة إلى تعلم كيف تعمل الخوارزميات بشكل بسيط. وتخطي سكراتش قد يسبب لك مشاكل في فهم المسارات التالية، وبالتالي ستحتاج أن ترجع إلى مسار سكراتش لتتعلمه من جديد، وهذا بالطبع سيضيع عليك الكثير من الوقت، لذلك أنصحك أن تنهي مسار سكراتش أولًا وبما أن لديك خبرة برمجية سابقة فيمكنك أن تهني هذا المسار وكل مشاريعه في وقت قصير (يمكنك أن تتحكم في سرعة الشرح في الفيديو). تم نشر أسئلة مشابهة من قبل يمكنك الإطلاع عليها من هنا:
  21. عندما تقوم بإستضافة تطبيقات ذات الصفحة الواحدة Single Page Application (SPA) فسيتم إدارة أغلب المسارات من خلال كود الواجهة الأمامية عبر JavaScript (لكي لا يتم إعادة تحميل الصفحة من الخادم) وبالتالي يجب أن يقوم الخادم بإرسال ملف index.html عند زيارة أي مسار (حتى إن لم يوجد هذا المسار في تطبيق فلاسك Flask) وذلك من خلال الكود التالي: from flask import Flask, send_from_directory import os # يجب تحديد المجلد الصحيح الذي يحتوي على ملفات الواجهة الأمامية هنا app = Flask(__name__, static_folder='client/build') @app.route('/', defaults={'path': ''}) @app.route('/<path:path>') def serve(path): if path != "" and os.path.exists(app.static_folder + '/' + path): return send_from_directory(app.static_folder, path) else: return send_from_directory(app.static_folder, 'index.html') if __name__ == '__main__': app.run() بهذا الشكل سوف يتم إرجاع الملف index.html في كل المسارات غير المحددة بالفعل في التطبيق، أي أن أي مسار آخر موجود في فلاسك Flask سوف يعمل بدون مشكلة.
  22. عندما تحاول الوصول إلى التطبيق الحالي current_app أو أي شيء يستعمله سوف تحصل على رسالة الخطأ التالية: RuntimeError: Working outside of application context. وهي مشابهة لرسالة الخطأ التي لديك، حيث أنك تحتاج إلى إستخدام app_context لعمل Push للـ context الخاص بالتطبيق بالشكل التالي: # في ملف app.py app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'My connection string' db.init_app(app) # لاحظ كيفية إستخدام الجملة with لتمرير app_context with app.app_context(): db.create_all() يمكنك أيضًا أن تقوم بإستخدام التابع push مباشرة (في حالة كنت تستعمل سطر الأوامر)، كالتالي: from flask import Flask from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() def create_app(): app = Flask(__name__) db.init_app(app) return app في سطر الأوامر: >>> from yourapp import create_app >>> app = create_app() >>> app.app_context().push() الطريقة الأخرى هي تمرير app نفسه إلى db.create_all: db.create_all(app=create_app())
  23. الدالة url_for تقبل معامل آخر هو _external وإذا قمت بتمرير هذا المعامل بقيمة True سوف يتم إنتاج عنوان URL المطلق Absolute وليس عنوان نسبي Relative: url_for('index', _external=True) وقد تحتاج أن تحدد النطاق الذي سيتم إستخدامه من خلال تعين قيمة SERVER_NAME وكذلك البروتوكول المستخدم في إعدادات التطبيق، كالتالي: app.config['SERVER_NAME'] = "localhost:5000" app.config['PREFERRED_URL_SCHEME'] = "http" بهذا الشكل سوف يتم إنتاج عنوان URL كامل عند إستعمال الدالة url_for أيضًا
  24. سبب هذا الخطأ أنك قمت بتثبيت WTForms بإصدار 2.3.1 أو أعلى ولكن لم تقم بتثبيت email_validator ويمكنك أن تقوم بتثبيت هذه الحزمة من خلال أحد الطرق التالية: عبر pip: pip install email-validator أو من خلال الأمر التالي: pip install wtforms[email] أو يمكنك أن تقوم بتثبيت إصدار أقدم من WTForms كالتالي: pip install wtforms==2.2.1
  25. يمكن حل هذه المشكلة بأكثر من طريقة على النحو التالي: الطريقة الأولى هي فتح إتصال بقاعدة البيانات مع تمرير المعامل check_same_thread بقيمة Flase لكي لا يظهر هذا الخطأ على الإطلاق، وهذه هي الطريقة الأسهل، لأنك لن تضطر إلى التعديل على الكود إلا في مكان واحد، كالتالي: conn = sqlite3.connect('database-name.db', check_same_thread=False) الطريقة الأخرى هي فتح إتصال بقاعدة البيانات داخل الدالة register نفسها بإستخدام الجملة with لكي يتم غلق الإتصال تلقائيًا بمجرد الإنتهاء منه: @app.route('/api/v1/register', methods=['POST']) def register(): # باقي كود الدالة هنا with sql.connect("database-name.db") as conn: name = "bob" cur = conn.cursor() cur.execute("INSERT INTO users(name,email,username,password) VALUES(?,?,?,?)", [name, email, username, password]) conn.commit() return "Successful" بهذا الشكل سوف يعمل كود SQLite بدون مشكلة.
×
×
  • أضف...