Django项目实战:在线作业管理系统(1)

项目环境:Python 3.6 + Django 2.0 + MySQL(Navicat for MySQL)

总体需求:

 教师端学生端
个人信息注册、登陆、查看、编辑个人信息;修改密码注册、登陆、查看、编辑个人信息;修改密码
课程信息

创建、删除课程;

创建、修改、删除作业;

查看学生提交的作业;

加入、退出课程;

查看课程作业;

提交、修改、删除作业;

设计思路

首先实现系统的登陆、注册功能,以及个人信息修改、退出功能。

然后再实现系统的课程信息相关功能。

效果图:本项目使用的模板为 bootstrap后台模版hAdmin

项目配置

通过命令行方式创建项目 homework,并创建一个名为 project 的 APP,并把它加到 settings.py 里 INSATLLED_APP 中,如果要使用 MySQL数据库,则需要进行如下配置。

django-admin startproject homework
cd homework
python manage.py startapp project
# homework/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'project',
]

# 数据库配置

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST':'localhost',
        'USER':'root',
        'PASSWORD':'123456',
        'PORT':'3306',
        'NAME':'project',
    }
}

因为要用到静态文件,需要在 settings.py 里设置 STATIC_URL 和 MEDIA(注意路径要写正确)。用户上传的文件会放在/media/文件夹里。

# homework/settings.py

# 将系统时间配置为本地时间,系统语言为中文

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'collectstatic')

# Be careful
STATICFILES_DIRS = [os.path.join(BASE_DIR,'static'),]

# specify media root for user uploaded files,

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')

项目的 urls.py 如下所示。将 project 的 urls.py 也添加进去。别忘了在结尾部分加static配置。

# homework/urls.py

from django.contrib import admin
from django.urls import path,include,re_path
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('', include('project.urls')),
    path('admin/', admin.site.urls),
] + static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)

模型 models.py

本项目对 Django Auth 自带的User模型进行了扩展,并允许用户添加更多的个人信息。由于引用了Django Auth自带的User模型,所以要 import 进来。其中外键属性中 related_name 的作用为简化反向查询。

# project/models.py

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


class Role(models.Model):
    ROLE_CHOICES = (
        (0,'学生'),
        (1,'教师')
    )
    user = models.OneToOneField(User,related_name='role',on_delete=models.CASCADE)
    role = models.SmallIntegerField(choices=ROLE_CHOICES,default=0,verbose_name='角色')

    def __str__(self):
    	return str(self.role)

'''
    定义一个抽象类,字段为各个表的公共字段,这个类并不会在数据库中建表
'''
class UserAbstractModel(models.Model):
    GENDER_CHOICES = (
        (0,'男'),
        (1,'女')
    )
    name = models.CharField('姓名',default='', max_length=50)
    gender = models.SmallIntegerField(choices=GENDER_CHOICES,default=0,verbose_name='性别')
    created = models.DateTimeField('创建时间', auto_now_add=True)
    modified = models.DateTimeField('最后更改时间', auto_now=True)
    description = models.TextField('个人描述',null=True)
    # photo = models.ImageField('用户头像',upload_to=user_directory_path,blank=True)

    class Meta:
        abstract = True

class Teacher(UserAbstractModel):
    user = models.OneToOneField(Role,related_name='teacher',on_delete=models.CASCADE)
    ranks = models.CharField(default='无', max_length=50,verbose_name='职称')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name='教师表'
        verbose_name_plural = verbose_name

class Student(UserAbstractModel):
    user = models.OneToOneField(Role,related_name='student',on_delete=models.CASCADE)
    classes = models.CharField('班级',default='', max_length=50)

    def __str__(self):
        return self.user.user.username

    def get_course_count(self):
    	return Course.objects.filter(student__id=self.id).count()

    class Meta:
        verbose_name='学生表'
        verbose_name_plural = verbose_name

执行以下命令,即可在数据库中看到相关的表。

python manage.py makemigrations
python manage.py migrate

路由 urls.py

# project/urls.py

from django.urls import re_path,path
from . import views

