models.py
from django.db import models class UserInfo(models.Model): """ 用户表:既有班主任也有老师 """ username = models.CharField(max_length=32) password = models.CharField(max_length=64) email = models.CharField(max_length=32) ut = models.ForeignKey("UserType",on_delete=models.CASCADE) #用户和用户类型一对多的关系 teacher_classes = models.ManyToManyField("Classes") #老师和班级的多对多关系 class UserType(models.Model): """ 用户类型表 """ title = models.CharField(max_length=32) class Classes(models.Model): """ 班级表 """ name = models.CharField(max_length=32) classteacher = models.ForeignKey("UserInfo",on_delete=models.CASCADE) #班级和班主任是一对多的关系 class Student(models.Model): """ 学生表 """ name = models.CharField(max_length=32) age = models.IntegerField(max_length=32) cls = models.ForeignKey("Classes",on_delete=models.CASCADE) #学生和班级的一对多关系
views.py
from django.shortcuts import render,redirect,HttpResponse
from web import models
from django.forms import Form
from django.forms import fields
from django.forms import widgets
from django.conf import settings
from django.core.validators import ValidationError
from django.core.validators import RegexValidator
# 1、创建规则
class TeacherForm(Form): #必须继承Form
# 创建字段,本质上是正则表达式
username = fields.CharField(
required=True, #必填字段
error_messages={"required":"用户名不能为空!!"}, #显示中文错误提示
widget=widgets.TextInput(attrs={"placeholder":"用户名","class":"form-control"}), #自动生成input框
label="姓名",
label_suffix=":"
)
password = fields.CharField(
required=True,
error_messages={'required': '密码不能为空'},
widget=widgets.PasswordInput(attrs={'placeholder': '密码', 'class': 'form-control'}),
label="密码",
label_suffix=":"
) # 不能为空
email = fields.EmailField(
required=True,
error_messages={"required":"邮箱不能为空!!","invalid":"无效的邮箱"},
widget=widgets.EmailInput(attrs={"placeholder": "邮箱", "class": "form-control"}), # 自动生成input框
label = "邮箱",
label_suffix = ":"
) #不能为空且邮箱格式要一致
teacher_classes = fields.MultipleChoiceField(
label="任教班级",
label_suffix=":",
choices=[] #注意一定要用values_list
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["teacher_classes"].choices = models.Classes.objects.values_list("id", "name")
def clean_name(self):
name = self.cleaned_data["name"]
valid = models.Student.objects.filter(name=name).first()
if valid:
raise ValidationError("用户名已存在")
return name
class LoginForm(Form):
username = fields.CharField(
required=True, #必填字段
min_length=2,
max_length=16,
error_messages={
"required":"用户名不能为空",
"min_length":"长度不能小于3",
"max_length":"长度不能大于16"
},
widget=widgets.TextInput({"placeholder":"username","class":"form-control"})
)
password = fields.CharField(
required=True,
min_length=3,
max_length=16,
error_messages={
"required": "密码不能为空",
"min_length": "密码长度不能小于3",
"max_length": "密码长度不能大于16",
# "invalid":"密码格式错误"
# error_messages的优先级高,如果写上"invalid":"密码格式错误"这个就会优先显示这个错误
},
widget=widgets.PasswordInput({"placeholder":"password","class":"form-control"}),
validators=[RegexValidator("\d+","密码只能是数字")] #可以进行正则匹配提示错误
)
def clean_username(self):
user = self.cleaned_data["username"]
is_exits = models.UserInfo.objects.filter(username=user).count()
if not is_exits:
raise ValidationError("用户名和密码错误")
return user #必须有return
class StudentForm(Form): #必须继承Form
# 创建字段,本质上是正则表达式
name = fields.CharField(
required=True, #必填字段
error_messages={"required":"姓名不能为空!!"}, #显示中文错误提示
widget=widgets.TextInput(attrs={"placeholder":"姓名","class":"form-control"}), #自动生成input框
)
age = fields.CharField(required=True, error_messages={'required': '年龄不能为空'},
widget=widgets.TextInput(attrs={'placeholder': '年龄', 'class': 'form-control'}),validators=[RegexValidator("\d+","只可以是数字")]
) # 不能为空
class_list = models.Classes.objects.all().values_list('id',"name")
cls_id=fields.ChoiceField(choices=class_list)
# 这个方法判断用户名存在不
def clean_name(self):
name = self.cleaned_data["name"] #只能拿自己当前的字段值
valid = models.Student.objects.filter(name=name).first()
if valid:
raise ValidationError("用户名已存在") #主动报错
return name #必须有返回值
# def clean_age(self):
# try:
# int(self.cleaned_data["age"])
# except:
# raise ValidationError("年龄只能为数字")
# return self.cleaned_data["age"]
class ClassesForm(Form):
name = fields.CharField(
required=True, # 必填字段
error_messages={"required": "姓名不能为空!!"}, # 显示中文错误提示
widget=widgets.TextInput(attrs={"placeholder": "姓名", "class": "form-control"}), # 自动生成input框
)
# 如果直接定义成classteacher_id,,_id 的形式,这样你添加数据的时候不会时时更新,所以在下面定义一个重写的方法
# classteacher_id = fields.ChoiceField(choices= models.UserInfo.objects.filter(ut_id = settings.ROLE_CLASSTEACHER).values_list('id', "username"))
classteacher_id = fields.ChoiceField(choices=[])
def __init__(self,*args,**kwargs): #重写init方法,时时更新
super().__init__(*args,**kwargs)
self.fields["classteacher_id"].choices = models.UserInfo.objects.filter(ut_id = settings.ROLE_CLASSTEACHER).values_list('id', "username")
def login(request):
if request.method == "GET":
form = LoginForm()
return render(request, "login.html", {"form": form})
else:
form = LoginForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)
user = models.UserInfo.objects.filter(**form.cleaned_data).first()
if user: #这次是和数据库里的数据进行比较
#验证成功
print(user.username)
request.session[settings.GDP] = {"id":user.id,"username":user.username} #设置session
return redirect("/teacherindex/")
else:
#验证失败,就给增加一个错
form.add_error("password","用户名或密码不正确")
return render(request, "login.html", {"form": form})
else:
return render(request, "login.html", {"form": form})
# 用装饰器的方法实现验证,如果是正确的用户就可以进去主页并且操作,如果不是就进不去主页,还让在登录页面上
# 这个方法可以是可以,但是你的函数要是有成百上千个,那每个都加装饰器是不是就有点费事了。
# 那还有一种更牛逼的方法,那就是中间件。用中间件就可以实现和装饰器一样的功能了
# def auth(func):
# def inner(request, *args, **kwargs):
# user_info = request.session.get("username")
# if not user_info:
# return redirect('/login/')
# return func(request, *args, **kwargs)
# return inner
def teacherindex(request):
teacher_obj = models.UserInfo.objects.filter(ut_id=1)
username = request.session.get("username")
return render(request,"teacherindex.html",{"teacher_obj":teacher_obj,"username":username})
# 2、使用规则:将数据和规则进行匹配
def addteacher(request):
if request.method=="GET":
form = TeacherForm() #只是让显示一个input框
return render(request, "addteacher.html", {"form":form})
else:
print(request.POST,"request.POST")
form = TeacherForm(data=request.POST)
if form.is_valid():# 开始验证
cls_list = form.cleaned_data.pop("teacher_classes")
form.cleaned_data['ut_id'] = 1
#创建新老师的对象
teacher_obj = models.UserInfo.objects.create(**form.cleaned_data)
#创建新老师和班级的关系
teacher_obj.teacher_classes.add(*cls_list) #以前添加的是对象,现在也可以吧id添加进去
return redirect("/teacherindex/")
else:
# print("=====?",form.errors,type(form.errors))#返回失败的结果
# print(form.errors["username"][0]) #拿到返回失败的结果,渲染到页面
return render(request, "addteacher.html", {"form":form})
def editteacher(request,nid):
obj = models.UserInfo.objects.filter(id=nid, ut_id=1).first()
# print(obj.username)
if not obj:
return redirect("/teacherindex/")
if request.method=="GET":
# print([obj.id for obj in obj.teacher_classes.all()],"==") #[2] 拿到select框的id是为了要做默认显示的,获取关联的所有的班级,做默认显示的
print(obj.password,"obj.password")
form = TeacherForm(initial={"username":obj.username,"password":obj.password,"email":obj.email,"teacher_classes":[obj.id for obj in obj.teacher_classes.all()]}) #就让显示一个input框,并且带有原来哪一行的内容
return render(request, "editteacher.html", {"form":form})
else:
form = TeacherForm(data=request.POST)
if form.is_valid():#开始校验,注意这要加括号
cls_list = form.cleaned_data.pop("teacher_classes")
print(cls_list)
models.UserInfo.objects.filter(id=nid).update(**form.cleaned_data)
obj.teacher_classes.set(cls_list) #更新第三张表
return redirect("/teacherindex/")
else:
return render(request, "editteacher.html", {"form":form})
def delteacher(request,nid):
models.UserInfo.objects.filter(id=nid).delete()
return redirect("/teacherindex/")
def studentindex(request):
username = request.session.get("username")
student_obj = models.Student.objects.all()
return render(request,"studentindex.html",{"student_obj":student_obj,"username":username})
def addstudent(request):
if request.method=="GET":
form = StudentForm()
return render(request,"addstudent.html",{"form":form})
else:
form = StudentForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)
models.Student.objects.create(**form.cleaned_data)
return redirect("/studentindex/")
else:
return render(request,"addstudent.html",{"form":form})
def delstudent(request,nid):
models.Student.objects.filter(id=nid).delete()
return redirect("/studentindex/")
def editstudent(request,nid):
if request.method=="GET":
student_obj = models.Student.objects.filter(id=nid).first()
print(student_obj.cls_id)
if not student_obj:
return redirect("/studentindex/")
form = StudentForm(initial={"name":student_obj.name,"age":student_obj.age,"cls_id":student_obj.cls_id}) #这个name是设置的字段名
# form = StudentForm(initial=student_obj.values("name","age").first()) #显示input并且让带有你点击哪一行的数据
return render(request,"editstudent.html",{"form":form})
else:
form = StudentForm(data=request.POST)
if form.is_valid():
models.Student.objects.filter(id=nid).update(**form.cleaned_data)
return redirect("/studentindex/")
else:
return render(request,"editstudent.html",{"form":form})
def classindex(request):
class_obj = models.Classes.objects.all()
username = request.session.get("username")
return render(request,"classindex.html",{"class_obj":class_obj,"username":username})
def delclass(request,nid):
models.Classes.objects.filter(id=nid).delete()
return redirect("/classindex/")
def addclass(request):
if request.method=="GET":
form = ClassesForm()
return render(request,"addclass.html",{"form":form})
else:
form = ClassesForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)
models.Classes.objects.create(**form.cleaned_data)
return redirect("/classindex/")
else:
return render(request,"addclass.html",{"form":form})
def editclass(request,nid):
if request.method == "GET":
class_obj = models.Classes.objects.filter(id=nid).first()
if not class_obj:
return redirect("/classindex/")
form = ClassesForm(initial={"name": class_obj.name,"classteacher_id":class_obj.classteacher_id}) # 这个name是设置的字段名,后面的那个做默认选中
# form = StudentForm(initial=student_obj.values("name","age").first()) #显示input并且让带有你点击哪一行的数据
return render(request, "editclass.html", {"form": form})
else:
form = ClassesForm(data=request.POST)
if form.is_valid():
models.Classes.objects.filter(id=nid).update(**form.cleaned_data)
return redirect("/classindex/")
else:
return render(request, "editclass.html", {"form": form})
def testMD(request):
print("view.test")
return HttpResponse("...")
urls.py
from django.contrib import admin from django.urls import path,re_path from web import views urlpatterns = [ re_path(r'admin/', admin.site.urls), re_path(r'^login/', views.login), # 老师管理 re_path(r'^teacherindex/', views.teacherindex), re_path(r'^addteacher/', views.addteacher), re_path(r'^editteacher/(\d+)', views.editteacher), re_path(r'^delteacher/(\d+)', views.delteacher), # 学生管理 re_path(r'^studentindex/', views.studentindex), re_path(r'^addstudent/', views.addstudent), re_path(r'^delstudent/(\d+)', views.delstudent), re_path(r'^editstudent/(\d+)', views.editstudent), # 班级管理 re_path(r'^classindex/', views.classindex), re_path(r'^addclass/', views.addclass), re_path(r'^delclass/(\d+)', views.delclass), re_path(r'^editclass/(\d+)', views.editclass), # 测试中间件 re_path(r'^test', views.testMD), ]
html
"en"> "UTF-8"> "X-UA-Compatible" content="IE=edge"> "viewport" content="width=device-width">login.htmlTitle
"en"> "UTF-8"> "X-UA-Compatible" content="IE=edge"> "viewport" content="width=device-width">Title
class="c1">base.htmlclass="right"> {% block right %} {% endblock %}
{% extends "base.html" %} {% block right %}欢迎{{ username }}登录
学生信息管理
"/addstudent/">
编号 | 姓名 | 年龄 | 班级 | 操作 |
---|---|---|---|---|
{{ forloop.counter }} | {{ s_obj.name }} | {{ s_obj.age }} | {{ s_obj.cls.name }} | "/editstudent/{{ s_obj.id }}"> "/delstudent/{{ s_obj.id }}"> |
{% extends "base.html" %} {% block right %}欢迎{{ username }}登录
老师信息管理
"/addteacher/">
编号 | 姓名 | 邮箱 | 任教班级 | 操作 | |
---|---|---|---|---|---|
{{ forloop.counter }} | {{ t_obj.username }} | {{ t_obj.email }} | {#{{ t_obj.teacher_classes }} | #} {# 多对多查关联字段#}{% for foo in t_obj.teacher_classes.all %} {{ foo.name }} {% endfor %} | "/editteacher/{{ t_obj.id }}"> "/delteacher/{{ t_obj.id }}"> |
{% extends "base.html" %} {% block right %}欢迎{{ username }}登录
班级信息管理
"/addclass/">
编号 | 姓名 | 班主任 | 操作 | |
---|---|---|---|---|
{{ forloop.counter }} | {{ c_obj.name }} | {{ c_obj.classteacher.username }} | {#{{ t_obj.ut.title }} | #}"/editclass/{{ c_obj.id }}"> "/delclass/{{ c_obj.id }}"> |
{% extends "base.html" %} {% block right %}{% endblock %} addstudent.html
{% extends "base.html" %} {% block right %}{% endblock %} addteacher.html添加老师信息
{% extends "base.html" %} {% block right %}{% endblock %} addclass.html
{% extends "base.html" %} {% block right %}{% endblock %} editstudent
{% extends "base.html" %} {% block right %}{% endblock %} editteacher修改老师信息
{% extends "base.html" %} {% block right %}{% endblock %} editclass
中间件(利用他来做跳转到登录页面)
from django.conf import settings from django.shortcuts import redirect class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, 'process_response'): response = self.process_response(request, response) return response # 至少要有两个类 class Md1(MiddlewareMixin): #必须继承 def process_request(self,request): # print(request.path_info,type(request.path_info),"----------") #str l = ["/login/"] if request.path_info in l: #因为login不做验证,就直接返回none就行了 return None print(request.session,"request.session") if not request.session.get(settings.GDP): return redirect("/login/") # 如果无返回值,就继续执行后续中间件和视图函数 # 如果有返回值,就执行自己的process_response和上面的response, 所以会执行两遍,页面刷新两次 def process_response(self,request,response): # print(response.content.decode("utf8"),"response.content---------------------") return response #必须有返回值 #好像没啥用 class Md2(MiddlewareMixin): def process_request(self,request): print("md2====process_request2") def process_response(self,request,response): print("md2====process_response2") return response
settings.py
""" Django settings for Django1 project. Generated by 'django-admin startproject' using Django 2.1. For more information on this file, see https://docs.djangoproject.com/en/2.1/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/2.1/ref/settings/ """ import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '$)o@fs02(n@f!+!sye+#ch!4#4#re=8f$jwvs0q4jq0adbyo8=' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'web.apps.WebConfig', ] 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', "middle.middle.Md1", # "middle.middle.Md2" ] ROOT_URLCONF = 'Django1.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'Django1.wsgi.application' # Database # https://docs.djangoproject.com/en/2.1/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', #通过这个去链接mysql 'NAME': 's9', 'USER':'root', 'PASSWORD':'2014(zy)', 'HOST':'localhost', 'PORT':'3306', } } # Password validation # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/2.1/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.1/howto/static-files/ STATIC_URL = '/static/' ROLE_TEACHER = 1 ROLE_CLASSTEACHER = 1 GDP="user_info"