11-day07-项目开发-项目展示、星标项目、取消星标、项目颜色定制
目录
一、获取项目列表
1.1、查询数据库获取数据
- 1、通过数据库查询项目表,然后循环遍历判断是否有星标;
- 我创建的所有的项目 :已星标、未星标
- 我参与的所有项目 :已星标、未星标
- 2、提取已星标
- 列表 = 循环 【我创建的所有项目】+ 【我参与的所有项目】把星标的数据提取出来;
- 3、得到三个列表 :
星标
、创建
、参与
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/views/project.py
from django.shortcuts import render, redirect
from web_app.forms.project import ProjectModelForm
from django.http import JsonResponse
from web_app import models
def project_list(request):
""" 项目列表 """
if request.method == 'GET':
# GET请求查看项目列表
"""
1. 从数据库中获取两部分数据
我创建的所有项目:已星标、未星标
我参与的所有项目:已星标、未星标
2. 提取已星标
列表 = 循环 [我创建的所有项目] + [我参与的所有项目] 把已星标的数据提取
得到三个列表:星标、创建、参与
"""
project_dict = {'star': [], 'my': [], 'join': []}
my_project_list = models.Project.objects.filter(creator=request.bug_manager.user)
for row in my_project_list:
if row.star:
project_dict['star'].append({"value": row, 'type': 'my'})
else:
project_dict['my'].append(row)
join_project_list = models.ProjectUser.objects.filter(user=request.bug_manager.user)
for item in join_project_list:
if item.star:
project_dict['star'].append({"value": item.project, 'type': 'join'})
else:
project_dict['join'].append(item.project)
form = ProjectModelForm(request)
return render(request, 'project_list.html', {'form': form, 'project_dict': project_dict})
# POST
form = ProjectModelForm(request=request, data=request.POST)
if form.is_valid():
# 通过验证,创建项目 :用户仅填写了项目名称、颜色、描述 ,查看设计的项目表,只有创建者没有默认值,所以获取创建人再写入数据库,不然会报错
form.instance.creator = request.bug_manager.user # 获取创建者
print(form.instance.creator)
form.save()
return JsonResponse({'status': True})
return JsonResponse({'status': False, 'error': form.errors})
1.2、样式处理
- 通过BoootStrap 面板进行展示 : https://v3.bootcss.com/components/#panels
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/project_list.html
{% extends 'layout/manage.html' %}
{% block css %}
<style>
.project {
margin-top: 10px;
}
.panel-body {
padding: 0;
display: flex;
flex-direction: row;
justify-content: left;
align-items: flex-start;
flex-wrap: wrap;
}
.panel-body > .item {
border-radius: 6px;
width: 228px;
border: 1px solid #dddddd;
margin: 20px 10px;
}
.panel-body > .item:hover {
border: 1px solid #f0ad4e;
}
.panel-body > .item > .title {
height: 104px;
color: white;
display: flex;
justify-content: center;
align-items: center;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
font-size: 15px;
text-decoration: none;
}
.panel-body > .item > .info {
padding: 10px 10px;
display: flex;
justify-content: space-between;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
color: #8c8c8c;
}
.panel-body > .item > .info a {
text-decoration: none;
}
.panel-body > .item > .info .fa-star {
font-size: 18px;
}
.color-radio label {
margin-left: 0;
padding-left: 0;
}
.color-radio input[type="radio"] {
display: none;
}
.color-radio input[type="radio"] + .cycle {
display: inline-block;
height: 25px;
width: 25px;
border-radius: 50%;
border: 2px solid #dddddd;
}
.color-radio input[type="radio"]:checked + .cycle {
border: 2px solid black;
}
</style>
{% endblock %}
{% block content %}
<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 class="panel panel-default">
<div class="panel-heading"><i class="fa fa-star" aria-hidden="true"></i> 星标</div>
<div class="panel-body">
{% for itms in project_dict.star %}
<div>{{ itms.name }}</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 itms in project_dict.my %}
<div>{{ itms.name }}</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 itms in project_dict.join %}
<div>{{ itms.name }}</div>
{% endfor %}
</div>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">新建项目</h4>
</div>
<div class="modal-body">
<form id="addForm">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<span class="error-msg"></span>
</div>
{% endfor %}
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取 消</button>
<button id="btnSubmit" type="button" class="btn btn-primary">确 定</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script>
$(function () {
bindSubmit();
});
function bindSubmit() {
$('#btnSubmit').click(function () {
$.ajax({
url: "{% url 'project_list' %}",
type: "POST",
data: $('#addForm').serialize(),
dataType: "JSON",
success: function (res) {
console.log(res);
if (res.status) {
location.href = location.href;
// location.reload()
} else {
$.each(res.error, function (key, value) {
$("#id_" + key).next().text(value[0]);
})
}
}
})
})
}
</script>
{% endblock %}
二、展示项目列表
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/project_list.html
{% extends 'layout/manage.html' %}
{% block css %}
<style>
.project {
margin-top: 10px;
}
.panel-body {
padding: 0;
display: flex;
flex-direction: row;
justify-content: left;
align-items: flex-start;
flex-wrap: wrap;
}
.panel-body > .item {
border-radius: 6px;
width: 228px;
border: 1px solid #dddddd;
margin: 20px 10px;
}
.panel-body > .item:hover {
border: 1px solid #f0ad4e;
}
.panel-body > .item > .title {
height: 104px;
color: white;
display: flex;
justify-content: center;
align-items: center;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
font-size: 15px;
text-decoration: none;
}
.panel-body > .item > .info {
padding: 10px 10px;
display: flex;
justify-content: space-between;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
color: #8c8c8c;
}
.panel-body > .item > .info a {
text-decoration: none;
}
.panel-body > .item > .info .fa-star {
font-size: 18px;
}
.color-radio label {
margin-left: 0;
padding-left: 0;
}
.color-radio input[type="radio"] {
display: none;
}
.color-radio input[type="radio"] + .cycle {
display: inline-block;
height: 25px;
width: 25px;
border-radius: 50%;
border: 2px solid #dddddd;
}
.color-radio input[type="radio"]:checked + .cycle {
border: 2px solid black;
}
</style>
{% endblock %}
{% block content %}
<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="#" class="title"
style="background-color: {{ item.value.get_color_display }};">{{ item.value.name }}</a>
<div class="info">
<div>
<a href="#">
<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="#" class="title"
style="background-color: {{ item.get_color_display }};">{{ item.name }}</a>
<div class="info">
<div>
<a href="#">
<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="#" class="title"
style="background-color: {{ item.get_color_display }};">{{ item.name }}</a>
<div class="info">
<div>
<a href="#">
<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>
<!-- Modal -->
<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">新建项目</h4>
</div>
<div class="modal-body">
<form id="addForm">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<span class="error-msg"></span>
</div>
{% endfor %}
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取 消</button>
<button id="btnSubmit" type="button" class="btn btn-primary">确 定</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script>
$(function () {
bindSubmit();
});
function bindSubmit() {
$('#btnSubmit').click(function () {
$.ajax({
url: "{% url 'project_list' %}",
type: "POST",
data: $('#addForm').serialize(),
dataType: "JSON",
success: function (res) {
console.log(res);
if (res.status) {
location.href = location.href;
// location.reload()
} else {
$.each(res.error, function (key, value) {
$("#id_" + key).next().text(value[0]);
})
}
}
})
})
}
</script>
{% endblock %}
三、星标项目
3.1、添加星标项目
-
添加星标项目分为一下情况:
- 我创建的项目 :
Project
表的start=True
- 我参与的项目 :
ProjectUser
表的start=True
- 我创建的项目 :
-
第一步 :设计路由,点击星标请求此url
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/urls.py
"""Bug_manager URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
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'^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'), # 星标项目
]
- 第二步 :模板对星标增加href,携带project_type和project_id请求URL
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/project_list.html
...
...
<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="#" 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="#" 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>
...
...
- 第三步 :views视图接收 project_type和project_id
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/views/project.py
...
...
def project_star(request, project_type, project_id):
""" 星标项目 """
if project_type == 'my':
models.Project.objects.filter(id=project_id, creator=request.bug_manager.user).update(star=True)
return redirect('project_list')
if project_type == 'join':
models.ProjectUser.objects.filter(project_id=project_id, user=request.bug_manager.user).update(star=True)
return redirect('project_list')
return HttpResponse('请求错误')
3.2、取消星标项目
-
取消星标项目分为一下情况:
- 我创建的项目 :
Project
表的start=False
- 我参与的项目 :
ProjectUser
表的start=False
- 我创建的项目 :
-
第一步 :回顾一下,此前编写的展示项目列表相关的代码
- 利用上面的views中拼凑的数据项目类型在星标模板中进行判断
item.type
- 第二步 :设计取消星标路由
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/urls.py
"""Bug_manager URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
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'^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'), # 取消星标
]
- 第三步 :模板对取消星标增加href,携带project_type和project_id请求URL
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/project_list.html
...
...
<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="#" 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>
...
...
- 第四步 :views视图接收 project_type和project_id
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/views/project.py
...
...
def project_unstar(request, project_type, project_id):
""" 取消星标 """
if project_type == 'my':
models.Project.objects.filter(id=project_id, creator=request.bug_manager.user).update(star=False)
return redirect('project_list')
if project_type == 'join':
models.ProjectUser.objects.filter(project_id=project_id, user=request.bug_manager.user).update(star=False)
return redirect('project_list')
return HttpResponse('请求错误')
四、BootStrapFrom支持部分使用样式
- models中定义的color字段为
SmallIntegerField
类型,默认会展示为下拉框
,如何修改为radio按钮
;
- 使用Form中重写字段类型的方式,实现color字段为radio按钮;
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/forms/project.py
# -*- coding:utf-8 -*-
from django import forms
from django.core.exceptions import ValidationError
from web_app.forms.bootstrap import BootStrapForm
from web_app import models
class ProjectModelForm(BootStrapForm, forms.ModelForm):
# 重写__init__ 仅为在views视图调用Form初始化函数式多传递request参数
def __init__(self, request, *args, **kwargs):
super().__init__(*args, **kwargs)
self.request = request
# desc = forms.CharField(widget=forms.Textarea(attrs={'xx': 123}))
class Meta:
model = models.Project
fields = ['name', 'color', 'desc']
# widgets 重写字段类型
widgets = {
'desc': forms.Textarea,
'color': forms.RadioSelect,
}
...
...
- 下图其实可以查看到,其实已经变成了按钮,只是样式有些问题,下面开始进行调整;
- 造成此问题的原因,是因为此前编写的
BootStrapFrom
会把每个字段都会加上form-control
的样式,所以需要进行优化,将BootStrapFrom
支持部分字段样式添加;
- 第一步 :BootStrapForm
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/forms/bootstrap.py
# -*- coding:utf-8 -*-
class BootStrapForm(object):
bootstrap_class_exclude = []
def __init__(self, *args, **kwargs):
"""
重写RegisterModelForm 的 初始化方法
name 表示字段名称
field 表示forms.CharField对象
code = forms.CharField(label='验证码', widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': "请输入验证码"}))
"""
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
if name in self.bootstrap_class_exclude:
continue
old_class = field.widget.attrs.get('class', "")
field.widget.attrs['class'] = '{} form-control'.format(old_class)
field.widget.attrs['placeholder'] = '请输入%s' % (field.label,)
- 第二步 :froms/project.py
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/forms/project.py
# -*- coding:utf-8 -*-
from django import forms
from django.core.exceptions import ValidationError
from web_app.forms.bootstrap import BootStrapForm
from web_app import models
class ProjectModelForm(BootStrapForm, forms.ModelForm):
# 不使用BootStrapForm自动添加的样式的字段
bootstrap_class_exclude = ['color']
# desc = forms.CharField(widget=forms.Textarea(attrs={'xx': 123}))
class Meta:
model = models.Project
fields = ['name', 'color', 'desc']
# widgets 重写字段类型
widgets = {
'desc': forms.Textarea,
'color': forms.RadioSelect,
}
...
...
五、项目颜色定制
5.1、forms.RadioSelect按钮插件源码分析
forms.RadioSelect
按钮源码
class RadioSelect(ChoiceWidget):
input_type = 'radio'
template_name = 'django/forms/widgets/radio.html'
option_template_name = 'django/forms/widgets/radio_option.html'
5.2、自定义form插件
- web_app/forms/widgets.py
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/forms/widgets.py
# -*- coding:utf-8 -*-
from django.forms import RadioSelect
class ColorRadioSelect(RadioSelect):
# template_name = 'django/forms/widgets/radio.html'
# option_template_name = 'django/forms/widgets/radio_option.html'
template_name = 'widgets/color_radio/radio.html'
option_template_name = 'widgets/color_radio/radio_option.html'
- web_app/templates/widgets/color_radio/radio.html
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/widgets/color_radio/radio.html
{% with id=widget.attrs.id %}
<div{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>
{% for group, options, index in widget.optgroups %}
{% for option in options %}
<label {% if option.attrs.id %} for="{{ option.attrs.id }}"{% endif %} >
{% include option.template_name with widget=option %}
</label>
{% endfor %}
{% endfor %}
</div>
{% endwith %}
- web_app/templates/widgets/color_radio/radio_option.html
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/widgets/color_radio/radio_option.html
{% include "django/forms/widgets/input.html" %}
<span class="cycle" style="background-color:{{ option.label }}"></span>
- from中使用自定义按钮插件
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/forms/project.py
# -*- coding:utf-8 -*-
from django import forms
from django.core.exceptions import ValidationError
from web_app.forms.bootstrap import BootStrapForm
from web_app import models
from web_app.forms.widgets import ColorRadioSelect
class ProjectModelForm(BootStrapForm, forms.ModelForm):
# 不使用BootStrapForm自动添加的样式的字段
bootstrap_class_exclude = ['color']
# desc = forms.CharField(widget=forms.Textarea(attrs={'xx': 123}))
class Meta:
model = models.Project
fields = ['name', 'color', 'desc']
# widgets 重写字段类型
widgets = {
'desc': forms.Textarea,
'color': ColorRadioSelect(attrs={'class': 'color-radio'})
}
...
...
向往的地方很远,喜欢的东西很贵,这就是我努力的目标。