管理中心预计效果如下:
django写离线脚本
探讨业务
设计表结构
我的表结构
功能实现【任务】
- 查看项目列表
- 创建项目
- 星标项目
今日详细
1、django 离线脚本
- django ,框架
- 离线,非web运行时(运行时与django运行与否没有关系)
- 脚本,一个或者几个py文件
- 了解以上知识点后在某个py文件中对django项目做一些处理。
web运行时的含义:运行django程序运行起来就叫django运行时,即Web网站运行起来,对于视图文件的视图函数是通过浏览器中访问网站,django网站自动触发函数,函数被称为web在运行时被django调用的函数。
示例1:使用离线脚本在用户表插入数据(仅运行i脚本文件)
仅运行脚本文件时要特地往数据库添加数据:链接数据库、操作、关闭链接#而在django启动时,实际上是执行manage.py文件,在运行是会把所有的配置文件加载在项目中,。这时候就可以链接数据库并运行了,但离线脚本是不行的。在django中写离线脚本的程序如下:在init_user中:
import osimport sysimport djangobase_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 绝对路径,不断地往上一层找,从而找到它的根目录.sys.path.append(base_dir) # 将根目录写在sys.path下,在内部就导入s25下面的那个settingsos.environ.setdefault("DJANGO_SETTINGS_MODULE", "bugmanagment.settings") # 将bugmanagment.settings写入DJANGO_SETTINGS_MODULE环境变量中django.setup() # os.environ['DJANGO_SETTINGS_MODULE'] #模拟django的manage.py文件,进行模拟运行django启动,从而读到配置文件from app01 import models# 仅运行脚本文件时:往数据库添加数据:链接数据库、操作、关闭链接models.UserInfo.objects.create(username='陈硕', email='chengshuo@live.com', mobile_phone='13838383838', password='123123')
运行结果如下:(加入数据库里面的结果:
示例2:数据库录入全国省市县
示例3:朋友圈项目敏感字、词语
示例4:saas免费版(为所有人提供项目管理平台)【价格策略通过离线脚本添加进去)
注:大量数据要插入数据库中时可以利用一下django的离线脚本进行操作。
2. 探究业务( 表设计)
注:request.tracer = 交易对象
3
1、创建相应表结构:
知识点扩展:
加入related_name解决一张表关联着同一张表的ForeignKey的问题
class ProjectUser(models.Model):
# 项目参与者
user = models.ForeignKey(verbose_name='参与者', to='UserInfo', related_name='a', on_delete=models.CASCADE)
project = models.ForeignKey(verbose_name='项目', to='Project', on_delete=models.CASCADE)
star = models.BooleanField(verbose_name='星标', default=False)
invitee = models.ForeignKey(verbose_name='邀请者', to='UserInfo', related_name='b', on_delete=models.CASCADE)
create_datetime = models.DateTimeField(verbose_name='加入时间', auto_now_add=True)
obj = UserInfo.objects.filter(id=1) # 用户对象
obj.projectuser_set.all() #通过字段反向关联ProjectUser表,但是因为一张表关联着同一张的ForeignKey,则应该用下一个操作才能实现
obj.a.all()
#或者obj.b.all()
代码:
from django.db import models
class UserInfo(models.Model):
username = models.CharField(verbose_name='用户名', max_length=32, db_index=True) # db_index=True 创建索引
email = models.EmailField(verbose_name='邮箱', max_length=32)
mobile_phone = models.CharField(verbose_name='手机号', max_length=32)
password = models.CharField(verbose_name='密码', max_length=32)
# price_policy = models.ForeignKey(verbose_name="价格策略", to='PricePolicy', null=True, blank=True)
def __str__(self):
return self.username
class Meta:
db_table = "UserInfo"
verbose_name_plural = '用户表'
class PricePolicy(models.Model):
"""价格策略"""
category_choices = (
(1, '免费版'),
(2, '收费版'),
(3, '其他'),
)
category = models.SmallIntegerField(verbose_name='收费类型', default=1, choices=category_choices)
title = models.CharField(verbose_name='标题', max_length=32)
price = models.PositiveIntegerField(verbose_name='价格') # 存正整数
project_num = models.PositiveIntegerField(verbose_name='项目数')
project_member = models.PositiveIntegerField(verbose_name='项目成员数')
project_space = models.PositiveIntegerField(verbose_name='单项目空间')
per_file_size = models.PositiveIntegerField(verbose_name='单文件大小')
create_datetime = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
class Transaction(models.Model):
# 交易记录
status_choice = (
(1, '未支付'),
(2, '已支付')
)
status = models.SmallIntegerField(verbose_name='状态', choices=status_choice)
order = models.CharField(verbose_name='订单号', max_length=64, unique=True) # 唯一索引
user = models.ForeignKey(verbose_name='用户', to='UserInfo', on_delete=models.CASCADE)
price_policy = models.ForeignKey(verbose_name='价格策略', to='PricePolicy', on_delete=models.CASCADE)
count = models.IntegerField(verbose_name='数量(年)', help_text='0表示无限期')
price = models.IntegerField(verbose_name='实际支付价格')
start_datetime = models.DateTimeField(verbose_name='开始时间', null=True, blank=True)
end_datetime = models.DateTimeField(verbose_name='结束时间', null=True, blank=True) # 为空代表无限期
create_datetime = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
class Project(models.Model):
"""项目表"""
COLOR_CHOICES = (
(1, "#56b8eb"),
(2, "#f28033"),
(3, "#ebc656"),
(4, "#a2d148"),
(5, "#20BFA4"),
(6, "#7461c2"),
(7, "#20bfa3"),
)
name = models.CharField(verbose_name='项目名', max_length=32)
color = models.SmallIntegerField(verbose_name='颜色', choices=COLOR_CHOICES, default=1)
desc = models.CharField(verbose_name='项目描述', max_length=255, null=True, blank=True)
use_space = models.IntegerField(verbose_name='项目已使用空间', default=0)
star = models.BooleanField(verbose_name='星标', default=False)
join_count = models.SmallIntegerField(verbose_name='参与人数', default=1)
creator = models.ForeignKey(verbose_name='创建者', to='UserInfo', on_delete=models.CASCADE)
create_datetime = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
# 查询:可以省事;(根据project_user字段进行查询)
# 增加、删除、修改、无法完成
project_user = models.ManyToManyField(to='UserInfo', through="ProjectUser",
through_fields=('project', 'user')) # 定义多对多字段
class ProjectUser(models.Model):
# 项目参与者
project = models.ForeignKey(verbose_name='项目', to='Project', on_delete=models.CASCADE)
user = models.ForeignKey(verbose_name='参与者', to='UserInfo', on_delete=models.CASCADE)
star = models.BooleanField(verbose_name='星标', default=False)
create_datetime = models.DateTimeField(verbose_name='加入时间', auto_now_add=True)
2、离线脚本
scripts.py专门放脚本文件。
在base.py中:
离线脚本的模版
import django
import os
import sys
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_dir)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bugmanagment.settings")
django.setup() # os.environ['DJANGO_SETTINGS_MODULE']
在init_price_policy中:
初始化价格策略
import base # 调用base
from app01 import models
def run():
exists = models.PricePolicy.objects.filter(category=1, title="个人免费版").exists()
if not exists:
models.PricePolicy.objects.create(
category=1,
title="个人免费版",
price=0,
project_num=3,
project_member=2,
project_space=20,
per_file_size=5
)
if __name__ == '__main__':
run()
3、用户注册【对前面的代码进行修改】
- 以前:创建用户
- 现在:用户&交易记录(获得免费版的额度)
def register(request):
# 注册
if request.method == 'GET':
form = RegisterModelForm()
return render(request, 'web/register.html', {'form': form})
# print(request.POST) # 后台拿到的数据,传到ModelForm进行校验
form = RegisterModelForm(data=request.POST)
if form.is_valid():
# 验证通过后,写入数据库(密码要是密文)
# instance = form.save,在数据库中新增一条数据,并将新增的这条数据赋值给instance,指的是当前我们添加的这条数据的用户对象
# 相当于models.UserInfo.objects.filter(id=1).first()
# 用户表中新建一条数据(注册)
# form.instance.password ="iudasndfiajsd;fj" #在保存之前将instance中的password进行重置
instance = form.save() # 自动剔除数据库中没有的字段
# 创建交易记录
policy_object = models.PricePolicy.objects.filter(category=1, title="个人免费版").first() #通过离线脚本添加的数据,取到价格策略的对象
models.Transaction.objects.create(
status=2,
order=str(uuid.uuid4()),
user=instance,
price_policy=policy_object,
count=0,
price=0,
start_datetime=datetime.datetime.now() #开始时间为当前时间
)
return JsonResponse({'status': True, 'data': '/web/login/'})
return JsonResponse({'status': False, 'error': form.errors})
4、添加项目
4.1 项目列表母版+样式
- 后台:登录成功之后才可以访问
- 官网:都可以访问
- 通过中间件+白名单 对后台管理的权限进行处理
- 当前的拥有的价格策略【额度】
模态对话框要用ajax请求,而不能用form表单提交。
所有代码:
在母版manage.html中:
{#管理中心模版#} {% load static %} "en"> "UTF-8">{% block title %}{% endblock %} "stylesheet" href="{% static 'plugin/bootstrap/css/bootstrap.min.css' %}"> "stylesheet" href="{% static 'plugin/font-awesome/css/font-awesome.min.css' %}"> {% block css %} {% endblock %} {% block content %} {% endblock %} {% block js %} {% endblock %}
在project_list中:
{% extends 'layout/manage.html' %} {% block css %} {% endblock %} {% block content %}class="container-fluid project"> class="btn btn-primary" data-toggle="modal" data-target="#addModal"> class="fa fa-plus-circle" aria-hidden="true"> 新建项目class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">{% endblock %} {% block js %} {% endblock %}class="modal-dialog" role="document">class="modal-content">class="modal-header">class="modal-title" id="myModalLabel"> 新建项目
class="modal-body">class="modal-footer">
在views\project.py中:
from django.shortcuts import render
from app01 import models
from web.forms.project import ProjectModelForm
from django.http import JsonResponse
def project_list(request):
"""项目列表"""
# print(request.transaction.user)
# print(request.transaction.price_policy.project_num)
if request.method == "GET":
return render(request, 'web/project_list.html', {'form': form})
# POST.对话框的ajax添加项目.
form = ProjectModelForm(request, data=request.POST) # 接收到请求(前端是用POST请求),进行表单验证
if form.is_valid():
# 验证通过:项目名、颜色、描述+creator谁创建的项目? 其他的内容,项目表中已经有默认值了
form.instance.creator = request.tracer.user # 当前登录的用户对象
# 创建项目
form.save() # 在保存之前要让models.py项目表中的字段都有值
return JsonResponse({'status': True})
return JsonResponse({'status': False, 'error': form.errors}) # 校验失败,返回错误信息
在forms\project.py中
from django import forms
from app01 import models
from web.forms.bootstrap import BootStrapForm
from django.core.exceptions import ValidationError
class ProjectModelForm(BootStrapForm, forms.ModelForm):
# desc = forms.CharField(widget=forms.Textarea())
class Meta:
model = models.Project
fields = ['name', 'color', 'desc']
widgets = {
'desc': forms.Textarea
}
#ModelForm里没有request,要重写init方法,在接口传一个request进来
def __init__(self, request, *args, **kwargs):
super().__init__(*args, **kwargs)
self.request = request
def clean_name(self):
"""项目校验"""
name = self.cleaned_data['name']
# 1.当前用户(self.request.tracer.user)是否已创建过此类项目(项目名不能重复)?
# 1.1 所有人是否已创建过这个项目
# exists = models.Project.objects.filter(name=name).exists()
# self.request.tracer.user
exists = models.Project.objects.filter(name=name, creator=self.request.tracer.user).exists()
if exists:
raise ValidationError("项目名已存在")
# 2.当前用户是否还有额度进行创建项目?
# 最多创建N个项目
# 项目额度(self.request.tracer.price_policy.project_num)
# 现在已创建多少项目?
count = models.Project.objects.filter(creator=self.request.tracer.user).count()
if count >=self.request.tracer.price_policy.project_num:
raise ValidationError('项目个数超限,请购买套餐')
return name
内容概要:
- 展示项目
- 星标项目
- 添加项目:颜色选择
- 项目切换&颜色选择
- 项目切换&项目管理菜单处置
- *wiki管理
1、展示项目:
1.1数据
1、从数据库中获取两部分数据
我创建的所有项目:含有已星标,未星标项目
我参与的所有项目:含有已星标,未星标项目
2、提取已星标项目
列表 = 循环 【我创建的所有项目】+【我参与的所有项目】把已星标的数据提取
3、页面渲染循环三组数据进行页面展示。
得到三个列表 : 星标、创建、参与
2、星标项目(去除星标)
2.1星标
我创建的项目:表中Project的star=True
我参与的项目:表中ProjectUser的star=True
2.2移除星标
我创建的项目:表中Project的star=False 我参与的项目:表中ProjectUser的star=False
3.选择颜色
颜色的选择将表中choice默认生成的select标签改成radio标签.
3.1、部分样式应用BootStrap
面向对象的继承,在form和ModelForm中进行样式的设置
class BootStrapForm(object):
bootstrap_class_exclude = [] # 支持某个字段不加样式
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items(): # 循环字段进行样式的设置
if name in self.bootstrap_class_exclude: # 不运用bootstrap样式
continue
field.widget.attrs['class'] = 'form-control'
field.widget.attrs['placeholder'] = '请输入%s' % (field.label,)
class ProjectModelForm(BootStrapForm, forms.ModelForm):
bootstrap_class_exclude = ['color'] # 走BootStrapForm中的init方法,把颜色的样式排除掉,此为不走BootStrapForm样式的方法
class Meta:
model = models.Project
fields ="_all_"
3.2定制ModelForm的插件(不用django默认提供的插件,不来自django的forms中)
class ProjectModelForm(BootStrapForm, forms.ModelForm):
class Meta:
model = models.Project
fields = "_all_"
widgets = {
'desc': forms.Textarea,
'color': ColorRadioSelect(attrs={'class': 'color-radio'})
}
注:’desc’利用的是默认的插件,color用的是自定义的插件。
from django.forms import RadioSelect
class ColorRadioSelect(RadioSelect):
template_name = 'widgets/color_radio/radio.html'
option_template_name = 'widgets/color_radio/radio_option.html'
自定义样式:在radio.html中:
{% with id=widget.attrs.id %}
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 %}
if option.attrs.id %} for="{{ option.attrs.id }}"{% endif %}>
{% include option.template_name with widget=option %}
{% endfor %}
{% endfor %}
{% endwith %}
在radio_option.html中:
{% include 'django/forms/widgets/input.html' %}
class="cycle" style="background-color: {{ option.label }}">
3.3项目选择颜色
- 就是3.1、3.2的关于知识点的应用+前端样式的编写
4、切换菜单
1.数据库中获取
我创建的:
我参与的:
2.循环显示
3.当前页面需要显示/其他页面也需要显示【模版中自定义的方法——inclusion_tag】
代码如下 :
在templatetags\project.py中:
from django.template import Library
from app01 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.tracer.user)
# 2.获取我参与的所有项目
join_project_list = models.ProjectUser.objects.filter(user=request.tracer.user)
# return {'my': [], 'join': []} #返回一个这样的字典.
return {'my': my_project_list, 'join': join_project_list}
运用all_project_list这个inclusion_tag后,返回模版
在all_project_list.html中
class="nav navbar-nav">
class="dropdown active">
"#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">项目 class="caret">
class="dropdown-menu">
{# my有值才展示#}
{% if my %}
class="fa fa-list" aria-hidden="true">我创建的项目
{% for item in my %}
"#">{{ item.name }}
{% endfor %}
"separator" class="divider">
{% endif %}
{% if join %}
class="fa fa-handshake-o" aria-hidden="true">我参与的项目
{% for item in join %}
"#">{{ item.project.name }}
{% endfor %}
"separator" class="divider">
{% endif %}
"{% url 'project_list' %}">所有项目
在母版manage.html中:插入两行代码即可
{% all_project_list request %}
{#调用inclusion_tag的时候记得要传入参数request#}
5.项目管理
写上它的多个功能以及他的路由url:
/manage/项目ID/dashboard
/manage/项目ID/issues
/manage/项目ID/statistics
/manage/项目ID/file
/manage/项目ID/wiki
/manage/项目ID/setting
5.1 进入项目展示菜单
- 进入项目
- 展示菜单
5.1.1 是否进入项目?【访问url前通过访问中间件进行判断】
- 判断URL是否以manage开头 [以它开头的就是进入了]
- project_id是我创建or我参与的 (否则进入的很可能是别人的项目或者进不去)
5.1.2 显示菜单
依赖:是否已经进入项目?(即request.tracer.project有值表明进入了项目)
class="nav navbar-nav">
"#">产品功能
"#">企业方案
"#">帮助文档
"#">价格
5.1.3 修复bug
5.1.4 默认选中菜单
总结
- 项目实现思路
- 星标/取消星标
- inclusion_tag实现项目切换
- 项目菜单
- 中间件 process_view
- 点击后默认选中菜单:基于inclusion_tag选中
- 路由分发
- include(”xxx.url”)
- include([ssfdsds,sdf]) #列表,找对应关系
- 颜色选择:源码+扩展【实现】 (了解即可) 其他的方法例如 :通过下拉框,或者通通过页面自己循环写input框
Original: https://www.cnblogs.com/zhouhuimin99/p/16673386.html
Author: 费皿啊
Title: 轻量级bug管理平台——管理中心
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/603860/
转载文章受原作者版权保护。转载请注明原作者出处!