app_name = 'project'
urlpatterns = [

    # 登陆、注册 以及 信息、密码修改
    path('',views.index,name='index'),
    re_path(r'^register/$',views.register,name='register'),
    re_path(r'^login/$', views.login, name='login'),
    re_path(r'^user/(?P<pk>\d+)/profile/$', views.profile, name='profile'),
    re_path(r'^user/(?P<pk>\d+)/profile/update/$', views.profile_update, name='profile_update'),
    re_path(r'^user/(?P<pk>\d+)/pwdchange/$', views.pwd_change, name='pwd_change'),
    re_path(r'^logout/$', views.logout, name='logout'),

]

表单 forms.py

forms.py 可通过clean 方法自定义表单验证,而不用在 views.py 里再进行表单验证。

from django import forms 
from django.contrib.auth.models import User 
from django.forms import ModelForm
from .models import Teacher,Student,Course,Homework,Handin,Comment,Group
from ckeditor_uploader.widgets import CKEditorUploadingWidget

class RegistrationForm(forms.Form):
    username = forms.CharField(label=' 用户名',max_length=50)
    password1 = forms.CharField(label=' 密 码 ',widget=forms.PasswordInput)
    password2 = forms.CharField(label='确认密码', widget=forms.PasswordInput)
    role = forms.ChoiceField(label='角色',choices=((0,'学生'),(1,'教师')))

    def clean_username(self):
        username = self.cleaned_data.get('username')

        if len(username) < 6:
            raise forms.validationError("用户名必须至少为6个字符!")
        elif len(username) > 50:
            raise forms.ValidationError("用户名太长!")
        else:
            filter_result = User.objects.filter(username__exact=username)
            if len(filter_result) > 0:
                raise forms.ValidationError("用户名已存在!")
        return username

    def clean_password1(self):
        password1 = self.cleaned_data.get('password1')

        if len(password1) < 6:
            raise forms.ValidationError("密码太短!")
        elif len(password1) > 20:
            raise forms.ValidationError("密码太长!")
        return password1

    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')

        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("密码不匹配,请重新输入!")

        return password2

class LoginForm(forms.Form):
    username = forms.CharField(label='用户名', max_length=50)
    password = forms.CharField(label='密码', widget=forms.PasswordInput)

    def clean_username(self):
        username = self.cleaned_data.get('username')
        filter_result =  User.objects.filter(username__exact=username)
        if not filter_result:
            raise forms.ValidationError("用户名不存在!")
        return username

class ProfileForm(forms.Form):
    name = forms.CharField(label='姓名', max_length=50, required=False)
    gender = forms.ChoiceField(label='性别',widget = forms.Select(),choices = ([('0','男'), ('1','女'), ]),required=False)

class PwdChangeForm(forms.Form):
    old_password = forms.CharField(label=' 原 密 码 ', widget=forms.PasswordInput)
    password1 = forms.CharField(label=' 新 密 码 ', widget=forms.PasswordInput)
    password2 = forms.CharField(label='确认密码', widget=forms.PasswordInput)

    def clean_password1(self):
        password1 = self.cleaned_data.get('password1')

        if len(password1) < 6:
            raise forms.ValidationError("密码太短!")
        elif len(password1) > 20:
            raise forms.validationError("密码太长!")
        return password1

    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')

        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("密码不匹配,请重新输入!")
        return password2

视图 views.py

  • 用户通过POST方法提交表单,RegistrationForm 对所提及的数据进行验证是否有效。

  • 如果用户没有提交表单或不是通过 POST 方法提交表单,则跳转到注册页面,生成一张空的 RegistrationForm

# project/views.py

from django.shortcuts import render, get_object_or_404, redirect
from django.contrib import auth
from django.contrib.auth.models import User

from .models import Teacher,Student
from .forms import RegistrationForm, LoginForm, ProfileForm, PwdChangeForm
from django.http import HttpResponseRedirect,Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required

def index(request):
    return render(request,'project/index.html')

