数据库实验3

实验三 嵌入式SQL与数据库连接

一、实验要求

掌握嵌入式SQL的使用方法,通过数据库连接技术连接DBMS,完成简易数据库应用系统的模拟实现。

二、实验目的

  • 理解嵌入式SQL;

  • 理解数据库连接技术;

  • 掌握基于特定宿主语言的数据库连接与访问;

  • 设计并实现通过嵌入式方式进行的数据库应用系统的增删改查询操作。

三、实验内容

1.数据库连接技术简介

本实验使用的是Django框架连接的openGauss数据库,本质是JDBC的方式连接数据库, 使用的驱动是postgresql jdbc driver ,版本:42.2.5,,jdbc版本:4.2

image-20210521163214744

图1

jdbc介绍

JDBC(Java DataBase Connectivity),即Java数据库连接。简而言之,就是通过Java语言来操作数据库。

我们可以把JDBC理解成是官方定义的一套操作所有关系型数据库的规则,规则即接口。

也就是说,官方定义了一套操作所有关系型数据库的接口,然后让各个数据厂商(Mysql、Oracle、postgresql等)用实现类去实现这套接口,再把这些实现类打包(数据驱动jar包),并提供数据驱动jar包给我们使用。

我们可以使用这套JDBC接口进行编程,但是真正执行的代码是驱动jar包中的实现类。

可以与数据库建立连接、发送、操作数据库的语句并处理结果。

2.数据库连接环境配置

①django配置

django中已经内置了对postgresql的数据库引擎,因此只需要配置好django就可以。

pip install Django

建议找一个较好的网络环境,否则会因为下载时间过长导致哈希校验失败

pip不行的话可以直接从网上找Django的压缩包安装,从这个网站找到如下的安装包

image-20210521164454002

图2
pip install D:Django‑3.2.3‑py3‑none‑any.whl

接下来就是验证配置,在命令行中输入:

python
import django
django.__version__

image-20210521164815852

图3

在这个时候就可以到安装django的目录下查看一下数据库的配置了,我的电脑上的位置是D:ProgramDataAnaconda3Libsite-packagesdjangodbackends

image-20210521165005725

图4

可以看到django支持连接postgresql数据库,且支持以psycopg2这个库连接,具体实现的代码在文件夹下

②配置openGauss数据库

对照群里的1_1_1_2_2_1_2_1_1_1_1_1_2_用navicat15连接华为云openguass数据库.docx配置openGauss,原因是连接数据库的密码无法通过openGauss的sha256的 检验,需要修改成MD5

cd /gaussdb/data/db1
vi postgresql.conf
//取消password_encryption_type注释并将等号后改为0
//password_encryption_type=0
vi pg_hba.conf
//将SHA156去掉,改为md5
//host all all 0.0.0.0/0 md5
gs_om -t start
//进入默认数据库
gsql -d postgres -p 26000 -r
//修改之前的用户密码
ALTER ROLE manager IDENTIFIED BY 'abcd@123' REPLACE 'Bigdata@123';//修改角色manager的密码为abcd@123。以此类推
gs_ctl  reload -D /gaussdb/data/db1

修改后为检验是否可以连接,我写了一个简单的验证连接的python代码

import psycopg2

conn = psycopg2.connect(database="teach", user="test", password="tset@123", host="192.168.56.101", port="26000")

if(conn):
    print("Connect database successfully")


c = conn.cursor()
#调用执行select语句查询数据
c.execute('select * from admin_sc.student ')
#通过游标的description属性获取列信息
for col in (c.description):
    print(col[0], end='	')
print('
--------------------------------')
#直接使用for循环来遍历游标中的结果集
for row in c:
    print(row)
c.close()     #关闭游标
conn.close()  #关闭连接以节约资源

运行结果如下:

image-20210521170330129

图5

至此,数据库连接成功

③在Django中配置数据库的连接

在项目的setting.py中修改数据库配置如下

'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'teach',
        'USER': 'test',
        'PASSWORD': 'tset@123',
        'HOST': '192.168.56.101',
        'PORT': '26000',
    },

3.嵌入式SQL的实现过程

Django支持的sql嵌入方式

Student.objects.extra(where=["Sno=%s"], params=['20181204'])
/*查询Student表中的学号等于20181204的数据*/

Student.objects.raw('selcet * from idnex_student')
/*读取Student表中的所有数据*/

