การปรับ MultiHostMiddleware สำหรับ django 2.1+

ฉันมีโปรเจ็กต์ django โปรเจ็กต์เดียวที่มีแอปต่างๆ มากมายที่ควรโฮสต์บนโดเมนที่ต่างกัน ตัวอย่างเช่นลองเรียกพวกเขาว่า:

เว็บไซต์ผู้ดูแลระบบ ourdashboard.com

เว็บไซต์เนื้อหาแรก oursite1.com

เว็บไซต์เนื้อหาที่สอง oursite2.com

ไซต์แดชบอร์ดมีไว้สำหรับผู้เผยแพร่เนื้อหาเท่านั้น ในขณะที่ไซต์เนื้อหามีไว้สำหรับผู้เยี่ยมชม แต่ละไซต์มีความแตกต่างกันในแง่ของฟังก์ชันการทำงาน เนื้อหา และการออกแบบ ฉันต้องการให้ผู้เผยแพร่สามารถโพสต์เนื้อหาบนทั้งสองไซต์ได้ ดังนั้นฉันจะไม่สร้างโปรเจ็กต์ django ที่แตกต่างกัน แต่ประเภทของเนื้อหานั้นต้องการไซต์ที่แตกต่างกันสำหรับผู้ชมเฉพาะกลุ่ม

ฉันเริ่มแอปชื่อแดชบอร์ด ฉันต้องการให้แอปนี้โฮสต์บนโดเมน ourdashboard.com ซึ่งการเข้าถึงโดเมนนี้จะเข้าถึง dashboard.urls โดยตรง โดยพื้นฐานแล้ว ฉันต้องการโฮสต์หลายไซต์โดยใช้โปรเจ็กต์ django เดียว โดยที่แต่ละโดเมนจะเชื่อมโยงกับไฟล์ URL ของแอปเฉพาะ

ฉันค้นคว้าข้อมูลเล็กน้อย และบังเอิญเจอ MultiHostMiddleware และพยายามนำไปใช้ ดูเรียบง่ายและใช้งานง่าย แต่เมื่อไม่เคยทำงานกับมิดเดิลแวร์ djangos มาก่อน ฉันจึงชนกำแพงตั้งแต่เริ่มต้น ฉันติดตั้งโค้ดอย่างถูกต้องตามคำแนะนำ แต่ฉันยังคงได้รับข้อผิดพลาดเซิร์ฟเวอร์ภายใน 500 ข้อ ตอนแรกฉันคิดว่าฉันทำบางอย่างผิดพลาดในไฟล์การตั้งค่าของฉัน แต่ไม่เห็นว่าปัญหาอยู่ที่ใด จากนั้น ฉันตรวจดูบันทึกและสังเกตเห็นว่าคลาสมิดเดิลแวร์ไม่ได้รับ get_response การวิจัยเพิ่มเติมอีกเล็กน้อยใน เอกสารประกอบมิดเดิลแวร์ แสดงให้ฉันเห็นว่าจำเป็นต้องมีการเริ่มต้นและฟังก์ชันที่เรียกได้ และ __init__ สามารถรับได้เพียงอาร์กิวเมนต์ 'get_response' เพียงตัวเดียวเท่านั้น นอกจากนี้ ฉันได้เรียนรู้ว่ามีการเปลี่ยนแปลงครั้งใหญ่กับมิดเดิลแวร์ djangos เมื่อไม่นานนี้ และการอัปเดตล่าสุดของ MultiHostMiddleware เมื่อ 3 ปีที่แล้ว (ปัจจุบันฉันใช้ Django 2.1.5 ดังนั้นหลังมิดเดิลแวร์จึงมีการเปลี่ยนแปลง) ตอนนี้ฉันจ้องโค้ดเก่ามาเป็นเวลา 6 ชั่วโมงแล้ว ค้นหาวิธีแก้ปัญหาที่เป็นไปได้ แต่บอกตามตรงว่าฉันไม่รู้ด้วยซ้ำว่าจะเริ่มต้นอย่างไรเมื่อพูดถึงมิดเดิลแวร์ ฉันยังคิดว่าฉันสามารถนำฟังก์ชันที่มีอยู่ไปใช้กับฟังก์ชันที่ต้องการได้ โดยคิดว่า process_response เป็นสิ่งที่เรียกได้ เนื่องจากมันจะส่งคืนการตอบสนอง แต่ฉันเพิ่งตกลงไปในหลุมกระต่ายอีกอันหนึ่ง ดังนั้น ฉันกำลังมองหาวิธีปรับใช้โค้ดเก่านี้สำหรับ django 2.1 เพื่อโฮสต์ไซต์ต่างๆ โดยใช้โปรเจ็กต์ django เดียวกัน

