Mengadaptasi MultiHostMiddleware untuk Django 2.1+

Saya memiliki satu proyek Django dengan beberapa aplikasi berbeda yang seharusnya dihosting di domain berbeda. Misalnya, sebut saja mereka:

Situs administratif, ourdashboard.com

Situs Konten Pertama oursite1.com

Situs Konten Kedua oursite2.com

Situs dashboard hanya untuk penerbit konten, sedangkan situs konten untuk pengunjung. Setiap situs berbeda dalam hal fungsionalitas, konten, dan desain. Saya ingin penerbit dapat memposting konten di kedua situs, jadi saya tidak akan membuat proyek Django yang berbeda. Namun genre konten memerlukan situs berbeda untuk audiens tertentu.

Saya memulai sebuah aplikasi bernama dashboard. Saya ingin aplikasi ini dihosting di domain dashboard.com kami, di mana mengakses domain ini akan langsung mengakses dashboard.urls. Jadi pada dasarnya saya ingin meng-host beberapa situs menggunakan satu proyek Django, di mana setiap domain akan ditautkan ke file url aplikasi tertentu.

Saya melakukan sedikit riset, dan menemukan MultiHostMiddleware dan mencoba mengimplementasikannya. Terlihat sederhana dan mudah, tetapi karena belum pernah bekerja dengan middleware Djangos sebelumnya, saya menemui jalan buntu sejak awal. Saya menerapkan kode dengan benar seperti yang diinstruksikan tetapi saya terus mendapatkan 500 Internal Server Error. Awalnya saya pikir saya mengacaukan sesuatu di file pengaturan saya, tapi tidak bisa melihat di mana masalahnya. Kemudian saya melihat log dan memperhatikan bahwa kelas middleware tidak menerima get_response. Sedikit penelitian lebih lanjut di Dokumentasi Middleware menunjukkan kepada saya bahwa inisialisasi dan fungsi yang dapat dipanggil diperlukan dan __init__ hanya dapat menerima satu argumen 'get_response'. Selain itu saya mengetahui ada beberapa perubahan besar pada Djangos middleware belum lama ini, dan pembaruan terakhir pada MultiHostMiddleware lebih dari 3 tahun yang lalu (Saat ini saya menggunakan Django 2.1.5, jadi perubahan pasca-middleware). Saya telah melihat kode lama selama 6 jam sekarang, mencari solusi yang mungkin, tapi sejujurnya saya bahkan tidak tahu harus mulai dari mana ketika berhubungan dengan middleware. Saya bahkan berpikir saya bisa mengadopsi fungsi yang ada ke fungsi yang diperlukan, berpikir process_response adalah yang dapat dipanggil, karena ia mengembalikan respons, tetapi saya jatuh ke lubang kelinci lain. Jadi, saya mencari cara untuk mengadaptasi kode lama ini untuk Django 2.1 untuk meng-host situs berbeda menggunakan proyek Django yang sama.

pengaturan.py

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

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

middleware.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

** MEMPERBARUI **

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 sumber
comment
bisakah Anda membagikan jejak tumpukan kesalahan?   -  person ruddra    schedule 05.02.2019
comment
@ruddra tentu saja, ditambahkan sebagai pembaruan di bagian bawah posting asli saya   -  person Ablivion    schedule 05.02.2019


Jawaban (1)


Saya pikir Anda menulis gaya lama MIDDLEWARE(yang ada hingga Django 1.10), Anda perlu memperbaruinya seperti ini:

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

FYI, ini adalah kode yang belum teruji, tetapi ini akan mencegah kesalahan yang Anda hadapi saat ini.

Memperbarui

Anda dapat memperbarui middleware Django gaya lama ke gaya baru sesuai dokumentasi. Saya rasa Anda dapat mencoba seperti ini:

from django.utils.deprecation import MiddlewareMixin

class MultiHostMiddleware(MiddlewareMixin):
    # rest of the code from your question
person ruddra    schedule 05.02.2019
comment
Setidaknya saya tidak lagi mendapatkan kesalahan apa pun. Namun saya juga tidak diarahkan ke url yang tepat. Sejauh ini saya menguji kode dan pada setiap domain dan request.META['MultiHost'] memang mengembalikan url yang tepat untuk domain tersebut (hanya dengan mencetak request[MultiHost] langsung di template), tetapi pada saat yang sama, setiap domain masih menunjuk ke url ROOT_URLCONF default. Dan ini adalah bagian yang membingungkan saya tentang middleware, karena menurut saya respons itulah yang menyebabkan kesalahan ini. Saya tidak tahu cara menguji konten respons dengan benar, tidak seperti konten permintaan yang bisa saya cetak begitu saja. - person Ablivion; 05.02.2019
comment
@Ablivion Saya tidak yakin bagaimana middleware ini akan bekerja, jujur. Saya baru saja memperbaiki kesalahan yang Anda hadapi. :) - person ruddra; 06.02.2019
comment
@Ablivion Saya rasa Anda dapat memeriksanya: django-tenant-schemas. bacathedocs.io/en/latest/use.html - person ruddra; 08.02.2019
comment
Sayangnya yang tampaknya terbatas pada sudomain, tidak dapat menemukan dokumentasi bagaimana mendukung dua domain terpisah. - person Ablivion; 08.02.2019
comment
Saya kira tidak demikian. Saya rasa ini mendukung banyak domain. Silakan periksa dokumentasinya lagi. Terima kasih - person ruddra; 08.02.2019
comment
akhirnya berhasil, django-hosts memecahkan masalah - person Ablivion; 11.02.2019