from django.db import connection
cursor=connection.cursor()
cursor.execute('selcet * from idnex_student')
cursor.fetchall()
/*读取Student表中的所有数据*/

①创建数据表

在index的models.py中代码如下,用于建立学生宿舍管理系统的数据表:

from django.db import models

# Create your models here.


class Residence (models.Model): #类对应数据库中的数据表
    Rno = models.CharField('宿舍楼号', max_length=2, primary_key=True) #类的属性对应数据表的属性 
    Rname = models.CharField('宿舍楼名', max_length=20)
    Rfloor = models.SmallIntegerField('楼层数', default=0)

    def __str__(self):
        return self.Rno    #用于外键的信息
    class Meta:
        verbose_name = '宿舍楼信息'      #在后台中显示的名称
        verbose_name_plural = '宿舍楼信息'


class Dormitory(models.Model):
    Dno = models.CharField('宿舍号', max_length=4)
    Rno = models.ForeignKey(Residence, on_delete=models.CASCADE, verbose_name='宿舍楼号')
    Dnum = models.SmallIntegerField('应住人数', default=0)

    def __str__(self):
        return self.Dno
    class Meta:
        verbose_name = '宿舍信息'
        verbose_name_plural = '宿舍信息'
        unique_together = (("Dno", "Rno"),)  #元组中的元素组不可重复


class Student(models.Model):
    SDept = (
        ('密码系', '密码系'),
        ('网空系', '网空系'),
        ('电通系', '电通系'),
        ('管理系', '管理系'),
    )        # 设置前端的可视化的值
    SSex = (
        ('男','男'),
        ('女','女'),
    )
    SL = (
        ('是','是'),
        ('否','否'),
    )
    Sno = models.CharField('学号', max_length=8, primary_key=True)
    Sname = models.CharField('姓名', max_length=20)
    Rno = models.ForeignKey(Residence, on_delete=models.CASCADE, verbose_name='宿舍楼号')
    Dno = models.ForeignKey(Dormitory, on_delete=models.CASCADE, verbose_name='宿舍号')
    Ssex = models.CharField('性别', max_length=3,choices=SSex)
    Sclass = models.CharField('班级', max_length=4)
    Sbed = models.CharField('床号', max_length=2)
    Sphone = models.CharField('联系方式', max_length=11, unique=True)
    Sdept = models.CharField('系名', max_length=20, choices=SDept)
    Sleader = models.CharField('是否为寝室长', max_length=3, choices=SL)

    def __str__(self):
        return self.Sno
    class Meta:
        verbose_name = '学生信息'
        verbose_name_plural = '学生信息'


class Worker(models.Model):
    SSex = (
        ('男','男'),
        ('女','女'),
    )
    Wno = models.CharField('工号', max_length=8, primary_key=True)
    Wname = models.CharField('姓名', max_length=20)
    Rno = models.ForeignKey(Residence, on_delete=models.CASCADE, verbose_name='宿舍楼号')
    Wphone = models.CharField('联系方式', max_length=11, unique=True)
    Wsex = models.CharField('性别', max_length=3, choices=SSex)

    def __str__(self):
        return self.Wno
    class Meta:
        verbose_name = '职工信息'
        verbose_name_plural = '职工信息'

class LateCheck(models.Model):
    id = models.AutoField('编号', primary_key=True)
    Wno = models.ForeignKey(Worker, on_delete=models.CASCADE, verbose_name='职工号')
    Sno = models.ForeignKey(Student, on_delete=models.CASCADE, verbose_name='学号')
    Ltime = models.DateTimeField('登记时间')

    class Meta:
        verbose_name = '归校登记'
        verbose_name_plural = '归校登记'


class HealthCheck(models.Model):
    id = models.AutoField('编号', primary_key=True)
    Wno = models.ForeignKey(Worker, on_delete=models.CASCADE, verbose_name='职工号')
    Rno = models.ForeignKey(Residence, on_delete=models.CASCADE, verbose_name='宿舍楼号')
    Dno = models.ForeignKey(Dormitory, on_delete=models.CASCADE, verbose_name='宿舍号')
    Htime = models.DateTimeField('登记时间')
    Hscore = models.IntegerField('卫生分数', default=60)

    class Meta:
        verbose_name = '寝室卫生检查'
        verbose_name_plural = '寝室卫生检查'

在index的models.py中代码如下,用于向默认的用户表中添加我们需要的信息:

from django.db import models
from django.contrib.auth.models import AbstractUser


