12-day07-项目开发-基于inclusion_tag实现菜单切换、项目管理URL及视图、项目菜单实现
目录
一、基于inclusion_tag实现菜单切换
1.1、inclusion_tag介绍
- 原型: django.template.Library.inclusion_tag()
- 主要作用:通过渲染一个模板来显示一些数据。
- 例如,Django的Admin界面使用自定义模板标签显示"添加/更改"表单页面底部的按钮。这些按钮看起来总是相同,但链接的目标却是根据正在编辑的对象而变化的。
- 这种类型的标签被称为"Inclusion 标签",属于自定义标签的一种。
1.2、inclusion_tag实现菜单切换
- 第一步 :定义inclusion_tag 渲染的数据函数及页面
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % mkdir web_app/templatetags
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % mkdir web_app/templates/inclusion
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templatetags/project.py
from django.template import Library
from web_app import models
register = Library()
@register.inclusion_tag('inclusion/all_project_list.html')
def all_project_list(request):
# 1. 获我创建的所有项目
my_project_list = models.Project.objects.filter(creator=request.bug_manager.user)
# 2. 获我参与的所有项目
join_project_list = models.ProjectUser.objects.filter(user=request.bug_manager.user)
return {'my': my_project_list, 'join': join_project_list, 'request': request}
# inclusion_tag定义的装饰器函数中的返回值,是可以直接在以下模板中使用的
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/inclusion all_project_list.html
<li class="dropdown active">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">项目 {% if request.bug_manager.project %}({{ request.bug_manager.project.name }}){% endif %}<span class="caret"></span></a>
<ul class="dropdown-menu">
{% if my %}
<li><i class="fa fa-list" aria-hidden="true"></i> 我创建的项目</li>
{% for item in my %}
<li><a href="#">{{ item.name }}</a></li>
{% endfor %}
<li role="separator" class="divider"></li>
{% endif %}
{% if join %}
<li><i class="fa fa-handshake-o" aria-hidden="true"></i> 我参与的项目</li>
{% for item in join %}
<li><a href="#">{{ item.project.name }}</a></li>
{% endfor %}
<li role="separator" class="divider"></li>
{% endif %}
<li><a href="{% url 'project_list' %}">所有项目</a></li>
</ul>
</li>
- 第二步 :manager母模板中调用inclusion_tag
(all_project_list需要接受request参数)
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/layout/manage.html
{% load static %}
{% load project %}
...
...
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
{% all_project_list request %} // 传入request参数
<ul class="nav navbar-nav navbar-right">
<li><a href="#">工作台</a></li>
<li><a href="#">日历</a></li>
<li><a href="#"> <i class="fa fa-bell-o" aria-hidden="true"></i> </a></li>
<li><a href="#"> <i class="fa fa-bookmark" aria-hidden="true"></i> </a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">{{ request.bug_manager.user.username }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'index' %}">官 网</a></li>
<li role="separator" class="divider"></li>
<li><a href="{% url 'logout' %}">退 出</a></li>
</ul>
</li>
</ul>
</div>
...
...
二、项目管理URL及视图
2.1、项目管理URL及视图、模板规划
2.1.1、路由规划
/manage/项目ID/dashboard
/manage/项目ID/issues
/manage/项目ID/statistics
/manage/项目ID/file
/manage/项目ID/wiki
/manage/项目ID/setting
- 第一种方式实现路由规划
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/urls.py
from django.conf.urls import url, include
from web_app.views import account
from web_app.views import home
from web_app.views import project
urlpatterns = [
url(r'^send/sms/$', account.send_sms, name='send_sms'), # 发送SMS
url(r'^login/sms/$', account.login_sms, name='login_sms'), # 短信登录
url(r'^register/$', account.register, name='register'), # 用户注册
url(r'^login/$', account.login, name='login'), # 用户名邮箱验证码登录
url(r'^image/code/$', account.image_code, name='image_code'), # 图片验证码
url(r'^index/$', home.index, name='index'), # 登录首页
url(r'^logout/$', account.logout, name='logout'), # 退出登录
url(r'^project/list/$', project.project_list, name='project_list'), # 项目列表
# /project/star/join/1
# /project/star/my/1
url(r'^project/star/(?P<project_type>\w+)/(?P<project_id>\d+)/$', project.project_star, name='project_star'), # 星标项目
url(r'^project/unstar/(?P<project_type>\w+)/(?P<project_id>\d+)/$', project.project_unstar, name='project_unstar'), # 取消星标
url(r'^manage/(?P<project_id>\d+)/dashboard/$',project.project_star, name='dashboard'),
url(r'^manage/(?P<project_id>\d+)/issues/$', project.project_star, name='issues'),
url(r'^manage/(?P<project_id>\d+)/statistics/$', project.project_star, name='statistics'),
...
]
推荐
第二种实现路由规划,路由分发,每个路由必须迭代一个project_id参数
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/urls.py
from django.conf.urls import url, include
from web_app.views import account
from web_app.views import home
from web_app.views import project
from web_app.views import manage
urlpatterns = [
url(r'^send/sms/$', account.send_sms, name='send_sms'), # 发送SMS
url(r'^login/sms/$', account.login_sms, name='login_sms'), # 短信登录
url(r'^register/$', account.register, name='register'), # 用户注册
url(r'^login/$', account.login, name='login'), # 用户名邮箱验证码登录
url(r'^image/code/$', account.image_code, name='image_code'), # 图片验证码
url(r'^index/$', home.index, name='index'), # 登录首页
url(r'^logout/$', account.logout, name='logout'), # 退出登录
url(r'^project/list/$', project.project_list, name='project_list'), # 项目列表
# /project/star/join/1
# /project/star/my/1
url(r'^project/star/(?P<project_type>\w+)/(?P<project_id>\d+)/$', project.project_star, name='project_star'), # 星标项目
url(r'^project/unstar/(?P<project_type>\w+)/(?P<project_id>\d+)/$', project.project_unstar, name='project_unstar'), # 取消星标
url(r'^manage/(?P<project_id>\d+)/', include([
url(r'^dashboard/$', manage.dashboard, name='dashboard'),
url(r'^wiki/$', manage.wiki, name='wiki'),
url(r'^file/$', manage.file, name='file'),
url(r'^setting/$', manage.setting, name='setting'),
url(r'^issues/$', manage.issues, name='issues'),
url(r'^statistics/$', manage.statistics, name='statistics'),
# url(r'^dashboard/issues/chart/$', manage.issues_chart, name='issues_chart'),
#
# url(r'^wiki/$', wiki.wiki, name='wiki'),
# url(r'^wiki/add/$', wiki.wiki_add, name='wiki_add'),
# url(r'^wiki/catalog/$', wiki.wiki_catalog, name='wiki_catalog'),
# url(r'^wiki/delete/(?P<wiki_id>\d+)/$', wiki.wiki_delete, name='wiki_delete'),
# url(r'^wiki/edit/(?P<wiki_id>\d+)/$', wiki.wiki_edit, name='wiki_edit'),
# url(r'^wiki/upload/$', wiki.wiki_upload, name='wiki_upload'),
#
# url(r'^file/$', file.file, name='file'),
# url(r'^file/delete/$', file.file_delete, name='file_delete'),
# url(r'^cos/credential/$', file.cos_credential, name='cos_credential'),
# url(r'^file/post/$', file.file_post, name='file_post'),
# url(r'^file/download/(?P<file_id>\d+)/$', file.file_download, name='file_download'),
#
# url(r'^setting/$', setting.setting, name='setting'),
# url(r'^setting/delete/$', setting.delete, name='setting_delete'),
#
# url(r'^issues/$', issues.issues, name='issues'),
# url(r'^issues/detail/(?P<issues_id>\d+)/$', issues.issues_detail, name='issues_detail'),
# url(r'^issues/record/(?P<issues_id>\d+)/$', issues.issues_record, name='issues_record'),
# url(r'^issues/change/(?P<issues_id>\d+)/$', issues.issues_change, name='issues_change'),
# url(r'^issues/invite/url/$', issues.invite_url, name='invite_url'),
#
# url(r'^statistics/$', statistics.statistics, name='statistics'),
# url(r'^statistics/priority/$', statistics.statistics_priority, name='statistics_priority'),
# url(r'^statistics/project/user/$', statistics.statistics_project_user, name='statistics_project_user'),
], None, None)),
# None 表示 反向代理的 namesapce,如果指定namesapce,前端请求此路由时就需要以{{% namespace_name:name%}} -> {{% haha:statistics_project_user%}}
]
2.1.2、路由规划
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/views/manage.py
from django.shortcuts import render
def dashboard(request, project_id):
return render(request, 'dashboard.html')
def wiki(request, project_id):
return render(request, 'wiki.html')
def file(request, project_id):
return render(request, 'file.html')
def setting(request, project_id):
return render(request, 'setting.html')
def issues(request, project_id):
return render(request, 'issues.html')
def statistics(request, project_id):
return render(request, 'statistics.html')
2.1.3、模板规划
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/dashboard.html
{% extends 'layout/manage.html' %}
{% block content %}
<h1>概览</h1>
{% endblock %}
2.2、项目管理URL及视图
- 第一步 :调整
项目列表 project_list.html
页面,当用户点击项目名称,就跳转至对用的项目信息中;
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/project_list.html
...
...
<div class="container-fluid project">
<div style="margin: 10px 0;">
<a class="btn btn-primary" data-toggle="modal" data-target="#addModal">
<i class="fa fa-plus-circle" aria-hidden="true"></i> 新建项目
</a>
</div>
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fa-star" aria-hidden="true"></i> 星标</div>
<div class="panel-body">
{% for item in project_dict.star %}
<div class="item">
<a href="{% url 'dashboard' project_id=item.value.id %}" class="title"
style="background-color: {{ item.value.get_color_display }};">{{ item.value.name }}</a>
<div class="info">
<div>
{# 取消星标 #}
<a href="{% url 'project_unstar' project_type=item.type project_id=item.value.id %}">
<i class="fa fa-star" aria-hidden="true" style="color: #f0ad4e;"></i>
</a>
<span>{{ item.value.creator.username }}</span>
</div>
<div>
<i class="fa fa-user-o" aria-hidden="true"></i>
<span>{{ item.value.join_count }}</span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fa-list" aria-hidden="true"></i> 我创建的</div>
<div class="panel-body">
{% for item in project_dict.my %}
<div class="item">
<a href="{% url 'dashboard' project_id=item.id %}" class="title"
style="background-color: {{ item.get_color_display }};">{{ item.name }}</a>
<div class="info">
<div>
<a href="{% url 'project_star' project_type='my' project_id=item.id %}">
<i class="fa fa-star" aria-hidden="true" style="color: #d5d5d5"></i>
</a>
<span>{{ item.creator.username }}</span>
</div>
<div>
<i class="fa fa-user-o" aria-hidden="true"></i>
<span>{{ item.join_count }}</span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fa-handshake-o" aria-hidden="true"></i> 我参与的</div>
<div class="panel-body">
{% for item in project_dict.join %}
<div class="item">
<a href="{% url 'dashboard' project_id=item.id %}" class="title"
style="background-color: {{ item.get_color_display }};">{{ item.name }}</a>
<div class="info">
<div>
<a href="{% url 'project_star' project_type='join' project_id=item.id %}">
<i class="fa fa-star" aria-hidden="true" style="color: #d5d5d5"></i>
</a>
<span>{{ item.creator.username }}</span>
</div>
<div>
<i class="fa fa-user-o" aria-hidden="true"></i>
<span>{{ item.join_count }}</span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
...
...
2.3、进入项目展开菜单
2.3.1、显示菜单
-
显示菜单条件:
进入项目,显示菜单,根据设计的路由,路由以manage开头的路由则表示已经进入项目
项目的project_id 是我创建的或者是我参与的才可以进入项目
-
第一步 :将
项目的project_id 是我创建的或者是我参与的才可以进入项目
及根据路由以manage开头,则表示已经进入项目
放置中间件
进行判断;
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/middleware/auth.py
from django.utils.deprecation import MiddlewareMixin
from web_app import models
from django.conf import settings
from django.shortcuts import redirect
import datetime
class Bug_manager(object):
def __init__(self):
self.user = None
self.price_policy = None
self.project = None
class AuthMiddleware(MiddlewareMixin):
def process_request(self, request):
""" 如果用户已经登录,则request中赋值 """
request.bug_manager = Bug_manager()
user_id = request.session.get('user_id', 0) # 用户登录则session中有用户ID,如果没有则为0
# 如果登录的用户存在则返回用户对象,不存在返回None
user_object = models.UserInfo.objects.filter(id=user_id).first()
request.bug_manager.user = user_object
# 白名单:没有登录都可以访问的URL
"""
1. 获取当用户访问的URL
2. 检查URL是否在白名单中,如果再则可以继续向后访问,如果不在则进行判断是否已登录
request.path_info 表示用户访问的URI
"""
if request.path_info in settings.WHITE_REGEX_URL_LIST:
return # 中间件返回None表示成功
# 检查用户是否已登录,已登录继续往后走;未登录则返回登录页面。
if not request.bug_manager.user:
return redirect('login')
# 登录成功之后,访问后台管理时:获取当前用户所拥有的额度(交易记录表)
# 方式一:免费额度在交易记录中存储
# 获取当前用户ID值最大(最近交易记录)
_object = models.Transaction.objects.filter(user=user_object, status=2).order_by('-id').first()
# 判断是否已过期
current_datetime = datetime.datetime.now()
if _object.end_datetime and _object.end_datetime < current_datetime:
_object = models.Transaction.objects.filter(user=user_object, status=2, price_policy__category=1).first()
# request.transaction = _object # (存储了整张交易记录表中的信息)
request.bug_manager.price_policy = _object.price_policy # (存储了登录的用户及用户的额度信息)
# 方式二:免费的额度存储配置文件
"""
# 获取当前用户ID值最大(最近交易记录)
_object = models.Transaction.objects.filter(user=user_object, status=2).order_by('-id').first()
if not _object:
# 没有购买
request.price_policy = models.PricePolicy.objects.filter(category=1, title="个人免费版").first()
else:
# 付费版
current_datetime = datetime.datetime.now()
if _object.end_datetime and _object.end_datetime < current_datetime:
request.price_policy = models.PricePolicy.objects.filter(category=1, title="个人免费版").first()
else:
request.price_policy = _object.price_policy
"""
def process_view(self, request, view, args, kwargs):
# 判断URL是否是以manage开头,如果是则判断项目ID是否是我创建 or 参与
if not request.path_info.startswith('/manage/'):
return
# 获取项目ID
project_id = kwargs.get('project_id')
# 是否是我创建的
project_object = models.Project.objects.filter(creator=request.bug_manager.user, id=project_id).first()
if project_object:
# 是我创建的项目的话,我就让他通过
request.bug_manager.project = project_object
return
# 是否是我参与的项目
project_user_object = models.ProjectUser.objects.filter(user=request.bug_manager.user, project_id=project_id).first()
if project_user_object:
# 是我参与的项目
request.bug_manager.project = project_user_object.project
return
return redirect('project_list')
-
前端就可以通过判断
request.bug_manager.project
有没有值,进行判断项目是否是我创建的活参与的,以及是否进入项目; -
第二步 :在项目管理母模板
manage.html
,增加对request.bug_manager.project
的判断;
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/layout/manage.html
...
...
<nav class="navbar navbar-av">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{% url 'project_list' %}">Bug_manager</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
{% all_project_list request %}
{% if request.bug_manager.project %}
<ul>
<li><a href="#">概览</a></li>
<li><a href="#">wiki</a></li>
</ul>
{% endif %}
<ul class="nav navbar-nav navbar-right">
<li><a href="#">工作台</a></li>
<li><a href="#">日历</a></li>
<li><a href="#"> <i class="fa fa-bell-o" aria-hidden="true"></i> </a></li>
<li><a href="#"> <i class="fa fa-bookmark" aria-hidden="true"></i> </a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">{{ request.bug_manager.user.username }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'index' %}">官 网</a></li>
<li role="separator" class="divider"></li>
<li><a href="{% url 'logout' %}">退 出</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
{% block content %}{% endblock %}
...
...
2.3.2、项目菜单bug修复及默认选中(inclusion_tag)
- 第一步 :获取当前请求的URL和所有的管理相关的URL进行比较,如果前缀相等,就添加一个class="active"(选中效果)
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templatetags/project.py
from django.template import Library
from web_app import models
from django.urls import reverse
register = Library()
@register.inclusion_tag('inclusion/all_project_list.html')
def all_project_list(request):
# 1. 获我创建的所有项目
my_project_list = models.Project.objects.filter(creator=request.bug_manager.user)
# 2. 获我参与的所有项目
join_project_list = models.ProjectUser.objects.filter(user=request.bug_manager.user)
return {'my': my_project_list, 'join': join_project_list, 'request': request}
@register.inclusion_tag('inclusion/manage_menu_list.html')
def manage_menu_list(request):
data_list = [
# 根据 reverse 反向生成url
{'title': '概览', 'url': reverse("dashboard", kwargs={'project_id': request.bug_manager.project.id})},
# {'title': '概览', 'url': reverse("null:dashboard", kwargs={'project_id': request.bug_manager.project.id})},
{'title': '问题', 'url': reverse("issues", kwargs={'project_id': request.bug_manager.project.id})},
{'title': '统计', 'url': reverse("statistics", kwargs={'project_id': request.bug_manager.project.id})},
{'title': 'wiki', 'url': reverse("wiki", kwargs={'project_id': request.bug_manager.project.id})},
{'title': '文件', 'url': reverse("file", kwargs={'project_id': request.bug_manager.project.id})},
{'title': '配置', 'url': reverse("setting", kwargs={'project_id': request.bug_manager.project.id})},
]
for item in data_list:
# 当前用户访问的URL:request.path_info: /manage/4/issues/xxx/add/
if request.path_info.startswith(item['url']):
item['class'] = 'active' # 增加选中效果
return {'data_list': data_list}
- 第二步 :manage_menu_list.html
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/inclusion/manage_menu_list.html
{% for item in data_list %}
<li {% if item.class %} class="{{ item.class }}" {% endif %} ><a href="{{ item.url }}">{{ item.title }}</a></li>
{% endfor %}
- 第三步 :调整项目管理母模板
manage.html
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/layout/manage.html
{% load static %}
{% load project %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{% static 'plugin/bootstrap/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'plugin/font-awesome/css/font-awesome.min.css' %}">
<link rel="stylesheet" href="{% static 'css/manage.css' %}">
<style>
.navbar-av {
border-radius: 0;
}
.error-msg {
color: red;
position: absolute;
font-size: 13px;
}
</style>
{% block css %}{% endblock %}
</head>
<body>
<nav class="navbar navbar-av">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{% url 'project_list' %}">Bug_manager</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
{% all_project_list request %}
{% if request.bug_manager.project %}
{% manage_menu_list request %}
{% endif %}
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">工作台</a></li>
<li><a href="#">日历</a></li>
<li><a href="#"> <i class="fa fa-bell-o" aria-hidden="true"></i> </a></li>
<li><a href="#"> <i class="fa fa-bookmark" aria-hidden="true"></i> </a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">{{ request.bug_manager.user.username }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'index' %}">官 网</a></li>
<li role="separator" class="divider"></li>
<li><a href="{% url 'logout' %}">退 出</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
{% block content %}{% endblock %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<script src="{% static 'plugin/bootstrap/js/bootstrap.min.js' %}"></script>
{% block js %}{% endblock %}
</body>
</html>
向往的地方很远,喜欢的东西很贵,这就是我努力的目标。