settings.py

MIDDLEWARE = [
    'network.middleware.MultiHostMiddleware',
    ...
]

HOST_MIDDLEWARE_URLCONF_MAP = {
    "ourdahsboard.com": "dashboard.urls",
    "oursite1.com": "musiclounge.urls",
    "oursite2.com": "artworld.urls",
}

มิดเดิลแวร์.py

import time
from django.conf import settings
from django.utils.cache import patch_vary_headers

class MultiHostMiddleware:

    def process_request(self, request):
        try:
            request.META["LoadingStart"] = time.time()
            host = request.META["HTTP_HOST"]
            #if host[-3:] == ":80":
            #    host = host[:-3] # ignore default port number, if present

            # best way to do this.
            host_port = host.split(':')
            if len(host_port)==2:                    
                host = host_port[0] 

            if host in settings.HOST_MIDDLEWARE_URLCONF_MAP:
                request.urlconf = settings.HOST_MIDDLEWARE_URLCONF_MAP[host]
                request.META["MultiHost"] = str(request.urlconf)
            else:
                request.META["MultiHost"] = str(settings.ROOT_URLCONF)

        except KeyError:
            pass # use default urlconf (settings.ROOT_URLCONF)

    def process_response(self, request, response):
        if 'MultiHost' in request.META:
            response['MultiHost'] = request.META.get("MultiHost")

        if 'LoadingStart' in request.META:
            _loading_time = time.time() - int(request.META["LoadingStart"])
            response['LoadingTime'] = "%.2fs" % ( _loading_time, )

        if getattr(request, "urlconf", None):
            patch_vary_headers(response, ('Host',))
        return response

** อัปเดต **

As, requestedstack error:

Traceback (most recent call last):
   File "/home/user/webapps/django_network/network/network/wsgi.py", line 16, in <module>
     application = get_wsgi_application()
   File "/home/user/webapps/django_network/lib/python3.7/Django-2.1.5-py3.7.egg/django/core/wsgi.py", line 13, in get_wsgi_application
     return WSGIHandler()
   File "/home/user/webapps/django_network/lib/python3.7/Django-2.1.5-py3.7.egg/django/core/handlers/wsgi.py", line 136, in __init__
     self.load_middleware()
   File "/home/user/webapps/django_network/lib/python3.7/Django-2.1.5-py3.7.egg/django/core/handlers/base.py", line 36, in load_middleware
     mw_instance = middleware(handler)
 TypeError: __init__() missing 1 required positional argument: 'get_response'

person Ablivion    schedule 05.02.2019    source แหล่งที่มา
comment
คุณช่วยแบ่งปันข้อผิดพลาด stacktraces ได้ไหม   -  person ruddra    schedule 05.02.2019
comment
@ruddra แน่นอนว่าเพิ่มเป็นการอัปเดตที่ด้านล่างของโพสต์ต้นฉบับของฉัน   -  person Ablivion    schedule 05.02.2019


คำตอบ (1)


ฉันคิดว่าคุณกำลังเขียนรูปแบบเก่า MIDDLEWARE(ซึ่งมีอยู่จนถึง django 1.10) คุณต้องอัปเดตดังนี้:

class MultiHostMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response


    def __call__(self, request):
        loading_time = time.time()
        request.META["LoadingStart"] = loading_time
        host = request.META["HTTP_HOST"]    
        host_port = host.split(':')
        response = self.get_response(request)
        if len(host_port)==2:                    
            host = host_port[0] 
        try:
            if host in settings.HOST_MIDDLEWARE_URLCONF_MAP:
                request.urlconf = settings.HOST_MIDDLEWARE_URLCONF_MAP[host]
                request.META["MultiHost"] = str(request.urlconf)
                response['MultiHost'] = str(request.urlconf)
            else:
                request.META["MultiHost"] = str(settings.ROOT_URLCONF)
                response["MultiHost"] = str(settings.ROOT_URLCONF)

        except KeyError:
            pass 
        _loading_time = time.time() - loading_time
        response['LoadingTime'] = "%.2fs" % ( _loading_time, )
        if getattr(request, "urlconf", None):
            patch_vary_headers(response, ('Host',)) 
        return response

โปรดทราบ นี่เป็นรหัสที่ยังไม่ผ่านการทดสอบ แต่จะป้องกันข้อผิดพลาดที่คุณกำลังเผชิญอยู่ในขณะนี้

อัปเดต

คุณสามารถอัปเดตมิดเดิลแวร์ django แบบเก่าเป็นรูปแบบใหม่ได้ตาม เอกสารประกอบ ฉันคิดว่าคุณสามารถลองสิ่งนี้:

from django.utils.deprecation import MiddlewareMixin

class MultiHostMiddleware(MiddlewareMixin):
    # rest of the code from your question
person ruddra    schedule 05.02.2019
comment
อย่างน้อยฉันก็ไม่ได้รับข้อผิดพลาดอีกต่อไป อย่างไรก็ตาม ฉันก็ไม่ถูกเปลี่ยนเส้นทางไปยัง URL ที่เหมาะสมเช่นกัน จนถึงตอนนี้ ฉันทดสอบโค้ดและในแต่ละโดเมนและร้องขอ META['MultiHost'] ส่งคืน URL ที่เหมาะสมสำหรับโดเมนเหล่านั้น (โดยการพิมพ์คำขอ [MultiHost] โดยตรงในเทมเพลต) แต่ในขณะเดียวกัน แต่ละโดเมนยังคงชี้ เป็น URL ROOT_URLCONF เริ่มต้น และนี่คือส่วนที่ทำให้ฉันสับสนเกี่ยวกับมิดเดิลแวร์ เพราะฉันคิดว่าการตอบสนองที่ทำให้เกิดข้อผิดพลาดนี้ ฉันไม่รู้วิธีทดสอบเนื้อหาการตอบกลับอย่างเหมาะสม ซึ่งต่างจากเนื้อหาคำขอที่ฉันสามารถพิมพ์ออกมาได้ - person Ablivion; 05.02.2019
comment
@Ablivion ฉันไม่แน่ใจว่ามิดเดิลแวร์นี้จะทำงานอย่างไรพูดตามตรง ฉันเพิ่งแก้ไขข้อผิดพลาดที่คุณพบ :) - person ruddra; 06.02.2019
comment
@Ablivion ฉันคิดว่าคุณสามารถตรวจสอบสิ่งนี้ได้: django-tenant-schemas readthedocs.io/en/latest/use.html - person ruddra; 08.02.2019
comment
น่าเสียดายที่ดูเหมือนว่าโดเมนหนึ่งจะถูกจำกัดให้ใช้โดเมนย่อยเท่านั้น ไม่พบที่ใดในเอกสารประกอบวิธีการรองรับสองโดเมนที่แยกจากกัน - person Ablivion; 08.02.2019
comment
ฉันไม่คิดอย่างนั้น ฉันคิดว่ามันรองรับหลายโดเมน โปรดตรวจสอบเอกสารอีกครั้ง ขอบคุณ - person ruddra; 08.02.2019
comment
ในที่สุดก็ใช้งานได้ django-hosts แก้ไขปัญหาได้ - person Ablivion; 11.02.2019