# Create your models here.


class MyUser(AbstractUser):
    is_student = models.BooleanField('是否为学生', default=False)
    is_worker = models.BooleanField('是否为职工', default=False)
    

    def __str__(self):
        return self.username

在pycharm的Terminal中输入以下指令完成数据表迁移:

python manage.py makemigrations
python manage.py migrate

②创建后台管理员的界面

在index的admin.py中编写以下代码,主要目的是在后台管理系统中设置嵌入式sql的查询条件,嵌入的基本都是查询的where条件:

from django.contrib import admin
from .models import *


# Register your models here.
admin.site.site_title = '数据库管理员后台管理'
admin.site.site_header = '数据库管理系统后台'

@admin.register(Student)
class StudentAdmin(admin.ModelAdmin):
    # 不可编辑字段
    # exclude = ['sno']
    # 改变新增或修改页面的网页布局
    fieldsets = (
        ('人员信息', {
            'fields': ('Sno', 'Sname', 'Ssex', 'Sclass', 'Sbed', 'Sphone', 'Sdept', 'Sleader', 'Rno', 'Dno')
        }),
    )

    # 将下拉框改为单选按钮
    # admin.HORIZONTAL是水平排列
    # admin.VERTICAL是垂直排列
    # radio_fields = {'Sno': admin.VERTICAL}

    # 在数据新增或修改的页面设置可读的字段,不可编辑
    # readonly_fields = ['Sno',]

    # 设置排序方式,['id']为升序,降序为['-id']
    ordering = ['Sno']

    # 设置数据列表页的每列数据是否可排序显示
    sortable_by = ['Sno', 'Sclass', 'Rno', 'Dno']

    # 在数据列表页设置显示的模型字段
    list_display = ['Sno', 'Sname', 'Ssex', 'Sclass', 'Sbed', 'Sphone', 'Sdept', 'Sleader', 'Rno', 'Dno']

    # 为数据列表页的字段设置路由地址,该路由地址可进入数据修改页
    list_display_links = ['Sno', 'Sname', 'Sclass', 'Sbed', 'Sphone', 'Rno', 'Dno']

    # 设置过滤器,如有外键,应使用双下画线连接两个模型的字段
    list_filter = ['Sdept', 'Sclass']

    # 在数据列表页设置每一页显示的数据量
    list_per_page = 15

    # 在数据列表页设置每一页显示最大上限的数据量
    list_max_show_all = 50

    # 为数据列表页的字段Sname设置编辑状态
    list_editable = ['Sdept', 'Ssex', 'Sleader']

    # 设置可搜索的字段
    search_fields = ['Sno', 'Sname']

    # 在数据列表页设置日期选择器
    # date_hierarchy = 'Sclass'

    # 在数据修改页添加“另存为”功能
    # save_as = True

    # 设置“动作”栏的位置
    actions_on_top = False
    actions_on_bottom = True


@admin.register(Worker)
class WorkerAdmin(admin.ModelAdmin):
    # list_display = ['Wno', 'Wname', 'Wphone', 'Wsex', 'Rno_id']
    fieldsets = (
        ('人员信息', {
            'fields': ('Wno', 'Wname', 'Wphone', 'Wsex', 'Rno')
        }),
    )

    ordering = ['Wno']

    sortable_by = ['Rno']

    list_display = ['Wno', 'Wname', 'Wphone', 'Wsex', 'Rno']

    list_display_links = ['Wno',  'Wphone',  'Rno']

    list_filter = ['Wsex', 'Rno__Rname']

    list_per_page = 15

    list_max_show_all = 50

    list_editable = ['Wsex']

    search_fields = ['Wno']

    # date_hierarchy = 'Sclass'

    actions_on_top = False
    actions_on_bottom = True


@admin.register(Dormitory)
class DorAdmin(admin.ModelAdmin):
    # list_display = ['id', 'Dno', 'Rno_id', 'Dnum']
    fieldsets = (
        ('人员信息', {
            'fields': ('Dno', 'Rno', 'Dnum')
        }),
    )

    ordering = ['id']

    sortable_by = ['Dno', 'Rno', 'Dnum']

    list_display = ['id', 'Dno', 'Rno', 'Dnum']

    list_display_links = ['id', 'Dno', 'Rno', 'Dnum']

    list_filter = ['Rno__Rname', 'Dnum']

    list_per_page = 15

    list_max_show_all = 50

    search_fields = ['Dno']

    actions_on_top = False
    actions_on_bottom = True