def register(request):
    if request.method == 'POST':
        # 验证表单RegistrationForm的数据是否有效
        form = RegistrationForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password2']
            role = form.cleaned_data['role']
            # 使用内置User自带create_user方法创建用户,不需要使用save()
            user = User.objects.create_user(username=username, password=password)
            role_profile = Role(role=int(role),user=user)
            role_profile.save()
            # 如果直接使用objects.create()方法后不需要使用save()
            if int(role) == 0:
                user_profile = Student(user=role_profile)
                user_profile.save()
            else:
                user_profile = Teacher(user=role_profile)
                user_profile.save()
            #  注册成功,通过HttpResponseRedirect方法转到登陆页面
            return HttpResponseRedirect("/login/")
    else:
        form = RegistrationForm()
    return render(request, 'project/registration.html', {'form': form})

def login(request):
    if request.method == 'POST':
        form = LoginForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            # 调用Django自带的auth.authenticate() 来验证用户名和密码是否正确
            user = auth.authenticate(username=username, password=password)
            if user is not None and user.is_active:
            	# 调用auth.login()来进行登录
                auth.login(request, user)
                # 登录成功,转到用户个人信息页面
                # []是有序的可reverse,{}是无序的
                return HttpResponseRedirect(reverse('project:index'))
            else:
                # 登陆失败
                return render(request, 'project/login.html', {'form': form,'message': '密码错误,请重试!'})
    else:
    	# 如果用户没有提交表单或不是通过POST方法提交表单,转到登录页面,生成一张空的LoginForm
        form = LoginForm()
    return render(request, 'project/login.html', {'form': form})

@login_required
def profile(request,pk):
	user = get_object_or_404(User,pk=pk)
	return render(request,'project/profile.html',{'user':user})

@login_required
def profile_update(request, pk):
    user = get_object_or_404(User, pk=pk)
    # user_profile = get_object_or_404(UserProfile, user=user)

    if request.method == "POST":
        form = ProfileForm(request.POST)

        if form.is_valid():
            if request.user.role.role == 0:
                user.role.student.name = form.cleaned_data['name']
                user.role.student.gender = form.cleaned_data['gender']
                user.role.student.save()
                return HttpResponseRedirect(reverse('project:profile', args=[user.id]))
            else:
                user.role.teacher.name = form.cleaned_data['name']
                user.role.teacher.gender = form.cleaned_data['gender']
                user.role.teacher.save()
                return HttpResponseRedirect(reverse('project:profile', args=[user.id]))
    else:
        if request.user.role.role == 0:
            default_data = {'name': user.role.student.name, 
                            'gender': user.role.student.gender,
                        }
        else:
            default_data = {'name': user.role.teacher.name, 
                            'gender': user.role.teacher.gender,
                        }
        form = ProfileForm(default_data)

    return render(request, 'project/profile_update.html', {'form': form, 'user': user})

@login_required
def logout(request):
    auth.logout(request)
    return HttpResponseRedirect("/login/")

@login_required
def pwd_change(request, pk):
    user = get_object_or_404(User, pk=pk)

    if request.method == "POST":
        form = PwdChangeForm(request.POST)

        if form.is_valid():

            password = form.cleaned_data['old_password']
            username = user.username
            
            user = auth.authenticate(username=username, password=password)

            if user is not None and user.is_active:
                new_password = form.cleaned_data['password2']
                user.set_password(new_password)
                user.save()
                return HttpResponseRedirect("/login/")

            else:
                return render(request, 'project/pwd_change.html', {'form': form,'user': user, 'message': '原密码错误,请重新输入!'})
    else:
        form = PwdChangeForm()

    return render(request, 'project/pwd_change.html', {'form': form, 'user': user})

