前期准备

需求文档

利用脑图简单绘制一下业务功能

整体需求的功能

数据库表设计

用PowerDesigner简单先设计一下需要用到的表(因为后端我用的是Django,所以不要把所有的表都设计一遍,只要简单把业务层的表设计一下即可)

在这里插入图片描述

功能设计

运动员:填写注册信息 => 登录 => 填写报名表
普通用户:无需注册 => 查询赛事 、 运动员信息 、投诉
记录组:录入成绩、 添加决赛名单、 发布成绩
宣传组:发布新闻、 投诉管理

移动web应用原型图

等待添加

接口文档

运动员登录

协议:http(s)
请求方式:POST
请求地址:http://localhost:8000/login
说明:运动员登录验证接口

请求参数是否必须类型说明
usernameString学号
passwordSrring密码

登录成功返回:

{
	"msg":"操作成功",
	"data":{
		"uname":"你登录的用户名",
		"pwd":"你登录的密码",
		"uid":"运动员id"
	},
	"code":1
}

返回说明:

返回参数类型说明
msgString返回信息
dataJson登录的学号、密码和用户id
codeint登录状态:1成功,0失败

运动员的赛事查询

协议:http(s)
请求方式:POST
请求地址:http://localhost:8000/player
说明:根据username查询运动员赛事接口

请求参数是否必须类型说明
usernameString学号

查询成功返回:

{
	"msg":"操作成功",
	"code":1,
	"data":[
	    {
	        "gameid": 1,
	        "game": "【男子】100米预赛",
	        "finall_gameid":2,
			"finall_game":"【男子】100米(决赛)",
	        "uid": 1,
	        "name": "周星驰""institution": "体育学院"
	    }
	
	]
}

返回说明:

返回参数类型说明
msgString返回信息
codeint注册状态:1成功,0失败

运动员注册

协议:http(s)
请求方式:POST
请求地址:http://localhost:8000/register
说明:运动员注册接口

请求参数是否必须类型说明
usernameString学号
passwordString密码
nameString姓名
genderint性别(男1 女0)
institutionidint学院id

注册成功返回:

{
	"msg":"操作成功",
	"code":1
}

返回说明:

返回参数类型说明
msgString返回信息
codeint注册状态:1成功,0失败

学院名查询

协议:http(s)
请求方式:GET
请求地址:http://localhost:8000/institutions
说明:id查询学院名接口

请求参数是否必须类型说明
idint通过学院id查询(如果为空,则返回所有学院)

查询返回:

{
	"msg":"操作成功",
	"code":1,
	"data":[
		{
			"id":1,
			"name":"体育学院"
		}
	]
}

返回说明:

返回参数类型说明
msgString返回信息
codeint注册状态:1成功,0失败
dataList列表:学院的id和名字

比赛查询

协议:http(s)
请求方式:GET
请求地址:http://localhost:8000/games
说明:id查询比赛信息接口

请求参数是否必须类型说明
idint通过比赛id查询(如果为空,则返回所有比赛)

查询返回:

{
	"msg":"操作成功",
	"code":1,
	"data":[
		{
			"id":1,
			"name":"【男子】100米(初赛)",
			"type":"田赛",
			"game_type":1,
			"gender":1,
			"unit":"秒",
			"data":"",
			"status":1,
			"start_time":"2020-01-01 12:48:00",
			"end_time":"2020-01-01 12:48:00"
		}
	]
}

返回说明:

返回参数类型说明
msgString返回信息
codeint注册状态:1成功,0失败
dataList列表:比赛名称、赛事分类 (田赛、径赛、团体赛)、初决赛(初赛:1,决赛2)、性别、成绩单位、信息、比赛状态(准备中:0,检录:1,结束2)、开始时间、结束时间

报名表查询

协议:http(s)
请求方式:GET
请求地址:http://localhost:8000/enroll
说明:id查询报名表接口

请求参数是否必须类型说明
playeridint通过运动员id查询(如果为空,则返回所有报名表)

查询返回:

{
	"msg":"操作成功",
	"code":1,
	"data":[
		{
			"id":1,
			"name":"姓名",
			"institution":"体育学院",
			"game_name":"比赛名",
			"gender":1"gameid":2,
		}
	]
}

