美文网首页
Django多子域名路由配置方案django-hosts

Django多子域名路由配置方案django-hosts

作者: 吾星喵 | 来源:发表于2019-05-21 15:50 被阅读0次

    欢迎访问我的博客查看 我的博客

    Django多子域名路由配置方案django-hosts

    效果

    • http://www.mydomain.cn/api/ --> http://api.mydomain.cn/
    • http://www.mydomain.cn/blog/ --> http://blog.mydomain.cn/
    • http://www.mydomain.cn/ --> http://www.mydomain.cn/ 保持不变

    同一个app实现

    原方案

    image.png
    # DjangoHostsTest/settings.py
    
    ALLOWED_HOSTS = [
        '.mydomain.cn',  # 匹配.mydomain.cn的所有域名
    ]
    

    修改主机的hosts,以支持域名访问本地服务,且服务运行在80端口run server 0.0.0.0:80测试。

    127.0.0.1 www.mydomain.cn
    127.0.0.1 blog.mydomain.cn
    127.0.0.1 api.mydomain.cn
    

    项目主urls

    # 项目urls
    
    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('blog/', include('blog.urls', namespace='blog')),
        path('api/', include('api.urls', namespace='api')),
        path('', include('www.urls', namespace='www')),
    ]
    

    项目 www - url

    # www ruls  apps/www/urls.py
    
    from django.urls import path
    from .views import index
    
    app_name = 'www'
    
    urlpatterns = [
        path('', index, name='index'),
    ]
    
    <!-- apps/www/templates/www/index.html -->
    
    <h2>项目主页</h2>
    <h4><a href="{% url 'blog:index' %}">博客</a></h4>
    <h4><a href="{% url 'api:index' %}">接口</a></h4>
    

    访问 http://www.mydomain.cn/

    image.png

    博客 blog - url

    # blog urls  apps/blog/urls.py
    
    from django.urls import path
    from .views import index, blog_list, blog_detail
    
    app_name = 'blog'
    
    urlpatterns = [
        path('', index, name='index'),
        path('list/', blog_list, name='list'),
        path('detail/<str:blog_id>/', blog_detail, name='detail'),
    ]
    
    <!-- apps/blog/templates/blog/index.html -->
    
    <h2>BLOG主页</h2>
    <a href="{% url 'blog:list' %}">进入BLOG列表</a>
    
    image.png
    <!-- apps/blog/templates/blog/list.html -->
    
    <h4><a href="{% url 'blog:index' %}">返回BLOG主页</a></h4>
    <ul>
        <li><a href="{% url 'blog:detail' 1 %}">进入BLOG详情1</a></li>
        <li><a href="{% url 'blog:detail' 2 %}">进入BLOG详情2</a></li>
    </ul>
    
    image.png
    <!-- apps/blog/templates/blog/detail.html -->
    
    <h2>BLOG详情</h2>
    <h4><a href="{% url 'blog:list' %}">返回BLOG列表</a></h4>
    <b>BLOG正文:</b>
    当前访问的ID:{{ blog_id }}
    
    image.png

    django-hosts配置

    实现 http://www.mydomain.cn/blog/ --> http://blog.mydomain.cn/

    现在如果直接访问 http://blog.mydomain.cn/ 是显示的项目主页,因为没有具体路径的url都由path('', include('www.urls', namespace='www')),去匹配

    image.png

    安装

    pip install django-hosts
    

    配置settings.py

    添加 django_hostsINSTALLED_APPS

    # DjangoHostsTest/settings.py
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'blog.apps.BlogConfig',
        'api.apps.ApiConfig',
        'www.apps.WwwConfig',
        'django_hosts',  # pip install django-hosts 安装,添加app(第1步)
    ]
    

    添加django_hosts.middleware.HostsRequestMiddlewareMIDDLEWARE最前面;添加django_hosts.middleware.HostsResponseMiddlewareMIDDLEWARE最后面。

    # DjangoHostsTest/settings.py
    
    MIDDLEWARE = [
        'django_hosts.middleware.HostsRequestMiddleware',  # django-hosts 必须添加到最前面(第2步)
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'django_hosts.middleware.HostsResponseMiddleware',  # django-hosts  必须添加到最后面(第3步)
    ]
    

    在项目主 urls.py 旁创建hosts.py 文件,创建一个包含默认主机模式的新模块

    image.png

    设置 ROOT_HOSTCONF 包含hosts.py文件的模块

    # DjangoHostsTest/settings.py
    
    ROOT_HOSTCONF = 'DjangoHostsTest.hosts'  # django-hosts  在ROOT_URLCONF之后增加,指定hosts.py文件可引用位置(第4步)
    

    设置DEFAULT_HOST,没匹配到的就用该模式

    # DjangoHostsTest/settings.py
    
    DEFAULT_HOST = 'www'  # django-hosts  ROOT_HOSTCONF之后增加,设置默认模式匹配。如果没有其他模式匹配,或者没有为host_url模板标记指定名称,则将使用它。(第5步)
    

    设置PARENT_HOST显示域部分

    # DjangoHostsTest/settings.py
    
    PARENT_HOST = 'mydomain.cn'  # django-hosts  如果想在呈现的URL的域部分附加一个默认域名,否则就只有“blog/index/”,而不是“blog.domain.cn/index/”(第6步)
    

    配置hosts.py

    # DjangoHostsTest/hosts.py
    
    """
    创建一个包含默认主机模式的新模块,例如在url .py旁边的hosts.py文件中。
    """
    from django.conf import settings
    from django_hosts import patterns, host
    
    host_patterns = patterns('',  # 配置模式的正则表达式,如果要使用https,在需要的host中增加 scheme='https://' 属性(第7步)
        host(r'www', settings.ROOT_URLCONF, name='www'),  # http://www.domain.cn/ 直接请求主urls中配置的路由
        host(r'api', 'api.urls', name='api'),   # http://api.mydomain.cn/
        host(r'blog', 'blog.urls', name='blog'),  # http://blog.mydomain.cn/
    )
    

    此时刷新 http://blog.mydomain.cn/ 是会报错的

    django.urls.exceptions.NoReverseMatch: 'blog' is not a registered namespace

    配置html

    在模板中,可以使用host_url()template tag来反向使用Django的URL template tag,需要添加{% load hosts %}

    • BLOG主页
    <!-- apps/blog/templates/blog/index.html -->
    
    <!DOCTYPE html>
    {% load hosts %}
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BLOG主页</title>
    </head>
    <body>
    <h2>BLOG主页</h2>
    {#<a href="{% url 'blog:list' %}">进入BLOG列表</a>#}
    <h4><a href="{% host_url 'list' host 'blog' %}">进入BLOG列表(django-hosts)</a></h4>
    </body>
    </html>
    

    就不能使用<a href="{% url 'blog:list' %}">进入BLOG列表</a>,这会导致报错。

    注意:任何与该App有关的用过host_url的模板中,都不能出现Django中的url,否则会出现问题'app' is not a registered namespace

    image.png

    现在BLOG列表的链接就是http://blog.mydomain.cn/list/

    • BLOG列表
    <!-- apps/blog/templates/blog/list.html -->
    
    <!DOCTYPE html>
    {% load hosts %}
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BLOG列表</title>
    </head>
    <body>
    <h2>BLOG列表</h2>
    {#<h4><a href="{% url 'blog:index' %}">返回BLOG主页</a></h4>#}
    <h4><a href="{% host_url 'index' host 'blog' %}">返回BLOG主页(django-hosts)</a></h4>
    <ul>
    {#    <li><a href="{% url 'blog:detail' 1 %}">进入BLOG详情1</a></li>#}
    {#    <li><a href="{% url 'blog:detail' 2 %}">进入BLOG详情2</a></li>#}
        <li><a href="{% host_url 'detail' 1 host 'blog' %}">进入BLOG详情1(django-hosts)</a></li>
        <li><a href="{% host_url 'detail' 2 host 'blog' %}">进入BLOG详情2(django-hosts)</a></li>
    </ul>
    </body>
    </html>
    
    image.png

    如果是需要传递参数<li><a href="{% url 'blog:detail' 1 %}">进入BLOG详情1</a></li>,也要做类似的改动<li><a href="{% host_url 'detail' 1 host 'blog' %}">进入BLOG详情1(django-hosts)</a></li>

    现在BLOG详情的链接就是http://blog.mydomain.cn/detail/1/

    • BLOG详情
    <!-- apps/blog/templates/blog/detail.html -->
    
    <!DOCTYPE html>
    {% load hosts %}
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BLOG详情</title>
    </head>
    <body>
    <h2>BLOG详情</h2>
    {#<h4><a href="{% url 'blog:list' %}">返回BLOG列表</a></h4>#}
    <h4><a href="{% host_url 'list' host 'blog' %}">返回BLOG列表(django-hosts)</a></h4>
    <b>BLOG正文:</b>
    当前访问的ID:{{ blog_id }}
    </body>
    </html>
    
    image.png

    视图中反向url

    在Python方面,比如视图,类似于Django的单向函数。只需使用django_hosts中的reverse()函数

    # apps/blog/views.py
    
    from django.shortcuts import render
    from django_hosts.resolvers import reverse
    
    
    def index(request):
        blog_99_url = reverse('detail', args=(99,), host='blog')
        return render(request, 'blog/index.html', {'blog_99_url': blog_99_url})
    

    在模板中显示该url

    <!-- apps/blog/templates/blog/index.html -->
    
    <!DOCTYPE html>
    {% load hosts %}
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BLOG主页</title>
    </head>
    <body>
    <h2>BLOG主页</h2>
    {#<a href="{% url 'blog:list' %}">进入BLOG列表</a>#}
    <h4><a href="{% host_url 'list' host 'blog' %}">进入BLOG列表(django-hosts)</a></h4>
    <a href="{{ blog_99_url }}" target="_blank">推荐阅读  {{ blog_99_url }}</a>
    </body>
    </html>
    
    image.png

    得到blog_99_url的连接为http://blog.mydomain.cn/detail/99/

    点进去就可以得到

    image.png

    media文件加载404问题

    修改原App urls.py

    # blog urls  apps/blog/urls.py
    
    from django.conf import settings
    from django.conf.urls.static import static
    from django.urls import path
    from .views import index, blog_list, blog_detail
    
    app_name = 'blog'
    
    urlpatterns = [
        path('', index, name='index'),
        path('list/', blog_list, name='list'),
        path('detail/<str:blog_id>/', blog_detail, name='detail'),
    ]
    
    if settings.DEBUG:
        urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    

    当DEBUG模式时,增加media的路径,而不用hosts时,media是配置到项目主 urls.py 中的

    Nginx的配置只需要将子域名都绑定到对应的启动端口即可,后端根据子域名进行不同的路由。
    另外这也会存在跨域问题,比如http://blog.mydomain.cn/登录是在http://www.mydomain.cn/usercenter/login/这个链接。

    相关文章

      网友评论

          本文标题:Django多子域名路由配置方案django-hosts

          本文链接:https://www.haomeiwen.com/subject/ulyjzqtx.html