@admin.register(Residence)
class ResAdmin(admin.ModelAdmin):
    # list_display = ['Rno', 'Rname', 'Rfloor']
    fieldsets = (
        ('人员信息', {
            'fields': ('Rno', 'Rname', 'Rfloor')
        }),
    )

    ordering = ['Rno']

    sortable_by = ['Rno']

    list_display = ['Rno', 'Rname', 'Rfloor']

    list_display_links = ['Rno', 'Rname', 'Rfloor']

    list_per_page = 15

    list_max_show_all = 50

    search_fields = ['Rno']

    actions_on_top = False
    actions_on_bottom = True


@admin.register(LateCheck)
class LcAdmin(admin.ModelAdmin):
    # list_display = ['Ltime', 'Sno_id', 'Wno_id']
    fieldsets = (
        ('人员信息', {
            'fields': ('Wno', 'Sno', 'Ltime')
        }),
    )

    ordering = ['id']

    sortable_by = ['Wno', 'Sno']

    list_display = ['id', 'Wno', 'Sno', 'Ltime']

    list_display_links = ['id', 'Wno', 'Sno', 'Ltime']

    list_per_page = 15

    list_max_show_all = 50

    search_fields = ['Wno__Wno', 'Sno__Sno']

    date_hierarchy = 'Ltime'

    actions_on_top = False
    actions_on_bottom = True


@admin.register(HealthCheck)
class HcAdmin(admin.ModelAdmin):
    # list_display = ['Htime', 'Dno_id', 'Rno_id', 'Wno_id', 'Hscore']
    fieldsets = (
        ('人员信息', {
            'fields': ('Dno', 'Rno', 'Htime', 'Hscore')
        }),
    )

    ordering = ['id']

    sortable_by = ['Dno', 'Rno']

    list_display = ['id', 'Dno', 'Rno', 'Htime', 'Hscore']

    list_display_links = ['id', 'Dno', 'Rno', 'Htime', 'Hscore']

    list_filter = ['Rno__Rname']

    list_per_page = 15

    list_max_show_all = 50

    search_fields = ['Dno__Dno', 'Rno__Rno']

    date_hierarchy = 'Htime'

    actions_on_top = False
    actions_on_bottom = True

在user的admin.py中编写以下代码:

from django.contrib import admin
from .models import *
# Register your models here.


@admin.register(MyUser)
class StudentAdmin(admin.ModelAdmin):
    fieldsets = (
        ('人员信息', {
            'fields': ('username', 'password', 'is_staff', 'is_superuser', 'is_student', 'is_worker')
        }),
    )

    ordering = ['id']

    list_display = ['id', 'username', 'is_staff', 'is_superuser', 'is_student', 'is_worker']

    list_display_links = ['id', 'username', 'is_staff', 'is_superuser', 'is_student', 'is_worker']

    # list_filter = ['Rno__Rname']

    list_per_page = 15

    list_max_show_all = 50

    # list_editable = ['Wname']

    search_fields = ['username']

    date_hierarchy = 'last_login'

    actions_on_top = False
    actions_on_bottom = True

在index的init.py中编写以下代码以修改在后台的显示名称以方便管理员使用:

from django.apps import AppConfig
import os
# 修改App在Admin后台显示的名称
# default_app_config的值来自apps.py的类名
default_app_config = 'index.IndexConfig'

# 获取当前App的命名
def get_current_app_name(_file):
    return os.path.split(os.path.dirname(_file))[-1]

# 重写类IndexConfig
class IndexConfig(AppConfig):
    name = get_current_app_name(__file__)
    verbose_name = '数据表管理'

在user的init.py中编写以下代码:

from django.apps import AppConfig
import os

default_app_config = 'user.IndexConfig'


def get_current_app_name(_file):
    return os.path.split(os.path.dirname(_file))[-1]


class IndexConfig(AppConfig):
    name = get_current_app_name(__file__)
    verbose_name = '用户管理'

至此后台的开发结束,后台界面的美化教程可以参考这个回答

效果如下图所示:

image-20210521183505274

图6

以学生表和归校登记表为例

学生表:

image-20210521184853911

图7

学生表功能简单展示:

image-20210521191011818

图8

归校登记表:

image-20210521193409469

图9

归校登记表功能简单展示:

image-20210521193308458