URL重定向方法(可参考这里

HttpResponseDirect - django.http 方法:例如 HttpResponseRedirect("/login/")   HttpResponseRedirect(reverse('project:profile', args=[user.id]))

redirect - django.shortcuts 方法:例如 redirect('/index/')   redirect('https://www.baidu.com/')  redirect(reverse('project:profile'))

reverse - django.urls 方法:其作用是对已命名的URL进行反向解析,还传递相应的参数(args或带key的参数kargs)。

模板 Templates

这里只展示部分模板代码,其中注册模板代码如下:

<!--templates/project/registration.html-->

{% extends "project/base.html" %}
{% block content %}


<body class="gray-bg">

    <div class="middle-box text-center loginscreen   animated fadeInDown">
        <div>
            <div>

            </div>
            <h3>欢迎注册 </h3>
            <form class="m-t" method="post" action="" enctype="multipart/form-data">
                {% csrf_token %}
                {% for field in form %}
                <div class="form-group">
                    {{ field.errors }}
                    {{ field.label_tag }} {{ field }}
                    {% if field.help_text %}
                        <p class="help">{{ field.help_text|safe }}</p>
                    {% endif %}
                </div>
                {% endfor %}
                <button type="submit" class="btn btn-primary">注 册</button>

            </form>
    
        </div>
    </div>

</body>

</html>

{% endblock %}

登陆模板:

<!--templates/project/login.html-->

{% load staticfiles %}
{% load static %}
<!DOCTYPE html>
<html>
<head>
	<title>登陆</title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">  
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<style type="text/css">
body{
    background: url("../img/1.jpg");
    animation-name:myfirst;
    animation-duration:12s;
    /*变换时间*/
    animation-delay:2s;
    /*动画开始时间*/
    animation-iteration-count:infinite;
    /*下一周期循环播放*/
    animation-play-state:running;
    /*动画开始运行*/
}
@keyframes myfirst
{
    0%   {background:url("{% static '/img/th1.jpg' %}");}
    50%  {background:url("{% static '/img/th2.jpg' %}");}
    100% {background:url("{% static '/img/th1.jpg' %}");}
}
.form{background: rgba(255,255,255,0.2);width:400px;margin:120px auto;}
/*阴影*/
.fa{display: inline-block;top: 27px;left: 6px;position: relative;color: #ccc;}
input[type="text"],input[type="password"]{padding-left:26px;}

</style>

<body>
{% block content %}
<div class="container">
    <div class="form row">
        <div class="form-horizontal col-md-offset-3" id="login_form">
            <h3 class="form-title">登陆</h3>
            <form class="form-horizontal" method="post" action="" enctype="multipart/form-data">
            	{% csrf_token %}
            <div class="col-md-9">
                <div class="form-group">
                    <i class="fa fa-user fa-lg"></i>
                    <input class="form-control required" type="text" placeholder="Username" id="username" name="username"/>
                </div>
                <div class="form-group">
                    <i class="fa fa-lock fa-lg"></i>
                    <input class="form-control required" type="password" placeholder="Password" id="password" name="password"/>
                </div>
                <div class="form-group">
                    <a href="{% url 'project:register' %}">注册</a>
                </div>
                <div class="form-group col-md-offset-9">
                    <button type="submit" class="btn btn-success pull-right" name="submit">登录</button>
                </div>
            </div>
        	</form>
        </div>
    </div>
</div>
{% endblock %}
</body>

</html>

用户信息模板:

<!-- templates/project/profile.html-->
{% extends "project/base.html" %}
{% load static %}
{% block content %}	

<body class="gray-bg">
    <div class="wrapper wrapper-content">
        <div class="row animated fadeInRight">
            <div class="col-sm-3"></div>
            <div class="col-sm-6">
                <div class="ibox float-e-margins">
                    <div class="ibox-title">
                        <h5>个人资料</h5>
                    </div>
                    <div>
                        <div class="ibox-content no-padding border-left-right" align="center">
                            <a class="" href="#" title="">
                                <img alt="image" class="img-responsive" src="{% static '/img/p_big2.jpg' %}" >
                            </a>
                        </div>
                        <div class="ibox-content profile-content">
                            <h4><strong>姓名:{{ user.role.student.name }}{{ user.role.teacher.name }}</strong></h4>
                            <h4>用户名: {{ user.username }}</h4>
                            <h4>Email: {{ user.email }} </h4>

                            <p><i class="fa fa-map-marker"></i> 河北省xxxxxxxxxxxxx</p>
                            <h5>自我描述</h5>
                            <p>
                                会点前端技术,div+css啊,jQuery之类的,不是很精;热爱生活,热爱互联网,热爱新技术;有一个小的团队,在不断的寻求新的突破。
                            </p>
                            <p>
                                <ul>
                                    {% if request.user.role.role == 1 %}
                                        {% if request.user.role.teacher.gender %}
                                            <li>性别: 女 </li>
                                        {% else %}
                                            <li>性别: 男 </li>
                                        {% endif %}
                                    {% else %}
                                        {% if request.user.role.student.gender %}
                                            <li>性别: 女 </li>
                                        {% else %}
                                            <li>性别: 男 </li>
                                        {% endif %}
                                    {% endif %}

                                    {% if request.user.role.role == 1 %}
                                        <li>用户类型:教师 </li>
                                    {% else %}
                                        <li>用户类型:学生 </li>
                                    {% endif %}
                                    {% if user.role.role == 1 %}
                                    <li>职称: {{ user.role.teacher.ranks }} </li>
                                    {% else %}
                                    <li>班级: {{ user.role.student.classes }} </li>
                                    {% endif %}
                                </ul>
                            </p>
                            <div class="row m-t-lg">
                                <div class="col-sm-4">
                                </div>
                                <div class="col-sm-4">
                                </div>
                                <div class="col-sm-4">
                                </div>
                            </div>
                            <div class="user-button">
                                <div class="row">
                                    <div class="col-sm-6">
                                        {% if user.is_authenticated %}
                                        <a href="{% url 'project:profile_update' user.id %}">
                                            <button type="button" class="btn btn-primary btn-sm btn-block"><i class="fa fa-envelope"></i> 编辑信息</button>
                                        </a>
                                        {% endif %}
                                    </div>
                                    <div class="col-sm-6">
                                        {% if user.is_authenticated %}
                                        <a href="{% url 'project:pwd_change' user.id %}">
                                            <button type="button" class="btn btn-default btn-sm btn-block"><span class="glyphicon glyphicon-wrench"> </span> 修改密码</button>
                                        </a>
                                        {% endif %}
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col-sm-3"></div>
        </div>
    </div>

</body>


{% endblock %}   

项目运行

python manage.py runserver

 

  • 51
    点赞
  • 365
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
校园舆情管理系统是一个基于Django开发的实际项目,它的主要目标是帮助学校管理和监控校园内的舆情信息,包括学生的投诉、教师的评价、校园新闻等。下面将介绍该系统的主要功能和实现方式。 1. 用户管理:系统支持多种类型的用户,包括学生、教师、管理员等。用户可以通过注册和登录来使用系统,并且根据用户类型来限制其访问权限。 2. 舆情信息发布:用户可以发布与校园相关的舆情信息,包括投诉问题、教师评价、校园新闻等。用户可以上传附件、添加标签和描述,以便更好地组织和管理舆情信息。 3. 舆情信息管理:管理员可以对发布的舆情信息进行审核和管理,包括审核投诉问题、处理教师评价、编辑校园新闻等。管理员可以通过系统提供的界面对舆情信息进行分类、标记、筛选等操作。 4. 舆情信息展示:系统提供多种方式来展示校园舆情信息,包括热门舆情排行榜、舆论分析报告、关键词云图等。用户可以通过这些展示方式来了解校园的舆情动态。 5. 舆情信息监测:系统可以对校园内的舆情信息进行实时监测,通过自然语言处理和数据挖掘等技术来识别和分析舆情信息。这样可以及时发现和处理校园的舆情问题。 该校园舆情管理系统使用Django框架进行开发,可以快速构建起一个功能完善的校园舆情管理平台。Django框架提供了丰富的功能和模块,包括用户管理、数据存储、Web界面等,可以大大加快开发进度和提高系统的稳定性。同时,Django还提供了便捷的API接口和模板引擎,方便系统与其他应用进行交互和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值