返回说明:

返回参数类型说明
msgString返回信息
codeint注册状态:1成功,0失败
dataList列表:报名id、用户姓名、所属学院、比赛名、性别、比赛id

投诉申请

协议:http(s)
请求方式:POST
请求地址:http://localhost:8000/complain
说明:申请投诉

请求参数是否必须类型说明
contactString联系方式
contentString投诉内容

查询返回:

{
	"msg":"操作成功",
	"code":1,
}

返回说明:

返回参数类型说明
msgString返回信息
codeint注册状态:1成功,0失败

新闻发布

协议:http(s)
请求方式:POST
请求地址:http://localhost:8000/news
说明:创建新闻

请求参数是否必须类型说明
titleString标题
contentString新闻内容(Markdown语法)

查询返回:

{
	"msg":"操作成功",
	"code":1,
}

返回说明:

返回参数类型说明
msgString返回信息
codeint注册状态:1成功,0失败

新闻查询

协议:http(s)
请求方式:GET
请求地址:http://localhost:8000/news
说明:id查询新闻

请求参数是否必须类型说明
idint新闻id(如果为空则返回所有新闻内容)

查询返回:

{
	"msg":"操作成功",
	"code":1,
	"data":[
		{
			"id":1,
			"title":"新闻标题",
			"content":"Markdown语法的正文内容",
			"create_time":"2021-01-01 12:20:00"
		}
	]
}

返回说明:

返回参数类型说明
msgString返回信息
codeint注册状态:1成功,0失败
dataList新闻的id、内容、创建时间

环境搭建

前端:创建VUE3脚手架项目

准备环境:

搭建项目:

  • 安装Vue-Cli 3
npm install -g @vue/cli
  • 创建vue项目
vue create 项目名
  • 选择配置(我选自定义)

Manually select features

选择:
Router
Vuex
Babel

最后:
Chose Vue version
3.x
历史路由:y
选择In package.json
是否保存配置:n(也可以选择y保存)

  • 进入目录测试项目启动
npm run serve
  • 用IDEA打开项目
    • 添加npm配置

命令:run
脚本:serve

    • 配置 package.json设置自动打开浏览器

serve 命令后面加上 --open

  • 配置ElementUI-Plus
    • 安装
npm install element-plus --save
    • 在main.js中引入Element-Plus
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementPlus from 'element-plus';
import 'element-plus/lib/theme-chalk/index.css';
import 'dayjs/locale/zh-cn'
import lang from 'element-plus/lib/locale/lang/zh-cn'

createApp(App).use(store).use(router).use(ElementPlus).mount('#app')


后端:创建Django3项目

准备环境:

  • SimpleUI后台管理 =>官方文档
  • 导入导出模块django-import-export

搭建项目:

  • 安装Django
pip install django
  • 创建项目(可用Pycharm直接创建)
django-admin startproject 项目名
  • 创建应用(Pycharm可自动创建)
python manage.py startapp App名
  • 安装导入导出神器django-import-export

知乎传送门

官方文档

pip install django-import-export

在setting.py的INSTALLED_APPS里添加

# settings.py
INSTALLED_APPS = (
    ...
    'import_export',
)
  • 安装simpleUI
 pip install django-simpleui
  • 在settings.py的INSTALLED_APPS添加App
    修改settings.py, 将simpleui和创建的App加入到INSTALLED_APPS里去,放在第一行,也就是django自带admin的前面。
 INSTALLED_APPS = [
       'simpleui', # 注意这里
       'django.contrib.admin',
       'django.contrib.auth',
       'django.contrib.contenttypes',
       'django.contrib.sessions',
       'django.contrib.messages',
       'django.contrib.staticfiles',
       ...     
 ]
    • 设置语言, 去Logo和管理后台名字
      修改settings.py, 添加如下代码:
 # 更改默认语言为中文
LANGUAGE_CODE = 'zh-hans'

# 更改地区时间
TIME_ZONE = 'Asia/Shanghai'