图10
实现的功能
  • 可以在前端展示数据库中的数据
  • 可以根据学号、姓名查询(支持模糊查询)
  • 可以根据根据系名、班级(下拉框)过滤数据
  • 可以执行数据的增(非主键可以为空)删改(有规则限制)查,但不能删除数据表
  • 可以根据月份来过滤数据

③创建数据库管理系统主页

在templates目录下创建index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>学生宿舍数据库管理系统</title>
</head>
<body style="background: url(../static/image/bg.jpg) repeat-x #fff;">
<div>
    <img src="../static/image/banner.jpg" alt="11">
</div>
    <h3>学生宿舍数据库管理系统首页</h3>
    {% if user.username %}
    <h4>欢迎回来,{{ user.username }}</h4> <!--用户登录后显示用户的名字-->
    {%  endif %}
    <br>
    <a href="{%  url 'user:register' %}">注册</a>
    <a href="{%  url 'user:login' %}">登录</a>
    <a href="{%  url 'user:logout' %}">注销</a>
    {% if user.username %}
    <a href="{%  url 'user:setps' %}">修改密码</a>
    <a href="{%  url 'index:haystack' %}">查询</a>
    <!--用户登录后才可以修改密码和查询数据-->
    {%  endif %}
    <br>
</body>
</html>

效果如下(登陆前):

image-20210521194248841

图11

登陆后:

image-20210521194343809

图12

20172301是学生表第一个人,就用他创建了一个号

编写user的后端处理登录注册、修改密码、注销等功能:

import re
from django.shortcuts import render, redirect
from django.contrib.auth.models import User, Group
from user.models import MyUser
from index.models import Student, Worker
from django.contrib.auth import login, logout, authenticate

# 用户注册
from django.urls import reverse


def registerView(request):
    # 设置模版上下文
    title = '注册'
    pageTitle = '用户注册'
    button_register = True
    if request.method == 'POST':
        u = request.POST.get('username', '')
        p = request.POST.get('password', '')
        p_c = request.POST.get('password_check', '')
        r = request.POST.get('is_stu_wor', '')
        if MyUser.objects.filter(username=u):
            tips = '用户已存在'
        elif p != p_c:
            tips = '两次密码不一致'
        else:
            if r == 'stu':
                flag = Student.objects.filter(Sno=u)
                # 数据库中是否存在这个学生
                flag1 = re.match('20[1-9]{2}[1-9]{2}[0-9][1-9]', u)
                # 学生的学号是否符合格式
                if flag1 == None or len(flag) == 0:
                    tips = '用户名不正确,请输入正确的学号'
                else:
                    print('学生注册')
                    d = dict(username=u, password=p, is_staff=0, is_superuser=0, is_student=1, is_worker=0)
                    user = MyUser.objects.create_user(**d)
                    user.save()
     				# create_user实现用户数据新增
                    group_s = Group.objects.get(id=1)
                    user.groups.add(group_s)
                    # 将学生用户添加到学生组中
                    button_login = True
                    tips = '注册成功,请登录'
            elif r == 'wor':
                flag = Worker.objects.filter(Wno=u)
                # 数据库中是否存在这个职工
                flag1 = re.match('20[0-9]{2}00[0-9][1-9]', u)
                # 职工的职工号是否符合格式
                if flag1 == None or len(flag) == 0:
                    tips = '用户名不正确,请输入正确的工号'
                else:
                    print('教职工注册')
                    d = dict(username=u, password=p, is_staff=0, is_superuser=0, is_student=0, is_worker=1)
                    user = MyUser.objects.create_user(**d)
                    user.save()
                    # create_user实现用户数据新增
                    group_w = Group.objects.get(id=2)
                    user.groups.add(group_w)
                    # 将职工用户添加到职工组中
                    button_login = True
                    tips = '注册成功,请登录'
            else:
                print('error')
    return render(request, 'user.html', locals())

# 用户登录
def loginView(request):
    # 设置模版上下文
    title = '登录'
    pageTitle = '用户登录'
    button_login = True
    if request.method == 'POST':
        u = request.POST.get('username', '')
        p = request.POST.get('password', '')
        flag1 = re.match('20[1-9]{2}[1-9]{2}[0-9][1-9]', u)
        flag2 = re.match('20[0-9]{2}00[0-9][1-9]', u)
        if flag1 == None and flag2 == None:
            tips = '用户不存在,请注册'
            return render(request, 'user.html', locals())
        if MyUser.objects.filter(username=u):  # filter实现数据查询
            user = authenticate(username=u, password=p)
            if user:
                if user.is_active:
                    login(request, user)
                return redirect(reverse('index:index'))
            else:
                tips = '账号密码错误,请重新输入'
        else:
            tips = '用户不存在,请注册'
    return render(request, 'user.html', locals())


