Django中有两个app,如果通过域名来访问,可以使用www.domain.com/a、www.domain.com/b来访问。这样就显得有点LowB了。如果我想通过a.domain.com、b.domain.com来访问两个app怎么办?
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实现
原方案
# 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>
博客 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>
<!-- 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>
<!-- apps/blog/templates/blog/detail.html -->
<h2>BLOG详情</h2>
<h4><a href="{% url 'blog:list' %}">返回BLOG列表</a></h4>
<b>BLOG正文:</b>
当前访问的ID:{{ blog_id }}
django-hosts配置
实现 http://www.mydomain.cn/blog/
--> http://blog.mydomain.cn/
现在如果直接访问 http://blog.mydomain.cn/ 是显示的项目主页,因为没有具体路径的url都由path('', include('www.urls', namespace='www')),
去匹配
安装
pip install django-hosts
配置settings.py
添加 django_hosts
到 INSTALLED_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.HostsRequestMiddleware
在MIDDLEWARE
最前面;添加django_hosts.middleware.HostsResponseMiddleware
在MIDDLEWARE
最后面。
# 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
文件,创建一个包含默认主机模式的新模块
设置 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
现在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>
如果是需要传递参数<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>
视图中反向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>
得到blog_99_url
的连接为http://blog.mydomain.cn/detail/99/
点进去就可以得到
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/
这个链接。
转载自:https://blog.starmeow.cn/detail/bf8229696f7a3bb4700cfddef19fa23f/