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

مسعود زاهي

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

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

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

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

    1

كل منشورات العضو مسعود زاهي

  1. Redis هو عبارة عن مَخزَن قيم مفاتيح key value store مفتوح المصدر يمكنه العمل كمخزن لتخزين البيانات في الذاكرة in-memory store أو كمخزن تخزين بيانات مؤقت. يُمكن استخدامه إمّا كخادوم قاعدة بيانات لوحده أو مرتبطًا مع قاعدة بيانات أخرى مثل MySQL لتسريع بعض الأشياء. يتم إستخدام Redis مع Django كذاكرة تخزين مؤقت cache لتخفيف الحمل الزائد على عمليات الاستعلام queries التي تتم على قاعدة البيانات المُستخدمة. إنطلاقا من النسحة رقم 4.0 لجانغو أصبح التخزين المؤقت باستخدام Redis من الأمور المُدمجة والمدعومة بعد أن كان عبارة عن تطبيق طرف ثالث. لاستعمل Redis مع جانغو نحتاجُ أولاً إلى تثبيت الخادم الخاص به. ندخل إلى الموقع الرسمي ونقوم بتثبيته على حسب النظام الذي نستخدمه. بعد تثبيت Redis سنحتاج إلى تثبيت redis-py وهي مكتبة في بايثون تقوم بالربط مع الخادم. لاستخدام Redis كخلفية لذاكرة التخزين المؤقت مع Django نقوم ب: في ملف الإعدادات settings.py نضيف django.core.cache.backends.redis.RedisCache. CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.redis.RedisCache', 'LOCATION': 'redis://127.0.0.1:6379', # هنا ضع عنوان الايبي مع المنفذ الخاص بالخادم # redis } } عادة ما يكون Redis محمياً باسم مستخدم وكلمة مرور نضيفهما إلى عنوان URL: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.redis.RedisCache', 'LOCATION': 'redis://username:password@127.0.0.1:6379', } } إذا كنا نملك عدة خوادم Redis تم إعدادها في وضع النسخ المتماثل (replication)، فيمكننا إضافتها على الشكل التالي: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.redis.RedisCache', 'LOCATION': [ 'redis://127.0.0.1:6379', # القائد 'redis://127.0.0.1:6378', # النسخة رقم 1 'redis://127.0.0.1:6377', # النسخة رقم 2 ], } } هكذا نكون قد أتممنا إضافة Redis إلى جانغو. للإستزادة من المعلومات يمكن الإطلاع على المقالات التالية الموجودة في أكاديمية حسوب:
  2. عند إستعمال save مع commit=False الكائن المُعاد من الدالة لن يُحفظ في قاعدة البيانات عكس الأمر عند إستخدام commit=True الكائن سوف يٌحفظ وبعدها يُعاد. يكون هذا الفعل مٌفيداً عندما نٌريد إجراء مُعالجة إضافية للكائن قبل حفظه في قاعدة البيانات. كمثال تطبيقي، نفرض أننا نملك نموذجاً حيثُ يكون عنوان البريد الالكتروني واسم المستخدم مُتماثلين دائما في هذه الحالة عند رسم النموذج نقوم بوضع حقل واحد خاص بالبريد الإلكتروني مثلاً وعند حفظ النموذج نُعبئ حقل اسم المستخدم بنفس القيمة. class UserForm(forms.ModelForm): ... def save(self): # نقوم بتمرير #commit=False # للنموذج # الكائن المُعاد # لا يكون محفوظا في قاعدة البيانات في هذه اللحظة user = super(UserForm, self).save(commit=False) # "هنا نجعل قيمة "اسم المستخدم" هي نفس قيمة "البريد الالكتروني user.username = user.email # هنا يتم الحفظ user.save() return user عكس ما إذا استخدمنا commit=True فإن الكائن سوف يٌحفظ في قاعدة البيانات قبل أن نقوم بوضع قيمة "اسم المستخدم".
  3. python3 manage.py sqlflush blog الأمر الذي استعملته هنا يقوم فقط بطباعة مجموعة أوامر بصيغة SQL، هذه الأوامر تعمل على حذف البيانات فقط ولا تحذف الجداول الخاصة بالتطبيق blog. إذا أردت حذف بيانات التطبيق blog فقط قُم بدمْج الأمر السابق مع الأمر dbshell: pyhon3 manage.py sqlflush blog | python3 manage.py dbshell الأمر dbshell وظيفته فتح ال shell الخاص بقاعدة البيانات. أما إذا أردت حذف كل بيانات التطبيقات استعمل الأمر python3 manage.py flush # أو django-admin flush أما إذا أردت حذف الجداول مع البيانات قم بتنفيذ الشفرة التالية في django shell python3 manage.py shell #نقوم بفتح django shell #نقوم بتنفيذ أوامر الحذف داخل قاعدة البيانات >>> from django.db import connection >>> cursor = connection.cursor() >>> cursor.execute('show tables;') >>> parts = ('DROP TABLE IF EXISTS %s;' % table for (table,) in cursor.fetchall()) >>> sql = 'SET FOREIGN_KEY_CHECKS = 0;\n' + '\n'.join(parts) + 'SET FOREIGN_KEY_CHECKS = 1;\n' >>> connection.cursor().execute(sql)
  4. لتعطيل expire_on_commit في SQL-Alchemy نقوم بإضافة المتغير session_options عند إنشاء كائن قاعدة البيانات فهو يسمح بتمرير الإعدادات إلى كل عناصر Session التي سوف تٌنشأ db = SQLAlchemy(app, session_options={"expire_on_commit": False})
  5. DoesNotExist و ObjectDoesNotExist هما عبارة عن أخطاء (exceptions) في جانغو تحدث عندما نريد جلب كائن من قاعدة البيانات لكن هذا الكائن غير متوفر إما لأنه حُذف أو لأن المُعرف الذي استخدمناه كان خاطئاً. في فرق بسيط بينهما وهو أن ObjectDoesNotExist عامة و DoesNotExist خاصة. لفهم هذا نقوم بالمثال التالي: from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist from myproject.apps.teams.models import Team try: user = User.objects.get(pk=1337) team = Team.objects.get(pk=23) except ObjectDoesNotExist: logging.error("المستخدم أو الفريق لا يوجد") في المثال السابق قُمنا بجلب كائن من النموذج User باستخدام المعرف 1337، و كائن من النموذج Team باستخدام المعرف 23. لو صودف أن أحد الكائنين غير متوفر سيحدث الخطأ ObjectDoesNotExist. لو أردنا أن نَفْصِل بين الخطأين مثلاً: عندما لا نجد المستخدم نسجل "المستخدم لا يوجد" وعندما لا نجد الفريق نكتب " الفريق لا يوجد" هنا لا نستطيع فعل ذلك باستخدام ObjectDoesNotExist فنستعمل DoesNotExist. from django.contrib.auth.models import User from myproject.apps.teams.models import Team try: user = User.objects.get(pk=1337) team = Team.objects.get(pk=23) except User.DoesNotExist: logging.error("المستخدم غير موجود") except Team.DoesNotExist: logging.error("الفريق غير موجود")
  6. شرح الشفرة: app.before_request: تقوم بتسجيل الدالة ليتم تشغيلها عند بداية كل طلب (request) في مثالك قامت بتسجيل الدالة before_request. app.teardown_request: تقوم بتسجيل الدالة ليتم تشغيلها عند نهاية كل طلب (request) في مثالك قامت بتسجيل الدالة teardown_request. g هو كائن يوفره Flask. هو عبارة عن كائن شامل تحفظ فيه أي بيانات تريدها أثناء سياق طلب واحد. في المثال الذي طرحته قُمت بالاحتفاظ بوقت البداية g.start = time.time() والذي قُمت باستخدامه لاحقاً في الدالة teardown_request لحساب الفرق بين وقت البداية والنهاية diff_time = time.time() - g.start ملاحظة: g كائن يعيش بين app.before_request و بين app.teardown_request اي في سياق التطبيق (the application context) يعني هذا أن g يختلف من طلب لآخر.
  7. الطرق المختلفة لدمج مجموعتي بحث (QuerySet): مجموعتا البحث من نفس النموذج Model: توجد عدة طرق لدمج مجموعتي بحث من نفس النموذج باستخدام رمز الأنبوب (Pipe) | : # q1, q2 and q3 لنفرض لدينا مجموعات البحث التالية # للدمج بين كل المجموعات نستخدم combined_result= q1 | q2 | q3 باستخدام itertools: توفر itertools طريقة تسلسلية تسمح لك بسهولة الجمع بين مجموعتين أو أكثر من مجموعات البحث من نفس النماذج أو نماذج مختلفة. from itertools import chain combined_list = list(chain(q1,q2)) مجموعتا البحث من نماذج مختلفة: باستخدام الدالة union: تقوم هذه الدالة باستخدام UNION الخاص ب SQL لدمج مجموعتين أو أكثر : qs1.union(qs2, qs3)
  8. صفحات GitHub مخصصة للمواقع الثابتة فقط — المواقع التي تم إنشاؤها باستخدام HTML و CSS و JS. لا يدعم المواقع التي تم إنشاؤها باستخدام Python أو .NET أو PHP أو لغات أخرى من جانب الخادم. ستحتاج إلى العثور على مضيف ويب بديل إذا كنت بحاجة إلى استضافة موقع مكتوب بإحدى هذه اللغات أو كنت بحاجة إلى مضيف قاعدة بيانات. من أشهر مواقع الاستظافة المجانية والتي تدعم لغة بايثون نجد: موقع pythonanywhere. موقع heroku.
  9. توجد طريقتين للوصول إلى ما ترغب به: الطريقة الأولى: استخدم {{request.path}} داخل القالب (Template)، ستقوم بإرجاع الرابط (URL) الخاص بالصفحة التي أنت فيها ، ثم قم بالتحقق من أنه يساوي القيمة التي أنت تريدها باستخدام أداة الشرط IF على الشكل التالي: <a href="/signin" class="{% if request.path == '/signin' %} active {% endif %}">Signin</a> <a href="/signup" class="{% if request.path == '/signup' %} active {% endif %}">Signup</a> <a href="/" class="{% if request.path == '/' %} active {% endif %}">Home</a> الطريقة الثانية: قُم بإنشاء متغيرات داخل دوال كل رابط، وهذه المتغيرات قم بارسالها للقالب عند عرضه. def signup_view(request): .... #قم بإنشاء المتغير #signup_page #وإرساله إلى القالب return render(request, "signup_template.html", {"sigup_page": True}) def signin_view(request): .... return render(request, "signup_template.html", {"signin_page": True}) def home_view(request): .... return render(request, "signup_template.html", {"home_page": True}) بعدها استخدم المتغيرات في القالب: <a href="/signin" class="{% if signin_page %} active {% endif %}">Signin</a> <a href="/signup" class="{% if signup_page %} active {% endif %}">Signup</a> <a href="/" class="{% if home_page %} active {% endif %}">Home</a>
  10. الخطأ Address already in use يظهر عادة لما يكون يكون المنفذ (Port) - في مثالك 8080 أو قيمة مسجلة داخل متغيرات النظام - مستخدمًا بالفعل من قبل بعض تطبيقات بايثون الأخرى أو أي تطبيق آخر. لإصلاح الخطأ قُم باختيار منفذ آخر لتطبيقك: app.run(host = os.getenv('IP', '0.0.0.0'), port=8088)# مثلا 8088 إذا كنت تريد رؤية البرنامج الذي يشغل هذا المنفذ استخدم الأمر: (لمستخدمي linux ) netstat -ntlp | grep 8080 والذي بدوره يقوم بالكشف عن التطبيق الذي يشغل المنفذ. مثلاً: Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN 6599/python قم بإنهائه باستخدام kill -9 PID #أي kill -9 6599
  11. يوجد خطأ في الشفرة User.objects.filter(name="mohssen").latest() الدالة latest تُرجع آخر كائن في من النموذج بناءً على حقل أم مجموعة حقول مثلاً: #آخر كائن بناءً على المعرف Entry.objects.latest('id') #آخر كائن بناءً على حقلين المعرف وتاريخ الإنشاء Entry.objects.latest('id', '-creation_date') فللحصول على آخر كائن من نموذج Django استعمل الدالة last: last_user = User.objects.last() #بعد الفلترة last_user_with_name_mohssen = User.objects.filter(name="mohssen").last() أما إذا أردت استعمال latest فعليك إختيار الحقل المُناسب: مثلا تاريخ الإنشاء، أو استعمل المُعَرف last_user = User.objects.latest('id') #بعد الفلترة last_user_with_name_mohsen = User.objects.filter(name="mohssen").latest('id')
  12. لكي تحصل على اسم جدول النموذج داخل قاعدة البيانات يُمكنك استعمال: from django.contrib.auth.models import User User.objects.model._meta.db_table #أو استعمل User._meta.db_table # أما اذا كنت تريد الوصول الى اسم الجدول من الكائن مباشرة استخدم # مثلا اسم الكائن هو # my_user my_user._meta.db_table
  13. من المفترض أن تكون SQLite قاعدة بيانات خفيفة ، وبالتالي لا يمكنها دعم مستوى عالٍ من التزامن. OperationalError: database is locked يُشير هذا الخطأ إلى أن التطبيق الخاص بك يُواجه التزامن أكثر من أن يتمكن SQLite التعامل معها. تحتوي مكتبة SQLite في Python على قيمة مُهلة افتراضية تٌحَدد المدة التي يُسمح فيها لمؤشر الترابط الثاني بالانتظار على القفل قبل إنهاء مهلته وإثارة الخطأ OperationalError: database is locked. يُمكنك حل هذا الخطأ عن طريق: التبديل إلى قاعدة بيانات أُخرى. عندَ نقطة معينة يصبح SQLite جدا "لايت" لتطبيقات العالم الحقيقي، وهذه الأنواع من الأخطاء تُشير إلى أنك قد وصلت إلى هذه النقطة. إعادة كتابة التعليمات البرمجية الخاصة بك لتقليل التزامن والتأكد من أن مُعاملات قاعدة البيانات قصيرة الأجل. زيادة قيمة المهلة الافتراضية عن طريق تعيين خيار timeout # داخل ملف settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'OPTIONS': { # ... 'timeout': 20, # ... }, } }
  14. نعم يُمكنك ذلك فقط يجب أن يكون كلاً من التطبيقين موجوداً في INSTALLED_APPS في ملف الإعدادات settings.py. #داخل ملف #settings.py INSTALLED_APPS = [ ... 'blog', 'profiles', ... ] بعدها يُمكنك إستخدام النموذج Post داخل التطبيق profiles # في الملف profiles/models.py from blog.models import Post #قم باستدعاء النموذج من التطبيق #blog class PostProperty(models.Model): post = models.ForeignKey(Post) كما يُمكنك إستخدامه على الشكل التالي: class PostProperty(models.Model): post = models.ForeignKey("blog.Post") #من دون أن تقوم باستدعاء النموذج
  15. استخدم الدالة abort من المكتبة flask_restful ليس من مكتبة flask ﻷن الأولى تقبل إضافة قِيم أخرى في كود ال JSON، والثانية لا تقبل: from flask import Flask from flask_restful import Resource, Api, abort #قم باستدعاء الدالة #abort # من المكتبة # flask_restful app = Flask(__name__) api = Api(app) class HelloWorld(Resource): def get(self): # قم باستخدام الدالة # وأضف القيم الجديدة إليها # على سبيل المثال قمنا هنا بإضافة # route= api.url_for(self) abort(500, message="Error: Can't find the file you looking for.", route=api.url_for(self)) return {'hello': 'world'} api.add_resource(HelloWorld, '/api/v1/get-log') if __name__ == "__main__": app.run(debug=True)
  16. لقراءة ملف الCSV قبل حِفظه قُم بتحويله إلى دفق نص (Text stream) باستخدام io.TextIOWrapper: import io from flask import Flask, jsonify, request @app.route('/upload/', methods=['POST']) def csv_upload(): filebuf = request.files.get('csvfile')#جلب الملف من الطلب if filebuf is None:# التأكد من أن الملف موجود وإلا نقوم بارجاع خطأ للعميل return jsonify(message='Please specify the file'), 400 elif 'text/csv' != filebuf.mimetype: #التأكد من أن نوع الملف المُحَمّل هو CSV return jsonify(message='Only CSV files will be accepted'), 415 text_stream = io.TextIOWrapper(filebuf.stream, encoding='utf8')# نقوم بتحويل الملف الى دفق نص for row in csv.reader(text_stream):#نقرأ محتوى الملف #ضع شيفرة القراءة هنا return jsonify(message=f'{filebuf.filename!r}Loaded'), 200#إرجاع جواب للعميل بأن الملف حُمّل بنجاح
  17. للحصول على مُعرف الحقل إستخدم {{ field.auto_id }} أو: {{ field.id_for_label }}
  18. إذا أردت عرض النموذجين كنموذج واحد في القالب لا يجب عليك دمجُهُما بس استعملهما داخل عنصر <form> واحد. مثال ذلك: <form action="/your-url/" method="post"> {% csrf_token %} {{ profileForm }} {{ userEditForm }} <input type="submit" value="Submit"> </form> ثم فقط قُم بمعالجة النماذج بشكل منفصل في العرض (View): def your_view(request): # في حالة # GET # نقوم بإنشاء كائن جديد من كل نموذج وإرساله إلى القالب للعرض if request.method == "GET": profileForm = ProfileForm() userEditForm = UserEditForm() # أما في حالة # POST # elif request.method == 'POST': # نقوم بإنشاء النموذجين وملئهما بالبيانات المُرسلة من القالب profileForm = ProfileForm(request.POST) userEditForm = UserEditForm(request.POST) # بعدها نتحقق في ماإذا كانت البيانات صالحة في النموذجين وليس بها أخطاء if profileForm.is_valid() and userEditForm.is_valid(): # إذا كانت البيانات صالحة نقوم بحفظها وإرسال العميل إلى صفحة أخرى profileForm.save() userEditForm.save() return HttpResponseRedirect('/thanks/') return render(request, 'template.html', {'profileForm': profileForm, 'userEditForm':userEditForm})
  19. نعم هناك طريقة: قُم بالفصل بين المهام التي يتعين على الخادم القيام بها وبين إرسال الرد للعميل. إستخدم مكتبة بايثون threading لإنشاء Thread ليقوم بتنفيذ الدالة بعد إرسال الرد للعميل على الشكل الآتي: from flask import Flask, request import time import threading#قم باستدعاء مكتبة بايثون app = Flask(__name__) @app.route('/your-route', methods=['POST']) def start_task(): def long_running_task(**kwargs): # أنشئ الدالة """ مهمة طويلة المدى """ ... # قم بتنفيذ الدالة داخل # Thread thread = threading.Thread(target=long_running_task) thread.start() return {"message": "Accepted"}, 202 # هنا تقوم بإرجاع الرد للعميل if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=True)
  20. استعمل form.errors التي ستعطيك مُلخصاً لجميع الأخطاء: for field, err in form.errors.items(): print(err )
  21. يُمكنك تعطيل خاصية الautoescape للحصول على النتيجة التي ترغب بها: {% autoescape false %} {{ 'username|name|email' | replace("|", ":<br/>") }} {% endautoescape %} لكن هذه الطريقة لا يُنصح بها لأنك تقوم بعطيل الحماية ضد حَقْن ال HTML أو ما يُعرف بالإنجليزية HTML Injection. في طريقة أخرى وهي إنشاء مُرشح خاص يقوم بهذا العمل: # myapp/util/filters.py from .. import app from markupsafe import Markup @app.template_filter() def custom_split(text): """ الفصل بين العناصر بأسطر""" return Markup("<br>".join(text.split("|"))) القالب يُصبحْ: {{ 'username|name|email'|custom_split }}
  22. لإضافة خاصية تسجيل المعلومات لكل الزيارات التي يقوم بها المستخدمون قم بإضافة الشفرة الآتية إلى ملف الإعدادات settings.py: LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'file': { 'level': 'DEBUG', 'class': 'logging.FileHandler', 'filename': 'path to the forlder temp/app.log',# ضع هنا المسار الكامل لملف التسجيل }, }, 'loggers': { 'django': { 'handlers': ['file'], 'level': 'DEBUG', 'propagate': True, }, }, } بعدها في ملف ال views.py الخاص بك أضف الشفرة التالية: import logging# قم بإستيراد المكتبة الخاص بالتسجيل logger = logging.getLogger(__name__) # قم بجلب المٌسجل def profile(request): ... # بعدها سجل ما تريد من المعلومات # التسجيلات سوف تٌحفظ في الملف الذي عينته في الإعدادات logger.debug('User visited /profile/me') logger.debug('User is %s' % (request.user.get_full_name())) logger.debug('User age is %s' % (request.user.profile.age)) 14:22:10 Jan 31 2022 Username is Mohssen 14:22:10 Jan 31 2022 User age is 23
  23. لنفرض مثلا أن الحقل الذي تستعمله query نوعه هو Charfield class YourModelForm(forms.Form): query = forms.CharField(required=True) فلإضافة الخاصية autocomplete إليه نقوم بالآتي: class YourModelForm(forms.Form): query = forms.CharField(required=True, widget=forms.TextInput(attrs={'autocomplete':'off'})) كما يمكننا تغيير خصائص الحقل داخل الدالة __init__ الخاصة بالنموذج. class YourModelForm(forms.Form): query = forms.CharField(required=True) def __init__(self, *args, **kwargs): super(YourModelForm, self).__init__(*args, **kwargs) self.fields['query'].widget.attrs.update({ 'autocomplete': 'off' })
  24. إستعمل مرشح القوالب filter لوضع علامة آمن على أكواد ال Html التي أضفتها حتى يقوم jinja بعرضها كعناصر وليس كنص. <body> {% block body %} {{ data|safe }} {% endblock %} <body> كما يمكنك الإستغناء عن unescape: return render_template("index.html", data= Markup(html)) هذا سيؤدي إلى عمل نفس الشيء و سيُحافظ على القالب الخاص بك نظيفًا. كما يُمكنك أيضا إستخدام: {٪ autoescape٪} التي تعمل على تعطيل نظام autoescape في القوالب: {% autoescape false %} <body> {% block body %} {{ data }} {% endblock %} </body> {% endautoescape %} ملاحظة: يُرجى توخي الحذر الشديد بشأن المتغيرات التي تستخدمها في هذه الكتلة.
  25. عادة يُفضل استعمال count أحسن من len لأنها أسرع وتستهلك ذاكرة أقل: qs.count() : ستترجم إلى: SELECT COUNT(*) FROM some_table وهي عبارة عن طلب واحد من جانغو و كل الحسابات الأخرى تتم داخل نظام إدارة قاعدة البيانات (RDBMS). أما len(qs) فهي تترجم إلى: SELECT * FROM some_table هذا يعني جلب كل العناصر الموجودة داخل الجدول وبعدها جانغو يقوم بِعَدِهَا وإرجاع النتيجة، وهذا يتطلب ذاكرة إضافية للتخزين قبل العَد.
×
×
  • أضف...