# 使用make_password实现密码修改
from django.contrib.auth.hashers import make_password
def setpsView(request):
    # 设置模版上下文
    title = '修改密码'
    pageTitle = '修改密码'
    password2 = True
    button_register = True
    button_login = True
    if request.method == 'POST':
        u = request.POST.get('username', '')
        p = request.POST.get('password', '')
        p2 = request.POST.get('password2', '')
        # 判断用户是否存在
        user = MyUser.objects.filter(username=u)
        if MyUser.objects.filter(username=u):
            user = authenticate(username=u,password=p)
            # 判断用户的账号密码是否正确
            if user:
                # 密码加密处理并保存到数据库
                dj_ps = make_password(p2, None, 'pbkdf2_sha256')
                user.password = dj_ps
                user.save()
            else:
                print('原始密码不正确')
    return render(request, 'user.html', locals())

# 用户注销,退出登录
def logoutView(request):
    logout(request)
    return redirect(reverse('index:index'))

编写user的后端实现普通用户的数据查找功能:

from django.shortcuts import render
from django.core.paginator import *
from django.conf import settings
from .models import *
from haystack.views import SearchView

# Create your views here.


def indexView(request):
    return render(request, 'index.html', locals())

# 视图以通用视图实现
class MySeacherStu(SearchView):
    # 模版文件
    template = 'search.html'
    # 重写响应方式
    # 如果请求参数q为空,返回模型Product的全部数据
    # 否则根据参数q搜索相关数据
    def create_response(self):
        if not self.request.GET.get('q', ''):
            show_all = True
            student = Student.objects.all().order_by('Sno')
            per = settings.HAYSTACK_SEARCH_RESULTS_PER_PAGE
            p = Paginator(student, per)
            try:
                num = int(self.request.GET.get('page', 1))
                page = p.page(num)
            except PageNotAnInteger:
                # 如果参数page不是整型,则返回第1页数据
                page = p.page(1)
            except EmptyPage:
                # 访问页数大于总页数,则返回最后1页的数据
                page = p.page(p.num_pages)
            return render(self.request, self.template, locals())
        else:
            show_all = False
            qs = super(MySeacherStu, self).create_response()
            return qs
实现的功能
  • 用户前端看到的数据被分页存放,且可以搜索
  • 注册用户必须是存在数据库中的学生或职工,不是则注册失败,通过正则表达式判断用户名是否符合格式防止sql注入攻击、XSS攻击
  • 登录用户必须是数据库中用户表中的用户,否则登录失败
  • 用户可以注销登录,否则会保留其session使其一直保持登录状态
  • 登录用户材可以查看数据、修改密码
  • 管理员和超级管理员不允许通过注册产生,只会创建默认账户各一个,应用上线后不再产生新账户

④创建数据库管理系统用户查看的数据