# 去掉默认Logo或换成自己Logo链接
SIMPLEUI_LOGO = 'https://th.bing.com/th/id/R2411a2b340731d67dfa0d84503e915e3?rik=zmYce%2fLys72JVQ&pid=ImgRaw'
  • 在App目录下新建一个admin.py
 # tasks/admin.py
from django.contrib import admin

admin.site.site_header = '大江狗管理后台'  # 设置header
admin.site.site_title = '大江狗管理后台'   # 设置title
admin.site.index_title = '大江狗管理后台'

from .models import Task
admin.site.register(Task)
  • 关闭Csrf验证

由于我们需要开发POST接口,Django框架当中封装了防跨站攻击的验证,但是我们仅仅只要一个简单的POST接口,所以先关闭Csrf验证。打开setting.py找到MIDDLEWARE并把’django.middleware.csrf.CsrfViewMiddleware’注释

MIDDLEWARE = [
   '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的配置引用了大江狗的文章

代码编写

前端

后端

  • 模型设计:

根据数据库设计的表,编写App目录下的models.py

from django.db import models


# Create your models here.
class Institution(models.Model):
    # id = models.IntegerField(verbose_name='学院id', primary_key=True, auto_created=True)
    name = models.CharField(verbose_name='学院名称', max_length=255, null=False)
    data = models.CharField(verbose_name='学院信息', max_length=255, null=True, blank=True)

    class Meta:
        verbose_name_plural = '学院表'

    def __str__(self):
        return self.name


class Player(models.Model):
    gender_chices = ((0, '女'), (1, '男'), (2, '未知'))

    # id = models.IntegerField(verbose_name='运动员id', primary_key=True)
    username = models.CharField(verbose_name='学号', max_length=7, null=False)
    password = models.CharField(verbose_name='密码', max_length=255, null=False)
    name = models.CharField(verbose_name='姓名', max_length=255, null=False)
    gender = models.IntegerField(verbose_name='性别', choices=gender_chices, null=False)
    institution = models.ForeignKey(Institution, null=True, on_delete=models.SET_NULL, verbose_name='学院名')
    data = models.CharField(verbose_name='数据 ', max_length=255, null=True, blank=True)
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)

    class Meta:
        verbose_name_plural = '运动员表'

    def __str__(self):
        return self.name


class Game(models.Model):
    gender_chices = ((0, '女'), (1, '男'), (2, '未知'))
    status_chices = ((0, '未开始'), (1, '检录'), (2, '结束'))

    # id = models.IntegerField(verbose_name='赛事id', primary_key=True)
    name = models.CharField(verbose_name='赛事名称', max_length=255, null=False)
    type = models.CharField(verbose_name='赛事类型', max_length=255, null=False)
    gender = models.IntegerField(verbose_name='性别', choices=gender_chices, null=False)
    unit = models.CharField(verbose_name='成绩单位', max_length=255, null=False)
    status = models.IntegerField(verbose_name='状态', choices=status_chices, null=False)
    start_time = models.DateTimeField(verbose_name='开始时间')
    end_time = models.DateTimeField(verbose_name='结束时间')
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    data = models.CharField(verbose_name='信息', max_length=255, null=True, blank=True)

    class Meta:
        verbose_name_plural = '赛事表'

    def __str__(self):
        return "【" + self.get_gender_display() + "子】" + self.name


class enroll(models.Model):
    # id = models.IntegerField(verbose_name='报名表id', primary_key=True)
    player = models.ForeignKey(Player, null=True, on_delete=models.SET_NULL, verbose_name='运动员')
    game = models.ForeignKey(Game, null=True, on_delete=models.SET_NULL, verbose_name='比赛')
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)

    class Meta:
        verbose_name_plural = '报名表'

    def __str__(self):
        return self.player.name + " 报名了: " + "【" + self.game.get_gender_display() + "子】" + self.game.name


class Score(models.Model):
    # id = models.IntegerField(verbose_name='成绩表id', primary_key=True)
    player = models.ForeignKey(Player, null=True, on_delete=models.SET_NULL, verbose_name='运动员')
    game = models.ForeignKey(Game, null=True, on_delete=models.SET_NULL, verbose_name='比赛')
    score = models.FloatField(verbose_name='成绩', null=True)
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)

    class Meta:
        verbose_name_plural = '成绩表'

    def __str__(self):
        return self.player.name + " 在" + \
               "【" + self.game.get_gender_display() + \
               "子】" + self.game.name + " 比赛中取得:" + str(self.score) + self.game.unit + "的成绩"
  • models.py编写class时的要点:
序号关键字要点
1id定义模型时,models会对每个模型自动添加一个主键,因此可以不需要再添加一个id字段,因为如果添加了,对应的Admin添加数据时要输入id
2__str__在模型中重写__str__相当于Java中的重写toString,可以解决外键关联时返回成对象的问题,__str__可以自定义返回内容
3null=True数据库级别可以为空,False反之(需要修改表结构)
4blank=Trueadmin级别可以为空、False反之(只需要修改model)
5Metadb_table自定义表名,verbose_name指定在admin管理界面中显示中文;verbose_name表示单数形式的显示,verbose_name_plural表示复数形式的显示;中文的单数和复数一般不作区别。
6choices对应字段值的映射(元组映射)
  • 在admin.py中注册models
from django.contrib import admin
from .models import *

# Register your models here.

admin.site.site_header = '大江狗管理后台'  # 设置header
admin.site.site_title = '大江狗管理后台'  # 设置title
admin.site.index_title = '大江狗管理后台'


class InstitutionAdmin(admin.ModelAdmin):
    list_display = ('name', 'data')


class PlayerAdmin(admin.ModelAdmin):
    list_display = ('username', 'name', 'gender', 'institution')
    search_fields = ('username', 'name')
    list_filter = ('gender', 'institution')


class GameAdmin(admin.ModelAdmin):
    list_display = ('type', 'gender', 'name', 'status', 'start_time', 'end_time')
    list_filter = ('type', 'gender', 'status', 'start_time', 'end_time')
    search_fields = ['name']
    list_editable= ['status', 'end_time']


class enrollAdmin(admin.ModelAdmin):
    list_display = ('gametype', 'username', 'player', 'gender', 'game', 'institution', 'create_time')
    list_filter = ['game__type', 'player__gender', 'game', 'player__institution', 'create_time']
    search_fields = ['player__name', 'player__username']

    def gametype(self, obj):
        """
        写方法查询比赛类型
        :param obj:
        :return game_type:
        """
        return obj.game.type

    def username(self, obj):
        """
        写方法查询运动员学号
        :param obj:
        :return game_type:
        """
        return obj.player.username

    def institution(self, obj):
        """
        写方法查询学院名称
        :param obj:
        :return instution_name:
        """
        return obj.player.institution.name

    def gender(self, obj):
        """
        写方法查询运动员性别
        :param obj:
        :return player_gender:
        """
        return obj.player.get_gender_display()


class ScoreAdmin(admin.ModelAdmin):
    list_display = ('gametype', 'username', 'player', 'institution', 'game', 'score', 'unit', 'create_time')
    search_fields = ['player__name', 'player__username']
    list_filter = ['game__type', 'player__gender', 'game', 'player__institution', 'create_time']

    def username(self, obj):
        """
        写方法查询运动员学号
        :param obj:
        :return game_type:
        """
        return obj.player.username

    def unit(self, obj):
        return obj.game.unit

    def institution(self, obj):
        """
        写方法查询学院名称
        :param obj:
        :return instution_name:
        """
        return obj.player.institution.name

    def gametype(self, obj):
        """
        写方法查询比赛类型
        :param obj:
        :return game_type:
        """
        return obj.game.type


class NewsAdmin(admin.ModelAdmin):
    list_display = ('title', 'content', 'create_time')
    search_fields = ('title', 'content')
    list_filter = ('create_time',)
    list_editable = ('content', )


class ComplaintAdmin(admin.ModelAdmin):
    search_fields = ('contact', 'content')
    list_display = ('contact', 'content', 'create_time')


admin.site.register(Institution, InstitutionAdmin)
admin.site.register(Player, PlayerAdmin)
admin.site.register(Game, GameAdmin)
admin.site.register(enroll, enrollAdmin)
admin.site.register(Score, ScoreAdmin)

