资料清单model

This commit is contained in:
caoqianming 2021-03-11 09:42:16 +08:00
parent 3feb75dc6d
commit ad4e61fee3
20 changed files with 322 additions and 78 deletions

View File

@ -77,7 +77,7 @@ service.interceptors.response.use(
error => { error => {
// console.log(error,response) // for debug // console.log(error,response) // for debug
Message({ Message({
message: error.message, message: '服务器错误',
type: 'error', type: 'error',
duration: 5 * 1000 duration: 5 * 1000
}) })

View File

@ -13,7 +13,6 @@
v-loading="treeLoding" v-loading="treeLoding"
class="filter-tree" class="filter-tree"
:data="dictTypeData" :data="dictTypeData"
default-expand-all
highlight-current highlight-current
:expand-on-click-node="false" :expand-on-click-node="false"
:filter-node-method="filterNode" :filter-node-method="filterNode"
@ -46,31 +45,42 @@
<div slot="header" class="clearfix"> <div slot="header" class="clearfix">
<span>字典详情</span> <span>字典详情</span>
</div> </div>
<el-button v-show="listQuery.type" type="primary" icon="el-icon-plus" @click="handleAddDict" >新增</el-button> <div >
<el-button v-show="listQuery.type" type="primary" icon="el-icon-plus" @click="handleAddDict" v-if="checkPermission(['dic_create'])" size="small">新增</el-button>
</div>
<el-table <el-table
v-show="listQuery.type" v-show="listQuery.type"
v-loading="listLoading" v-loading="listLoading"
:data="dictList.results" :data="dictList"
style="width: 100%;margin-top:10px;" style="width: 100%;margin-top:10px;"
border border
fit fit
stripe stripe
highlight-current-row highlight-current-row
max-height="600" max-height="600"
row-key="id"
default-expand-all
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column align="center" label="名称">
<el-table-column label="名称">
<template slot-scope="scope">{{ scope.row.name }}</template> <template slot-scope="scope">{{ scope.row.name }}</template>
</el-table-column> </el-table-column>
<el-table-column align="header-center" label="描述"> <el-table-column label="代号/编号">
<template slot-scope="scope">{{ scope.row.code }}</template>
</el-table-column>
<el-table-column label="描述">
<template slot-scope="scope">{{ scope.row.desc }}</template> <template slot-scope="scope">{{ scope.row.desc }}</template>
</el-table-column> </el-table-column>
<el-table-column align="header-center" label="排序"> <el-table-column label="是否有效">
<template <template slot-scope="scope">
slot-scope="scope"
>{{ scope.row.sort }}</template> <el-tag type="success" v-if="scope.row.is_used">有效</el-tag>
<el-tag type="danger" v-else>无效</el-tag>
</template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="操作"> <el-table-column label="操作">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button
v-if="!scope.row.is_superuser" v-if="!scope.row.is_superuser"
@ -79,26 +89,27 @@
size="small" size="small"
icon="el-icon-edit" icon="el-icon-edit"
@click="handleEdit(scope)" @click="handleEdit(scope)"
/> />
<el-button <!-- <el-button
v-if="!scope.row.is_superuser" v-if="!scope.row.is_superuser"
:disabled="!checkPermission(['dict_delete'])" :disabled="!checkPermission(['dict_delete'])"
type="danger" type="danger"
size="small" size="small"
icon="el-icon-delete" icon="el-icon-delete"
@click="handleDelete(scope)" @click="handleDelete(scope)"
/> /> -->
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<p v-show="!listQuery.type">点击左侧类型查看字典</p> <p v-show="!listQuery.type">点击左侧类型查看字典</p>
<pagination <!-- <pagination
v-show="dictList.count>0" v-show="dictList.count>0"
:total="dictList.count" :total="dictList.count"
:page.sync="listQuery.page" :page.sync="listQuery.page"
:limit.sync="listQuery.page_size" :limit.sync="listQuery.page_size"
@pagination="getList" @pagination="getList"
/> /> -->
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
@ -115,24 +126,39 @@
<treeselect v-model="dicttype.pid" :multiple="false" :options="dictTypeData" placeholder="父级"/> <treeselect v-model="dicttype.pid" :multiple="false" :options="dictTypeData" placeholder="父级"/>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div style="text-align:right;"> <span slot="footer">
<el-button type="danger" @click="dgV1=false">取消</el-button> <el-button type="danger" @click="dgV1=false">取消</el-button>
<el-button type="primary" @click="confirm1('Form1')">确认</el-button> <el-button type="primary" @click="confirm1('Form1')">确认</el-button>
</div> </span>
</el-dialog> </el-dialog>
<el-dialog :visible.sync="dgV2" :title="dgT2==='edit'?'编辑字典':'新建字典'"> <el-dialog :visible.sync="dgV2" :title="dgT2==='edit'?'编辑字典':'新建字典'">
<el-form ref="Form2" :model="dict" label-width="80px" label-position="right" :rules="rule2"> <el-form ref="Form2" :model="dict" label-width="80px" label-position="right" :rules="rule2">
<el-form-item label="编号" prop="code">
<el-input v-model="dict.code" placeholder="编号" />
</el-form-item>
<el-form-item label="名称" prop="name"> <el-form-item label="名称" prop="name">
<el-input v-model="dict.name" placeholder="名称" /> <el-input type="textarea" v-model="dict.name" placeholder="名称" />
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="desc"> <el-form-item label="描述" prop="desc">
<el-input v-model="dict.desc" placeholder="描述" /> <el-input type="textarea" v-model="dict.desc" placeholder="描述" />
</el-form-item>
<el-form-item label="父级" prop="pid">
<treeselect v-model="dict.pid" :multiple="false" :options="dictList" placeholder="父级"/>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="dict.sort" :min="1" :max="999"></el-input-number>
</el-form-item>
<el-form-item label="是否有效" prop="is_used">
<el-switch
v-model="dict.is_used">
</el-switch>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div style="text-align:right;"> <span slot="footer">
<el-button type="danger" @click="dgV2=false">取消</el-button> <el-button type="danger" @click="dgV2=false">取消</el-button>
<el-button type="primary" @click="confirm2('Form2')">确认</el-button> <el-button type="primary" @click="confirm2('Form2')">确认</el-button>
</div> </span>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
@ -165,20 +191,20 @@ const defaultDict = {
name: '', name: '',
desc: '', desc: '',
sort: 1, sort: 1,
type: null type: null,
is_used: true,
pid:null
} }
export default { export default {
components: { Pagination, Treeselect }, components: { Pagination, Treeselect },
data() { data() {
return { return {
dicttype: defaultDictType, dicttype: Object.assign({}, defaultDictType),
dict: defaultDict, dict: Object.assign({}, defaultDict),
dictList: { count: 0 }, search:'',
dictList: [],
listLoading: true, listLoading: true,
listQuery: { listQuery: {},
page: 1,
page_size: 20
},
dgV1: false, dgV1: false,
dgT1: 'new', dgT1: 'new',
rule1: { rule1: {
@ -192,7 +218,7 @@ export default {
}, },
filterDictTypeText: '', filterDictTypeText: '',
treeLoding: false, treeLoding: false,
dictTypeData: [] dictTypeData: [],
} }
}, },
computed: {}, computed: {},
@ -202,7 +228,6 @@ export default {
} }
}, },
created() { created() {
this.getList()
this.getDictTypeList() this.getDictTypeList()
}, },
methods: { methods: {
@ -212,20 +237,15 @@ export default {
return data.label.indexOf(value) !== -1 return data.label.indexOf(value) !== -1
}, },
handleDictTypeClick(obj, node, vue) { handleDictTypeClick(obj, node, vue) {
this.listQuery.page = 1
this.listQuery.type = obj.id this.listQuery.type = obj.id
this.getList() this.getList()
}, },
getList() { getList() {
this.listLoading = true this.listLoading = true
getDictList(this.listQuery).then(response => { getDictList(this.listQuery).then(response =>{
if (response.code >= 200) { this.dictList = genTree(response.data)
if (response.data.results) { this.listLoading = false
this.dictList = response.data }).catch(error=>{this.listLoading = false})
}
this.listLoading = false
}
})
}, },
getDictTypeList() { getDictTypeList() {
this.treeLoding = true this.treeLoding = true
@ -259,8 +279,8 @@ export default {
this.$refs['Form2'].clearValidate() this.$refs['Form2'].clearValidate()
}) })
}, },
handleEditDictType(val) { handleEditDictType(data) {
this.dicttype = val // copy obj this.dicttype = Object.assign({}, data) // copy obj
this.dgT1 = 'edit' this.dgT1 = 'edit'
this.dgV1 = true this.dgV1 = true
this.$nextTick(() => { this.$nextTick(() => {
@ -277,7 +297,7 @@ export default {
.then(async() => { .then(async() => {
const { code } = await deleteDict(scope.row.id) const { code } = await deleteDict(scope.row.id)
if (code>=200){ if (code>=200){
this.dictList.results.splice(scope.row.index, 1) this.dictList.splice(scope.row.index, 1)
this.$message({ this.$message({
type: 'success', type: 'success',
message: '成功删除!' message: '成功删除!'
@ -294,30 +314,22 @@ export default {
const isEdit = this.dgT1 === 'edit' const isEdit = this.dgT1 === 'edit'
if (isEdit) { if (isEdit) {
updateDictType(this.dicttype.id, this.dicttype).then(res => { updateDictType(this.dicttype.id, this.dicttype).then(res => {
if (res.code >= 200) {
this.getDictTypeList() this.getDictTypeList()
this.dgV1 = false this.dgV1 = false
this.$notify({ this.$message({
title: '成功',
message: '编辑成功', message: '编辑成功',
type: 'success', type: 'success',
duration: 2000
}) })
} }).catch(error=>{})
})
} else { } else {
createDictType(this.dicttype).then(res => { createDictType(this.dicttype).then(res => {
if (res.code >= 200) {
this.getDictTypeList() this.getDictTypeList()
this.dgV1 = false this.dgV1 = false
this.$notify({ this.$message({
title: '成功',
message: '新增成功', message: '新增成功',
type: 'success', type: 'success',
duration: 2000
}) })
} }).catch(error=>{})
})
} }
} else { } else {
return false return false
@ -330,30 +342,22 @@ export default {
const isEdit = this.dgT2 === 'edit' const isEdit = this.dgT2 === 'edit'
if (isEdit) { if (isEdit) {
updateDict(this.dict.id, this.dict).then(res => { updateDict(this.dict.id, this.dict).then(res => {
if (res.code >= 200) {
this.getList() this.getList()
this.dgV2 = false this.dgV2 = false
this.$notify({ this.$message({
title: '成功',
message: '编辑成功', message: '编辑成功',
type: 'success', type: 'success',
duration: 2000
}) })
} }).catch(error=>{})
})
} else { } else {
createDict(this.dict).then(res => { createDict(this.dict).then(res => {
if (res.code >= 200) {
this.getList() this.getList()
this.dgV2 = false this.dgV2 = false
this.$notify({ this.$message({
title: '成功',
message: '新增成功', message: '新增成功',
type: 'success', type: 'success',
duration: 2000
}) })
} }).catch(error=>{})
})
} }
} else { } else {
return false return false

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class SupervisionConfig(AppConfig):
name = 'supervision'

View File

@ -0,0 +1,56 @@
# Generated by Django 3.0.5 on 2021-03-11 00:33
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('system', '0007_auto_20210311_0833'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Content',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('name', models.CharField(max_length=100, verbose_name='名称')),
('desc', models.CharField(max_length=1000, verbose_name='详情')),
('can_doself', models.BooleanField(default=False, verbose_name='可随时主动报送')),
('belong_to', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='content_belong_to', to='system.Organization', verbose_name='所属部门')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='content_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('type', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='system.Dict', verbose_name='材料类型')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='content_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'verbose_name': '报送清单',
'verbose_name_plural': '报送清单',
},
),
migrations.CreateModel(
name='Record',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('is_lock', models.BooleanField(default=False, verbose_name='是否锁住')),
('is_yes', models.BooleanField(default=True, verbose_name='是否适用')),
('note', models.TextField(verbose_name='说明')),
('content', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='supervision.Content', verbose_name='材料内容')),
],
options={
'verbose_name': '上报记录',
'verbose_name_plural': '上报记录',
},
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 3.0.5 on 2021-03-11 00:39
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('supervision', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='content',
name='belong_to',
),
]

View File

@ -0,0 +1,37 @@
from django.db import models
from utils.model import BaseModel
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict
# Create your models here.
class Content(CommonAModel):
"""
资料清单
"""
name = models.CharField('名称', max_length=100)
desc = models.CharField('详情', max_length=1000)
type = models.ForeignKey(Dict, verbose_name='材料类型', on_delete= models.DO_NOTHING)
can_doself = models.BooleanField('可随时主动报送', default=False)
class Meta:
verbose_name = '报送清单'
verbose_name_plural = verbose_name
# class Task(CommonBModel):
# name = models.CharField('名称', max_length=100)
# pass
class Record(BaseModel):
"""
上报记录
"""
content = models.ForeignKey(Content, verbose_name='材料内容', on_delete=models.DO_NOTHING)
# task = models.ForeignKey(Task, verbose_name='关联任务', null=True, blank=True, on_delete=models.SET_NULL)
is_lock = models.BooleanField('是否锁住', default=False)
is_yes = models.BooleanField('是否适用', default=True)
note = models.TextField('说明')
class Meta:
verbose_name = '上报记录'
verbose_name_plural = verbose_name

View File

@ -0,0 +1,21 @@
from rest_framework import serializers
from .models import *
from apps.system.serializers import OrganizationSerializer
class ContentSerializer(serializers.ModelSerializer):
type_ = serializers.SerializerMethodField()
class Meta:
model = Content
fields = '__all__'
@staticmethod
def setup_eager_loading(queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.select_related('type')
return queryset
def get_type_ (self, obj):
data = obj.type.name
if obj.type.pid:
data = obj.type.pid.name + '/' + data
return data

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,9 @@
from django.urls import path, include
from rest_framework import routers
from .views import ContentViewSet
router = routers.DefaultRouter()
router.register('content', ContentViewSet, basename="content")
urlpatterns = [
path('', include(router.urls))
]

View File

@ -0,0 +1,28 @@
from django.shortcuts import render
from rest_framework.mixins import ListModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from .models import *
from .serializers import *
from rest_framework.decorators import action
from django.conf import settings
from rest_framework import status
from rest_framework.response import Response
from apps.system.models import Organization
from openpyxl import Workbook, load_workbook
from django.db.models import Count
from utils.pagination import PageOrNot
from apps.system.mixins import CreateModelAMixin
# Create your views here.
class ContentViewSet(CreateModelAMixin, ModelViewSet):
"""
资料清单增删改查
"""
perms_map = {'get': '*', 'post': 'content_create',
'put': 'content_update', 'delete': 'content_delete'}
queryset = Content.objects.all()
serializer_class = ContentSerializer
search_fields = ['name', 'desc']
filterset_fields = ['type']
ordering = ['type__sort', 'create_time']

View File

@ -0,0 +1,25 @@
# Generated by Django 3.0.5 on 2021-03-11 00:33
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('system', '0006_auto_20201230_1730'),
]
operations = [
migrations.AlterField(
model_name='file',
name='create_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='file_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
),
migrations.AlterField(
model_name='file',
name='update_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='file_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.0.5 on 2021-03-11 01:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('system', '0007_auto_20210311_0833'),
]
operations = [
migrations.AddField(
model_name='dict',
name='is_used',
field=models.BooleanField(default=True, verbose_name='是否有效'),
),
migrations.AddField(
model_name='historicaldict',
name='is_used',
field=models.BooleanField(default=True, verbose_name='是否有效'),
),
]

View File

@ -155,6 +155,7 @@ class Dict(SoftModel):
sort = models.IntegerField('排序', default=1) sort = models.IntegerField('排序', default=1)
pid = models.ForeignKey('self', null=True, blank=True, pid = models.ForeignKey('self', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='') on_delete=models.SET_NULL, verbose_name='')
is_used = models.BooleanField('是否有效', default=True)
history = HistoricalRecords() history = HistoricalRecords()
class Meta: class Meta:
@ -170,9 +171,9 @@ class CommonAModel(SoftModel):
业务用基本表A,包含create_by, update_by字段 业务用基本表A,包含create_by, update_by字段
""" """
create_by = models.ForeignKey( create_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name='create_by') User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name='%(class)s_create_by')
update_by = models.ForeignKey( update_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name='update_by') User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name='%(class)s_update_by')
class Meta: class Meta:
abstract = True abstract = True
@ -182,11 +183,11 @@ class CommonBModel(SoftModel):
业务用基本表B,包含create_by, update_by, belong_to字段 业务用基本表B,包含create_by, update_by, belong_to字段
""" """
create_by = models.ForeignKey( create_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name='create_by') User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name='%(class)s_create_by')
update_by = models.ForeignKey( update_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name='update_by') User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name='%(class)s_update_by')
belong_to = models.ForeignKey( belong_to = models.ForeignKey(
Organization, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='所属部门', related_name='belong_to') Organization, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='所属部门', related_name='%(class)s_belong_to')
class Meta: class Meta:
abstract = True abstract = True

View File

@ -64,6 +64,9 @@ import datetime
class Login2View(APIView): class Login2View(APIView):
"""
邮箱验证码登录
"""
authentication_classes = [] authentication_classes = []
permission_classes = [] permission_classes = []
def post(self, request): def post(self, request):
@ -139,6 +142,16 @@ class DictViewSet(ModelViewSet):
search_fields = ['^name'] search_fields = ['^name']
ordering_fields = ['id'] ordering_fields = ['id']
ordering = 'id' ordering = 'id'
def paginate_queryset(self, queryset):
"""
如果查询参数里没有page但有type或type__code时则不分页,否则请求分页
也可用utils.pageornot方法
"""
if self.paginator is None:
return None
elif (not self.request.query_params.get('page', None)) and ((self.request.query_params.get('type__code', None)) or (self.request.query_params.get('type', None))):
return None
return self.paginator.paginate_queryset(queryset, self.request, view=self)
class PositionViewSet(ModelViewSet): class PositionViewSet(ModelViewSet):

Binary file not shown.

View File

@ -43,7 +43,8 @@ INSTALLED_APPS = [
"django_filters", "django_filters",
'apps.system', 'apps.system',
'apps.crm', 'apps.crm',
'apps.ability' 'apps.ability',
'apps.supervision'
] ]
MIDDLEWARE = [ MIDDLEWARE = [

View File

@ -58,16 +58,14 @@ class MyTokenObtainPairView(TokenViewBase):
urlpatterns = [ urlpatterns = [
path('', TemplateView.as_view(template_name="index.html")), path('', TemplateView.as_view(template_name="index.html")),
path('api/admin/', admin.site.urls), path('api/admin/', admin.site.urls),
path('api/login/', MyTokenObtainPairView.as_view(), name='my_login'),
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token2/', Login2View.as_view(), name='token_obtain_2'), path('api/token2/', Login2View.as_view(), name='token_obtain_2'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/token/black/', LogoutView.as_view(), name='token_black'), path('api/token/black/', LogoutView.as_view(), name='token_black'),
path('api/system/', include('apps.system.urls')), path('api/system/', include('apps.system.urls')),
path('api/ability/', include('apps.ability.urls')), path('api/ability/', include('apps.ability.urls')),
path('api/docs/', include_docs_urls(title="接口文档", path('api/supervision/', include('apps.supervision.urls')),
authentication_classes=[], permission_classes=[])), path('api/docs/', include_docs_urls(title="接口文档",authentication_classes=[], permission_classes=[])),
path('api/', include(router.urls)), path('api/', include(router.urls)),
url(r'^static/(?P<path>.*)$', serve, url(r'^static/(?P<path>.*)$', serve,{'document_root': settings.STATIC_ROOT}, name='static'),
{'document_root': settings.STATIC_ROOT}, name='static'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)