在templates目录下创建search_s.html(以学生表为例)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>学生列表</title>
    {# 导入CSS样式文件 #}
    {% load staticfiles %}
    <link rel="stylesheet" href="{% static "css/common_my.css" %}">
    <link rel="stylesheet" href="{% static "css/search_my.css" %}">
</head>
<body>
<div class="header">
    <div class="search-box">
        <form action="" method="get">
            <div class="search-keyword">
                {# 搜索文本框必须命名为q #}
                <input name="q" type="text" class="keyword">
            </div>
            <input type="submit" class="search-button" value="搜 索">
        </form>
    </div>
</div>

<div class="wrapper clearfix">
<div class="listinfo">
    <ul class="listheader">
        <li class="myitem">学号</li>
        <li class="myitem">姓名</li>
        <li class="myitem">性别</li>
        <li class="myitem">班级</li>
        <li class="myitem">床号</li>
        <li class="myitem">手机号</li>
        <li class="myitem">系部</li>
        <li class="myitem">寝室长</li>
        <li class="myitem">宿舍楼号</li>
        <li class="myitem">宿舍号</li>
    </ul>
    <ul class="ullsit">
        {# 列出当前分页所对应的数据内容 #}
        {% if show_all %}
            {% for item in page.object_list %}
            <li>
                <div class="item">
                    <div class="myiteminfo">{{ item.Sno }}</div>
                    <div class="myiteminfo">{{item.Sname}}</div>
                    <div class="myiteminfo">{{ item.Ssex }}</div>
                    <div class="myiteminfo">{{ item.Sclass }}</div>
                    <div class="myiteminfo">{{ item.Sbed }}</div>
                    <div class="myiteminfo">{{ item.Sphone }}</div>
                    <div class="myiteminfo">{{ item.Sdept }}</div>
                    <div class="myiteminfo">{{ item.Sleader }}</div>
                    <div class="myiteminfo">{{ item.Rno }}</div>
                    <div class="myiteminfo">{{ item.Dno }}</div>
                </div>
            </li>
            {% endfor %}
        {% else %}
            {# 导入自带高亮功能 #}
            {% load highlight %}
            {% for item in page.object_list %}
            <li>
                <div class="item">
                    <div class="myiteminfo">{% highlight item.object.Sno with query %}</div>
                    <div class="myiteminfo">{% highlight item.object.Sname with query %}</div>
                    <div class="myiteminfo">{% highlight item.object.Ssex with query %}</div>
                    <div class="myiteminfo">{% highlight item.object.Sclass with query %}</div>
                    <div class="myiteminfo">{% highlight item.object.Sbed with query %}</div>
                    <div class="myiteminfo">{% highlight item.object.Sphone with query %}</div>
                    <div class="myiteminfo">{% highlight item.object.Sdept with query %}</div>
                    <div class="myiteminfo">{% highlight item.object.Sleader with query %}</div>
                    <div class="myiteminfo">{% highlight item.object.Rno with query %}</div>
                    <div class="myiteminfo">{% highlight item.object.Dno with query %}</div>
                </div>
            </li>
            {% endfor %}
        {% endif %}
    </ul>
    {# 分页导航 #}
    <div class="page-box">
    <div class="pagebar" id="pageBar">
    {# 上一页的路由地址 #}
    {% if page.has_previous %}
        {% if query %}
            <a href="{% url 'index:haystack'%}?q={{ query }}&page={{ page.previous_page_number }}" class="prev">上一页</a>
        {% else %}
            <a href="{% url 'index:haystack'%}?page={{ page.previous_page_number }}" class="prev">上一页</a>
        {% endif %}
    {% endif %}
    {# 列出所有的路由地址 #}
    {% for num in page.paginator.page_range %}
        {% if num == page.number %}
            <span class="sel">{{ page.number }}</span>
        {% else %}
            {% if query %}
                <a href="{% url 'index:haystack' %}?q={{ query }}&page={{ num }}">{{num}}</a>
            {% else %}
                <a href="{% url 'index:haystack' %}?page={{ num }}">{{num}}</a>
            {% endif %}
        {% endif %}
    {% endfor %}
    {# 下一页的路由地址 #}
    {% if page.has_next %}
        {% if query %}
            <a href="{% url 'index:haystack' %}?q={{ query }}&page={{ page.next_page_number }}" class="next">下一页</a>
        {% else %}
            <a href="{% url 'index:haystack' %}?page={{ page.next_page_number }}" class="next">下一页</a>
        {% endif %}
    {% endif %}
    </div>
    </div>
</div>
</div>
</body>
</html>
实现功能
  • 用户只能对数据查看,不可修改
  • 用户可以对数据检索(支持模糊搜索),检索到的数据高亮显示

四、问题分析

1.核心问题

最大的问题就是实现什么样的功能,需求分析真的是太难了

我的解决方法是积极和同小组的同学交流(毕竟是同一个系统),他们也向我提供了改善管理员输入体验的设想,再通过查找相关资料实现功能,让系统更加人性化。

其次是上网查询资料,看看有没有人做过相关的工作,有没有经验可循。

还可以请不相关的同学来体验系统,提提意见。

其他的就只能靠自己深入思考了。

2.数据表映射的问题

将我们的原先实验一、二的数据表想要映射到python的对象中时发现python对外键的定义有所不同,导致了对数据表的更改:python不支持两个属性做主键

解决方法:只能通过一个自增ID作为主键,通过unique_together方法保证宿舍楼号和宿舍号不同时重复

3.数据库连接失败

解决方法:按照上文的方法修改为MD5验证

4.缺少连接数据库的引擎

解决方法:手动下载对应的引擎并添加到lib目录下对应的位置

五、实验感想

本次实验我主要是将前两次实验的内容重新整合,为了保证安全性设计了用户组,将通过认证的用户分配给对应的用户组来实现权限分配,又通过用户认证的过程基本保证了安全性,通过对输入内容的判断防止了sql注入攻击、XSS攻击,通过CSRF的机制来防止重放攻击,整个系统的安全性得到一定的保障,将数据的增加、删除和修改的一部分功能给予管理员用户,将全部的权限给予超级管理员,其他用户只有查询一部分表的权限基本保证系统不会收到来自内部的攻击。

经过本次实验我体会到了制作一个可以用的数据库管理系统的难度,让我对数据库设计的步骤有了更加清醒的认识,意识到我在需求分析方面还存在不足,需要继续提高,数据库实施阶段需要加快速度,对数据库的运维我感觉主要是在开发过程中多写提示语句,多用try-catch-finally的结构,给自己点提示信息,方便查错,前几个阶段我感觉最重要的就是ER图的设计了,需要审慎考虑,因为会对后面的具体实现产生巨大的影响,如果设计存在巨大漏洞的话,后面几乎很难弥补了。

六、附录

主要是一些其他的重要代码(防止看不懂)

注册登录的html

<!DOCTYPE html>
<html>
<head>
    {% load staticfiles %}
	<title>{{ title }}</title>
	<link rel="stylesheet" href="{% static "css/reset.css" %}" />
	<link rel="stylesheet" href="{% static "css/user.css" %}" />
    <script src="{% static "js/jquery.min.js" %}"></script>
    <script src="{% static "js/user.js" %}"></script>
</head>
<body>
<div class="page">
	<div class="loginwarrp">
		<div class="logo">{{ pageTitle }}</div>
        <div class="login_form">
			<form id="Login" name="Login" method="post" action="">
                {% csrf_token %}
				<li class="login-item">
					<span>用户名:</span>
					<input type="text" name="username" class="login_input">
                    <span id="count-msg" class="error"></span>
				</li>
				<li class="login-item">
					<span>密 码:</span>
					<input type="password" name="password" class="login_input">
                    <span id="password-msg" class="error"></span>
				</li>
                {% if button_register %}
                    <li class="login-item">
                        <span>确认密码:</span>
                        <input type="password" name="password_check" class="login_input">
                        <span id="password-msg" class="error"></span>
                    </li>
                    <li class="login-item">
                        <span>选择身份:</span>
                        <select name="is_stu_wor" class="login_input">
                        <option value="stu" selected="selected">学生</option>
                        <option value="wor">教职工</option>
                        </select>
                        <span id="password-msg" class="error"></span>
                    </li>
                {% endif %}
                {% if password2 %}
                    <li class="login-item">
                        <span>新密码:</span>
                        <input type="password" name="password2" class="login_input">
                        <span id="password-msg" class="error"></span>
				    </li>
                {% endif %}
                <div>{{ tips }}</div>
				<li class="login-sub">
					<input type="submit" name="Submit" value="确定">
				</li>
                <hr color="#ddd">
                <div align="center"><a href="{%  url 'index:index' %}">回到首页</a></div>
                {% if button_login %}
                    <div align="right"><a href="{%  url 'user:register' %}">还没有注册</a></div>
                {% endif %}
                {% if button_register %}
                    <div align="right"><a href="{%  url 'user:login' %}">已经注册,直接登录</a></div>
                {% endif %}
           </form>
		</div>
	</div>
</div>
<script type="text/javascript">
	window.onload = function() {
		var config = {
			vx : 4,
			vy : 4,
			height : 2,
			width : 2,
			count : 100,
			color : "121, 162, 185",
			stroke : "100, 200, 180",
			dist : 6000,
			e_dist : 20000,
			max_conn : 10
		};
		CanvasParticle(config);
	}
</script>
<script src="{% static "js/canvas-particle.js" %}"></script>
</body>
</html>

user的路由表

from django.urls import path
from .views import *


urlpatterns = [
	path('login.html', loginView, name='login'),
	path('register.html', registerView, name='register'),
	path('setps.html', setpsView, name='setps'),
	path('logout.html', logoutView, name='logout'),
]

用户组的权限设计

image-20210521220520321

图13

image-20210521220556733

图14

image-20210521220611994

图15
原文地址:https://www.cnblogs.com/wqnmlkb/p/14797609.html