admin.site.register(News, NewsAdmin)
admin.site.register(Complaint, ComplaintAdmin)


添加admin.ModelAdmin子类装饰器到原模型:

关键字说明
list_display显示的字段
search_fields搜索字段
list_filter过滤字段(过滤外键时,添加的列表元素格式为:外键名__字段名, 多级外键过滤:外键名__外键表的外键字段__字段名…)
date_hierarchy顶部添加逐层深入的导航条
ordering设置模块界面显示的排序顺序
fields表示编辑表单界面各字段的顺序,也可以少些一些,用来屏蔽不让用户改的字段。(即:按顺序显示什么字段)
filter_horizontal和admin中给予权限选择一样的多选移动框
filter_vertical与filter_horizontal一样,只不过是垂直显示的。
raw_id_fields显示外键详细信息
list_editable设置字段可以页面修改
  • 在views.py中写入api
from django.shortcuts import render
from django.http import HttpResponse
import datetime
import json

from sportmeeting.models import *


class api:
    def __init__(self, data):
        """
        初始化data
        :param data: List或Dict 数据库数据
        """
        self.data = data

    def success(self):
        """
        成功返回的json
        :return: String 编码后的json字符串
        """
        return HttpResponse(json.dumps(
            {
                'msg': '操作成功',
                'code': 1,
                'data': self.data
            }
        ),
            content_type="application/json"
        )

    def error(self):
        """
        错误返回的json
        :return:
        """
        return HttpResponse(json.dumps(
            {
                'msg': '非法操作',
                'code': 0,
                'data': self.data
            }
        ),
            content_type="application/json"
        )


def current_datetime():
    return str(datetime.datetime.now())[:-7]


# Create your views here.

def login(request):
    if request.method == 'POST':
        try:
            json_data = json.loads(request.body)
            username = json_data['username']
            password = json_data['password']
        except:
            return api({'msg': 'json格式不正确'}).error()

        try:
            user = Player.objects.get(username=username)
            if user.password == password:
                return api({'uname': user.username, 'pwd': user.password, 'uid': user.id}).success()
            else:
                return api('密码错误').error()

        except Exception as e:
            return api('账号未注册').error()

    return api('must be post').error()


def register(request):
    if request.method == 'POST':
        try:
            json_data = json.loads(request.body)
            username = json_data['username']
            password = json_data['password']
            name = json_data['name']
            gender = json_data['gender']
            institutionid = json_data['institutionid']
        except:
            return api({'msg': 'json格式不正确'}).error()

        if Player.objects.filter(username=username).exists():
            return api('账号已存在').error()
        else:
            try:
                Player.objects.create(
                    username=username,
                    password=password,
                    name=name,
                    gender=gender,
                    institution_id=institutionid
                )
                return api('注册成功').success()
            except Exception as e:
                return api(e).error()


def institutions(request):
    if request.method == 'GET':
        ins_id = request.GET.get('id', '')
        if ins_id == '':
            ins = Institution.objects.all()
            datalist = []
            for item in ins:
                datalist.append({'id': item.id, 'name': item.name})
            return api(datalist).success()
        else:
            ins = Institution.objects.filter(id=ins_id)
            datalist = []
            for item in ins:
                datalist.append({'id': item.id, 'name': item.name})
            return api(datalist).success()


def games(request):
    if request.method == 'GET':
        game_id = request.GET.get('id', '')
        if game_id == '':
            ins = Game.objects.all()
            datalist = []
            for item in ins:
                datalist.append(
                    {'id': item.id,
                     'name': item.name,
                     'type': item.type,
                     'gender': item.gender,
                     'unit': item.unit,
                     'data': item.data,
                     'status': item.status,
                     'start_time': str(item.start_time)[:-6],
                     'end_time': str(item.end_time)[:-6]
                     }
                )
            return api(datalist).success()
        else:
            ins = Game.objects.filter(id=game_id)
            datalist = []
            for item in ins:
                datalist.append(
                    {'id': item.id,
                     'name': item.name,
                     'type': item.type,
                     'gender': item.gender,
                     'unit': item.unit,
                     'data': item.data,
                     'status': item.status,
                     'start_time': str(item.start_time)[:-6],
                     'end_time': str(item.end_time)[:-6]
                     }
                )
            return api(datalist).success()


