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

مسعود زاهي

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

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

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

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

    1

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

  1. من الخصائص القوية التي يمتاز بها إطار العمل جانغُو عن غيره من أُطر العمل هو ال ORM الخاصة به والتي تجعل عمل إستخراج المعلومات من قاعدة البيانات سهلاً ومفهوماً. في الشفرة التي قُمت بكتابتها توجد علاقة OneToMany بين النموذج User والنموذج Product، إذا أردنا الحصول على المنتجات الغير المُرتبطة بالمستخدمين نقوم بعمل: products = Product.objects.filter(user__isnull=True) لاحظ أننا استخدمنا المُرشح isnull والذي يسمح بالتحقق من أن الحقل user ليس به قيمة. الآن إذا أردنا الأمر العكسي أي تصفية المستخدمين الذين ليس لديهم أي منتجات في المتجر هُنا نستعمل العلاقة العكسية بين النموذجين على الشكل التالي: #المستخدمون الذين ليس لديهم منتجات users_without_products = User.objects.filter(product__is_null=True) # المستخدمون الذي لديهم على الأقل مُنتج واحد users_wit_products = User.objects.filter(product__is_null=False)
  2. الشفرة لا تعمل لأن جانغو QuerySet ليست قابلة للتسلسل. لجعلها كذلك تُوجد عدة طُرق: الطريقة الأولى: تحويل ال QuerySet إلى قائمة (list) ثم تحويل القائمة إلى JSON class UsersListView(ListView): queryset = Users.objects.all() def get(self, request, *args, **kwargs): data = list(self.queryset.values()) # نحولها إلى قائمة return JsonResponse(data, safe=False) # بعدهها نُرجع القائمةة على شكل JSON الطريقة الثانية: استعمال الدالة serializers من الوحدة django.core التي تسمح بترجمة جانغو QuerySet إلى تنسيقات أخرى مثل ال xml، json from django.core import serializers # نقوم باستدعاء الدالة class UsersListView(ListView): queryset = Users.objects.all() def get(self, request, *args, **kwargs): #نحول البيانات إلى json data = serializers.serialize('json', self.queryset) return HttpResponse(data, content_type='application/json')
  3. لاستخراج النص من عنصر HTML في جانغو يُمكنك إستعمال الدالة strip_tags التي تقوم بنزع كل الوسوم الخاصة ب HTML من النص. from django.utils.html import strip_tags # نقوم باستدعاء الدالة post_title = '<div>Some Content</div>' post_title = strip_tags(post_title) print(my_string) # النص المُخرج سوف يَكون # Some Content كما يُمكنك إستخدام المُرشح striptags في القوالب لنزع وسوم ال HTML من المُتغيرات على الشكل التالي: {{ post_title|striptags }}
  4. لتعيين حد لحجم الملفات التي يتم رفعها في جانغو يُمكنك إضافة مُحقق (Validator) يقومُ بفحص حجم الملف قبل حفظه في النموذج. from django.core.exceptions import ValidationError def validate_file_size(value): filesize= value.size if filesize > 2097152: #2mb raise ValidationError("The maximum file size that can be uploaded is 2MB") else: return value الدالة validate_file_size تقومُ بالتحقق من أن حجم الملف لا يتعدى 2mb (أي 2097152) بالبايت و إثارة إستثناء إذا كان كذلك. لإضافتها كمُحقق نقوم بالتالي: image = forms.FileField(upload_to='images/', validators=[validate_file_size])
  5. هل تُريد عمل نظام الدخول في تطبيق ويب أو تطبيق سطح مكتب؟. وأي إطار عمل تستخدمُه؟.
  6. نعم يُمكنك إستدعاء دالة عرض (view) داخل دالة عرض أخرى. مثلاً: #دالة العرض الأولى def view1(request): #الكود الذي تُريد إستدعاءه في دالة عرض أخرى return HttpResponse("some html here") #دالة العرض الثانية def view2(request): view1(request) # إستدعاء الدالة 1 return HttpResponse("some different html here") أو الأحسن أنك تعمل دالة بايثون تضع فيها الشفرة المشتركة بين دالتي العرض: def common_function(): #أكتب هنا الكود المشترك بين الدالتين return #دالة العرض الأولى def view1(request) common_function()# قم باستدعاء الدالة المشتركة return HttpResponse("some html here") #دالة العرض الثانية def view2(request) common_function()# قم باستدعاء الدالة المشتركة return HttpResponse("some different html here")
  7. لجعل مُتغير متاحاً في كل القوالب بشكل إفتراضي يجب إنشاء مُعالج سياق (context processor) جديد وإضافته إلى إعدادات جانغو. لفِعل ذلك نقوم بإنشاء ملف بايثون داخل تطبيق جانغو ونقوم بتسميته my_context_processors.py. داخل الملف نقوم بكتابة الشفرة التالية: from myapp.models import Category def categories_processor(request): categories = Category.objects.all() return {'categories': categories} # أنشأنا متغير جديد فيه كل المُنتجات ثم نُضيف my_context_processors داخل ملف الإعدادات: TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'loaders': [ ... ], 'context_processors': [ 'django.template.context_processors.debug', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', "myapp.my_context_processors.categories_processor" # نُضيفه هنا ], }, } ] بهذا الشكل يكون categories مًتواجداً في كل القوالب.
  8. يُمكنك إنشاء أمر في جانغو يقوم بقراءة ملف ال CSV وإدخال المعلومات داخل النموذج Product. لإنشاء الأمر نقوم بإنشاء مجلد داخل تطبيق جانغو ونقوم بتسميته management، داخل هذا المجلد نقوم بإنشاء مجلد آخر اسمه commands، وبداخله نقوم بإنشاء ملف بايثون يحمل الإسم insert_products_from_csv.py. نقوم بوضع هذه الشفرة داخل الملف. from django.core.management.base import BaseCommand import csv class Command(BaseCommand): help = 'إنشاء كائنات إنطلاقاً من ملف csv' def add_arguments(self, parser): parser.add_argument('--path', type=str, help="مسار الملف") def handle(self, *args, **options): # نجلب مسار الملف file_path = options['path'] # نقرأ الملف with open(file_path, 'rb') as csv_file: reader = csv.reader(csv_file, delimiter=';') for row in reader: # نستخرج معلومات المُنتج من كل سطر product_id = row[0] product_name = row[1] product_price = row[2] product_description = row[3] # نحفظ المعلومات في النموذج person, created = Person.objects.update_or_create( id=product_id, name=product_name, price=product_price, description=product_description ) لتشغيل الأمر نكتب python manage.py insert_products_from_csv --path "هنا نضع مسار الملف كاملاً"
  9. أنت تُحاول تشغيل تطبيق flask في المنفذ 81 الذي يُعتبر من المنافذ ذوات الإمتيازات (privileged port) . إستعمل منفذ آخر مثل 5000 لن يطلب منك النظام إمتيازات المُدير لاستعماله. app.run(host="127.0.0.1", port=5000, debug=True) ملاحظة: المنافذ ذوات الإمتيازات هي المنافذ الأقل من 1024 وهي منافذ لا يُسمح للمستخدمين العاديين تشغيل الخوادم عليها - هذا إجراء أمني -.
  10. إعدادات جانغُو الإفتراضية لا تعمل على إنشاء ملفات logs. وإنما فقط تقوم بإرسال رسالة إلكترونية إلى مُديري المشروع المُتواجدة عناوينهم الإلكترونية في القائمة ADMINS (في ملف الإعدادات settings.py) في حالة الخطأ رقم 500. إذا أردت إضافة هذا الأمر وحفظ الأخطاء داخل ملفات logs عليك بتغيير القيمة الإفتراضية ل LOGGING في ملف الإعدادات على الشكل التالي: # هذه هي الإعدادات الإفتراضية لجانغو LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'filters': { 'require_debug_false': { '()': 'django.utils.log.RequireDebugFalse', }, 'require_debug_true': { '()': 'django.utils.log.RequireDebugTrue', }, }, 'formatters': { 'django.server': { '()': 'django.utils.log.ServerFormatter', 'format': '[{server_time}] {message}', 'style': '{', } }, 'handlers': { 'console': { 'level': 'INFO', 'filters': ['require_debug_true'], 'class': 'logging.StreamHandler', }, 'django.server': { 'level': 'INFO', 'class': 'logging.StreamHandler', 'formatter': 'django.server', }, 'mail_admins': { 'level': 'ERROR', 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler' }, ## نقوم بإضافة 'applogfile': { 'level':'DEBUG', 'class':'logging.handlers.RotatingFileHandler', ## هنا نضع المسار الذي تريد حفظ الملفات فيه مع اسم الملف 'filename': os.path.join(BASE_DIR, 'mylog.log'), 'maxBytes': 1024*1024*15, # 15MB الحجم الأقصى للملف الواحد 'backupCount': 10, # العدد الأقصى للملفات }, }, 'loggers': { 'django': { 'handlers': ['console', 'mail_admins', 'applogfile'], #نُضيف الاسم إلى القائمة 'level': 'INFO', }, 'django.server': { 'handlers': ['django.server'], 'level': 'INFO', 'propagate': False, }, }, } ملفات ال logs سوف تُحفظ في المسار وبالاسم الذي حددته في الإعدادات.
  11. هذا مثال بسيط لفهم تقسيم الصفحات الخاص ب Flask-SQLAlchemy. نفرض أنه يوجد لدينا صفحة نقوم بعرض مجموعة من الألوان بداخلها. أولاُ نقوم بجلب الألوان: @app.route('/colors') def colors(): # نجلب الألوان من قاعدة البيانات # ونعرضها في القالب colors = Color.query.all() return render_template('colors/all_colors.html', colors=colors) ثانيا نعرض الألوان في القالب: <div class="table-responsive"> <table class="table table-sm table-borderless mb-0"> <thead class="thead-dark"> <tr> <th>S/N</th> <th>Color Name</th> <th>Date Created</th> <th>Actions</th> </tr> </thead> <tbody> {% for color in colors %} <tr> <th scope="row">{{ loop.index }}</th> <td>{{ color.name }}</td> <td>{{ color.created_at }}</td> </tr> {% endfor %} </tbody> </table> </div> كل الألوان سيتم عرضُها. حتى ولو كان عددها كبيراً جداً وهذا سيؤدي إلى ثقل في تحميل الصفحة. الحل طبعا هو إضافة ال pagination. لإضافتها نغير الشفرة إلى: ROWS_PER_PAGE = 10 # نعين عدد الالوان التي نريدها في كل صفحة @app.route('/colors') def colors(): # نضغ إعدادات الترقيم page = request.args.get('page', 1, type=int) # نستعمل الدالة paginate # من Flask SQLAlchemy # ونمرر لها الصفحة الحالية مع عدد الألوان في كل صفحة colors = Color.query.paginate(page=page, per_page=ROWS_PER_PAGE) return render_template('colors/all_colors.html', colors=colors) نقوم بتعديل القالب: لعرض العناصر يجب إستدعاء colors.items بدل colors. <div class="table-responsive"> <table class="table table-sm table-borderless mb-0"> <thead class="thead-dark"> <tr> <th>S/N</th> <th>Color Name</th> <th>Date Created</th> <th>Actions</th> </tr> </thead> <tbody> {% for color in colors.items %} ^^^^^^^^^^^^ <tr> <th scope="row">{{ loop.index }}</th> <td>{{ color.name }}</td> <td>{{ color.created_at }}</td> </tr> {% endfor %} </tbody> </table> </div> <!-- إنشاء روابط تقسيم الصفحات --> <div class="text-right"> <a href="{{ url_for('colors', page=colors.prev_num) }}" class="btn btn-outline-dark {% if colors.page == 1 %}disabled{% endif %}"> &laquo; </a> <!-- نعمل حلقة لعمل رابط لكل صفحة --> {% for page_num in colors.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %} {% if page_num %} <!-- نقوم بكتابة شرط للتحقق من الصفحة الحالية--> {% if colors.page == page_num %} <a href="{{ url_for('colors', page=page_num) }}" class="btn btn-dark"> {{ page_num }} </a> {% else %} <a href="{{ url_for('colors', page=page_num) }}" class="btn btn-outline-dark"> {{ page_num }} </a> {% endif %} {% else %} ... {% endif %} {% endfor %} <a href="{{ url_for('colors', page=colors.next_num) }}" class="btn btn-outline-dark {% if colors.page == colors.pages %}disabled{% endif %}"> &raquo; </a> </div> <p class="text-right mt-3"> Showing page {{ colors.page }} of {{ colors.pages }} </p>
  12. في الحالة العادية JsonResponse تقوم بإرجاع رمز الحالة 200، إذا أردنا إرجاع رمز حالة آخر مثلاً في حالة الخطأ يُمكننا تعيين قيمة status في JsonResponse: return JsonResponse({'status':'false','message':message}, status=500) ^^^^^^^^^^
  13. الشفرة التي قُمت بكتابتها ليس بها أي خطأ. تفحص باقي شفترك قد يَكْمن الخطأ هناك. الشفرة التي أدخلتها تسمح بوضع قيمة افتراضية للحقل created_at تُساوي تاريخ اليوم الذي حُفظ فيه الكائن. إذا قامَ المُستخدم بوضع قيمة أخرى فستُحفظ القيمة التي وَضعها.
  14. توجَدُ عدة خيارات يُمكنك إستخدامها وهذه الخيارات عادة ما تكونُ مُتوفرة في وضع التصحيح (Debug Mode). من بينها: الخيار الأول: استخدام وسم القالب {% debug %} والذي يقوم بعرض كل معلومات وضع التصحيح المتوفرة ومن بينها المُتغيرات. الخيار الثاني: استخدام تطبيق جانغو Django debug toolbar.
  15. نعم هناك طريقة باستخدام order_by التي تسمح بترتيب المجموعة QuerySet الناتجة عن الفرز الذي قُمت به . للترتيب من الأقدم إلى الأحدث نقوم ب: qs = Article.objects.filter(since=since).order_by("id") أما من الأحدث إلى الأقدم نقوم ب: qs = Article.objects.filter(since=since).order_by("-id") لجلب أحدث 10 منشورات نُضيف: qs = Article.objects.filter(since=since).order_by("-id")[:10]
  16. يُمكنك إستخدام الطريقة هذه للوُصول إلى أول عُنصر من القائمة: {{ users.0 }} هذه الطريقة تَسمحُ لك بالوصول إلى توابع وخواص الكائن مٌباشرة بالشكل التالي: {{ users.0.fullName }} يُمكنك أيضا إستخدام الحلقة التكرارية forloop والتوقف عند أول عُنصر وطباعة خاصية من خواصه: {% for user in users %} {% if forloop.first %} <!-- إطبع هنا الخاصية --> {{ user.fullName }} {% endif %} {% endfor %} أو يُمكنك إستخدام علامة القالب with : {% with users|first as first_user %} {{ first_user.fullName }} {% endwith %}
  17. للحصول على اسم الملف فقط في بايثون يُمكنك استخدام الدالة basename من الوحدة os على الشكل التالي: >> import os >> os.path.basename(file.name) لإستعمال هذه الدالة في القوالب يلزم إنشاء تابع أو خاصية في النموذج واستدعائه في القالب: class MyModel(models.Model): file = models.FileField() ... #أنشأنا الخاصية filename @property def filename(self): return os.path.basename(self.file.name) بعدها نستخدمُه على الشكل التالي: {% for uploaded in all_uploads %} <tr> <td>File Name: {{uploaded.filename}}</td><!-- لاحظ كيفية استعمال الخاصية --> <td>File Path: {{uploaded.file.name}}</td> <td>File Size: {{uploaded.file.size}}</td> </tr> {% endfor %}
  18. مرحباً عبد العظيم، نحنُ لا نَقومُ بحل واجبات الطُلّاب هنا نحن نقوم بمُساعدتهم لحلها. إعطاءك الحل مُباشرةً لا يُفِيدُك. لهذا حَاول حل التمرين لوحدك وإن واجهتك مُشكلة إطرحها هُنا مع وضع الشفرة التي كتبتها وسوف نقوم بتوجيهك.
  19. للتحقق مما إذا كانت العلاقة OneToOneField غير موجودة (تُساوي None) في جانغو يُمكنك إستخدام دالة بايثون hasattr: if hasattr(request.user, 'category') or hasattr(request.user, 'subcategory'): # المُستخدم لديه # category # أو # subcategory else: # المستخدم لا يملك الخاصيتين يُمكنك تصفح موسوعة حسوب لمعرفة كيفية عمل هذه الدالة.
  20. تُوجد عدة طُرق لإخفاء المفاتيح السرية Secret Keys في مرحلة الإنتاج Production من بينها: إخفاء المفاتيح داخل متغيرات بيئة المُستخدم Environment Variables # في نظام لينكس لإخفاء المفاتيح السرية نستعمل export SECRET_KEY = 'اكتب المفتاح السري هنا' وبعدها إستدعاؤها من داخل الشيفرة. import os SECRET_KEY = os.environ['SECRET_KEY'] حفظ الأرقام السرية داخل ملف .env # ملف .env SECRET_KEY = 'اكتب المفتاح السري هنا' بعدها يُمكن إستعمال مكتبة بايثون python-decouple لإسترجاعها: from decouple import config SECRET_KEY = config('SECRET_KEY') ملاحظة: لتثبيت مكتبة python-decouple يُرجى كتابة الأمر pip install django-generate-secret-key إذا كُنت تستخدم جانغو فيُمكنك أيضا إنشاء مفتاح سري حال الإنتاج باستخدام تطبيق جانغو django-generate-secret-key الذي يسمح بإنشاء المفتاح باستخدام الأمر: python manage.py generate_secret_key
  21. للحصول على الرابط الذي أتى منه العميل في flask يُمكنك إستخدام: referrer = request.headers.get("Referer") أو باستخدام الإختصار: referrer = request.referrer
  22. request.POST هو عبارة عن قاموس (dictionary) في بايثون أي هو عبارة عن مجاميع غير مرتبة من الأزواج (مفتاح: قيمة) مع إشتراط كون المفاتيح ذات قيم فريدة أي غير مُكَرَّرة. إستعمالٌك ل request.POST['KEY'] قدْ يُثير الخطأ KeyError في حالة عدم تواجد المفتاح KEY في القاموس. أما إستعمالُك ل request.POST.get('KEY') لا يُثير الخطأ وإنما يقوم بإرجاع القيمة None في حالة عدم تواجد المفتاح في القاموس. بالإضافة إلى أن استعمال get يُتيح لك خاصية إضافية وهي إرجاع قيمة إفتراضية في حالة عدم تواجد المفتاح في القاموس. مثلاً: >>> value = request.POST.get('KEY') >>> print(value) None >>> value = request.POST.get('KEY', 'القيمة الإفتراضية') >>> print(value) 'القيمة الإفتراضية' لمزيد من المعلومات عن القواميس يُمكنك زيارة موسوعة حسوب. كما يُمكنك قراءة بعض المقالات الموجودة في أكاديمية حسوب:
  23. يُمكنك إشتخدام المُدَقق RegexValidator للتحقق من طول القيمة قبل حفظها في قاعدة البيانات مع مُراعاة أن الرقم الموضوع في العبارة النمطية '^.{10}$' هو نفسه قيمة max_length: from django.core.validators import RegexValidator #قم باستدعاء المُدقق class MyModel(models.Model): """ قم بإضافة المدقق إلى الحقل وقم باستبدال 10 بالطول الذي تُريده """ national_number = models.CharField('National Number', max_length=10, validators=[RegexValidator(regex='^.{10}$', message='يجب أن يكون طول القيمة يُساوي 10', code='nomatch')]) كما يُمكنك إستخدام المُدقق MinLengthValidator مع مُراعاة أن القيمة المُمَرَّرَةُ له هي نفسها قيمة max_length: from django.core.validators import MinLengthValidator #قم باستدعاء المُدقق class MyModel(models.Model): """ قم بإضافة المدقق إلى الحقل وقم باستبدال 10 بالطول الذي تُريده """ national_number = models.CharField('National Number', max_length=10, validators=[MinLengthValidator(10)])
  24. يُمكنك معرفة عدد العناصر الموجودة في أحد الجداول بإستخدام الدالة count مُباشرة بدون إستعمال مرشحات على الشكل التالي: table.query.count() أو session.query(Table).count() # Table # هو اسم النموذج الخاص بك مُلاحظة: الطريقة أعلاه قد تكون بطيئة نوعًا ما في بعض نُظم قواعد البيانات مثل MySql. للحصول على نتيجة أسرع يُمكن استخدام: from sqlalchemy import func session.query(func.count(Table.id)).scalar()
  25. يُمكنك إستخدام Django signals والتي هي عبارة عن إشارات تسمح بإرسال تنبيهات عندَ حُدوث إجراءات معينة من بين تلك الإشارات نجد: post_save: تُستدعى هذه الإشارة بعد حفظ الكائن في قاعدة البيانات أي بعد حدوث الدالة save. pre_save: تُستدعى هذه الإشارة قبل حفظ الكائن في قاعدة البيانات اي قبل حدوث الدالة save. لتشغيل الأكواد عند إنشاء كائن جديد من النموذج Model نقوم بإنشاء signal من نوع post_save: from django.db.models.signals import post_save from django.dispatch import receiver @receiver(post_save, sender=Model) def run_code(sender, instance, created, **kwargs): # نتحقق أولا من أن الكائن جديد if created: # هنا نضع الأكواد التي نُريد تشغيلها عندما يتم إنشاء # كائن جديد
×
×
  • أضف...