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

مسعود زاهي

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

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

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

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

    1

أجوبة بواسطة مسعود زاهي

  1. 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("الفريق غير موجود")

     

    • أعجبني 1
  2. شرح الشفرة:

    • 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 يختلف من طلب لآخر.

     

    • أعجبني 1
  3. الطرق المختلفة لدمج مجموعتي بحث (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)

         

    • أعجبني 1
  4. صفحات GitHub مخصصة للمواقع الثابتة فقط — المواقع التي تم إنشاؤها باستخدام HTML و CSS و JS. لا يدعم المواقع التي تم إنشاؤها باستخدام Python أو .NET أو PHP أو لغات أخرى من جانب الخادم. ستحتاج إلى العثور على مضيف ويب بديل إذا كنت بحاجة إلى استضافة موقع مكتوب بإحدى هذه اللغات أو كنت بحاجة إلى مضيف قاعدة بيانات.

    من أشهر مواقع الاستظافة المجانية والتي تدعم لغة بايثون نجد:

    1. موقع pythonanywhere.
    2. موقع heroku.

     

    • أعجبني 1
  5. توجد طريقتين للوصول إلى ما ترغب به:

    الطريقة الأولى:

    • استخدم {{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>

     

    • أعجبني 1
  6. الخطأ  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

     

    • أعجبني 1
  7. يوجد خطأ في الشفرة

    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')

     

    • أعجبني 1
  8. لكي تحصل على اسم جدول النموذج داخل قاعدة البيانات يُمكنك استعمال:

    from django.contrib.auth.models import User
    
    User.objects.model._meta.db_table
    #أو استعمل
    User._meta.db_table
    # أما اذا كنت تريد الوصول الى اسم الجدول من الكائن مباشرة استخدم
    # مثلا اسم الكائن هو 
    # my_user
    my_user._meta.db_table

     

    • أعجبني 1
  9. من المفترض أن تكون SQLite قاعدة بيانات خفيفة ، وبالتالي لا يمكنها دعم مستوى عالٍ من التزامن.

    OperationalError: database is locked 

     يُشير هذا الخطأ إلى أن التطبيق الخاص بك يُواجه التزامن أكثر من أن يتمكن SQLite التعامل معها.

    تحتوي مكتبة SQLite في Python على قيمة مُهلة افتراضية تٌحَدد المدة التي يُسمح فيها لمؤشر الترابط الثاني بالانتظار على القفل قبل إنهاء مهلته وإثارة الخطأ OperationalError: database is locked.

    يُمكنك حل هذا الخطأ عن طريق:

    1. التبديل إلى قاعدة بيانات أُخرى. عندَ نقطة معينة يصبح SQLite جدا "لايت" لتطبيقات العالم الحقيقي، وهذه الأنواع من الأخطاء تُشير إلى أنك قد وصلت إلى هذه النقطة.
    2. إعادة كتابة التعليمات البرمجية الخاصة بك لتقليل التزامن والتأكد من أن مُعاملات قاعدة البيانات قصيرة الأجل.
    3. زيادة قيمة المهلة الافتراضية عن طريق تعيين خيار timeout
      # داخل ملف settings.py
      DATABASES = {
          'default': {
              'ENGINE': 'django.db.backends.sqlite3',
              'OPTIONS': {
                  # ...
                	'timeout': 20,
          		# ...
              },
          }
      }

       

    • أعجبني 1
  10. نعم يُمكنك ذلك فقط يجب أن يكون كلاً من التطبيقين موجوداً في 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") #من دون أن تقوم باستدعاء النموذج

     

    • أعجبني 1
  11. استخدم الدالة 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)

     

    • أعجبني 1
  12. لقراءة ملف ال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#إرجاع جواب للعميل بأن الملف حُمّل بنجاح

     

    • أعجبني 1
  13. إذا أردت عرض النموذجين كنموذج واحد في القالب لا يجب عليك دمجُهُما بس استعملهما داخل عنصر <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})

     

    • أعجبني 1
  14. نعم هناك طريقة:

    1. قُم بالفصل بين المهام التي يتعين على الخادم القيام بها وبين إرسال الرد للعميل. 
    2. إستخدم مكتبة بايثون 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)

       

    • أعجبني 1
  15. يُمكنك تعطيل خاصية  ال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 }}

     

    • أعجبني 1
  16. لإضافة خاصية تسجيل المعلومات لكل الزيارات التي يقوم بها المستخدمون قم بإضافة الشفرة الآتية إلى ملف الإعدادات 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

     

    • أعجبني 1
  17. لنفرض مثلا أن الحقل الذي تستعمله 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'
                })

     

     

    • أعجبني 1
  18. إستعمل مرشح القوالب 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 %}

    ملاحظة: يُرجى توخي الحذر الشديد بشأن المتغيرات التي تستخدمها في هذه الكتلة.

    • أعجبني 1
  19. عادة يُفضل استعمال count أحسن من len لأنها أسرع وتستهلك ذاكرة أقل:

    qs.count()

    : ستترجم إلى:

    SELECT COUNT(*) FROM some_table

    وهي عبارة عن طلب واحد من جانغو و كل الحسابات الأخرى تتم داخل نظام إدارة قاعدة البيانات (RDBMS).

    أما 

    len(qs)

    فهي تترجم إلى:

    SELECT * FROM some_table

    هذا يعني جلب كل العناصر الموجودة داخل الجدول وبعدها جانغو يقوم بِعَدِهَا وإرجاع النتيجة، وهذا يتطلب ذاكرة إضافية للتخزين قبل العَد.

    • أعجبني 1
  20. عادة يحدث هذا الاستثناء لما نُحاول فك حزمة (a tuple) ، لكن الحزمة تحتوي على عدد كبير من القيم أكبر من المتغيرات التي نريد فك الحزمة فيها. مثال على ذلك:

    def mehtod():
        return ("a","b","c") #الدالة تقوم بارجاع حُزمة فيها ثلاث قيم
    a,b,c = mehtod()#نقوم بفك الحزمة في ثلاث متغيرات
                     # هنا لا يحصل خطأ
    print a
    >> "a"
    print b
    >> "b"
    print c
    >> "c"
    
    # أما هنا يحصل خطأ
    a,b = mehtod() # لأننا قمنا بفك الحزممة في عدد متغيرات أقل من حجم الحزمة

    الآن ، لا أعرف سبب حدوث ذلك في حالتك ، ولكن ربما ستوجهك هذه الإجابة في الاتجاه الصحيح ان شاء الله.

    • أعجبني 2
    • سبب المشكلة: هو أن جانغو يقوم بفحص قيمة Host في رأس طلب الHTTP المُرسلة ويُقارنها بالقيم الموجودة داخل ALLOWED_HOSTS المُتواجدة في ملف الإعدادات settings.py. إذا كانت قيمة HOST - سواءًا عُنوان أيْبي أو إسم نطاق- مُتواجدة في ALLOWED_HOSTS يقوم جانغو بسماح الطلب. أما في حالة عدم تواجدها فيقوم برفضها مثل ما حصل معك.

    ملاحظة: هذه هي عبارة عن حماية يوفرها جانغو ليمنع هجمات "HTTP HOST Header"، والتي تكون ممكنة حتى في ظل العديد من تكوينات خادم الويب التي تبدو آمنة.

    • حل المشكلة: يكون بإضافة xxx.xxx.xx.xx الى ALLOWED_HOSTS الموجودة في ملف settings.py.
      ALLOWED_HOSTS = ['xxx.xxx.xx.xx']

       

    • أعجبني 1
  21. الأمر بسيط أولا قم بجلب الكائن my_interest باستعمال الدالة get مثلاً:

    my_interest = Interest.objects.get(id=my_interest_id)
    #قمت بجلب الكائن باستعمال معرفه
    #يمكنك جلبه بأي خاصية من خصائصه

    بعدها احذف الرابطة بينه وبين my_user:

    my_user.interests.remove(my_interest)
    # ملاحظة:
    #remove 
    #تقوم بالفصل بين الكائنين ولا تقوم بحذف أي منهما

     

    • أعجبني 1
×
×
  • أضف...