def enroll_model(request):
    if request.method == 'GET':
        enroll_id = request.GET.get('id', '')
        if enroll_id == '':
            items = enroll.objects.all()
            datalist = []
            for item in items:
                datalist.append(
                    {'id': item.id,
                     'name': item.player.name,
                     'institution': item.player.institution.name,
                     'game_name': item.game.name,
                     'gender': item.game.gender,
                     'gameid': item.game.id,
                     }
                )
            return api(datalist).success()
        else:
            ins = enroll.objects.filter(id=enroll_id)
            datalist = []
            for item in ins:
                datalist.append(
                    {'id': item.id,
                     'name': item.player.name,
                     'institution': item.player.institution.name,
                     'game_name': item.game.name,
                     'gender': item.game.gender,
                     'gameid': item.game.id,
                     }
                )
            return api(datalist).success()


def complain(request):
    if request.method == 'POST':
        try:
            json_data = json.loads(request.body)
            contact = json_data['contact']
            content = json_data['content']
        except:
            return api({'msg': 'json格式不正确'}).error()
        try:
            Complaint.objects.create(
                contact=contact,
                content=content
            )
            return api({'msg': '投诉提交成功'}).success()
        except:
            return api({'msg': '投诉提交错误'}).error()
    else:
        return api({'msg': '投诉提交错误'}).error()


def news(request):
    if request.method == 'POST':
        try:
            json_data = json.loads(request.body)
            title = json_data['title']
            content = json_data['content']
        except:
            return api({'msg': 'json格式不正确'}).error()
        try:
            News.objects.create(
                title=title,
                content=content,
            )
            return api({'msg': '提交成功'}).success()
        except:
            return api({'msg': '投诉错误'}).error()
    else:
        news_id = request.GET.get('id', '')
        if news_id == '':
            items = News.objects.all()
            datalist = []
            for item in items:
                datalist.append(
                    {'id': item.id,
                     'title': item.title,
                     'content': item.content
                     }
                )
            return api(datalist).success()
        else:
            items = News.objects.filter(id=news_id)
            datalist = []
            for item in items:
                datalist.append(
                    {'id': item.id,
                     'title': item.title,
                     'content': item.content
                     }
                )
            return api(datalist).success()


def player(request):
    if request.method == 'GET':
        username = request.GET.get('username')
        try:
            playerobj = Player.objects.get(username=username)
        except:
            return api("查无此用户").error()
        items = playerobj.enroll_set.all()
        data = []
        for item in items:
            data.append(
                {
                    "gameid": item.id,
                    "game": str(item.game),

                    "uid": item.player.id,
                    "name": item.player.name,
                    "institution": item.player.institution.name

                }
            )
        return api(data).success()

api主要就是对数据库的查询处理

转载:objects.all()、objects.get()与objects.filter()区别

转载:外键查询与反查

关键字说明
.objects.all()返回的是QuerySet对象,程序并没有真的在数据库中执行SQL语句查询数据,但支持迭代,使用for循环可以获取数据
.objects.get(id=‘1’)从数据库的取得一个匹配的结果,返回一个对象,如果记录不存在的话,它会报错。它返回的是一个字典的形式,如果去取得关联表的数据的话,而关键表的数据如果多于2条的话也会报错
.objects.filter()filter和get类似,但支持更强大的查询功能。方法是从数据库的取得匹配的结果,返回一个对象列表,如果记录不存在的话,

它会返回[]
主表对象.从表_set.all()|外键反查,上述api中是通过用户来查询出他的报名表(主表对象先通过get获取,然后再.从表_set.all())

  • 基本命令

数据库迁移模型生成

python manage.py makemigrations

数据库迁移

python manage.py migrate

创建admin后台用户

python manage.py createsuperuser

运行Django


python manage.py runserver 0.0.0.0:8000

* [Django3官方文档](https://docs.djangoproject.com/zh-hans/3.1/)

项目部署

项目测试

Logo

前往低代码交流专区

更多推荐