DjangoORM Django-ORM

Django ORMORM(Object Relational Mapping):对象关系映射,描述Django数据模型类和数据库之间的映射关系,通俗的讲就是让一个类和一个数据库表进行对应,这使ORM在数据库层和业务逻辑层之间起到桥梁作用 。
Django通过类代码描述数据表字段、表间关系等内容,并通过相应命令把类所描述的内容持久化到数据库 。
Django ORM的模式特征Django ORM与数据库映射的关系表现为django中的一个数据模型(Model)映射一个数据库表 。其基本情况是:类映射到数据库表,类的属性映射为数据库表字段,类的实例对象则映射为数据行 。
Django ORM能实现的功能:一是生成数据库表,如数据库表的创建、修改、删除;二是操作数据库表的数据行,如数据行的增删改查 。但不能创建数据库 。
Django ORM使用步骤主要有:

  1. 在项目使用的数据库管理系统中建立数据库 。
  2. 在项目的配置文件settings中设置数据库的连接字符 。
  3. 在应用程序的models文件编写继承于models.Model的数据模型 。
  4. 运行python manage.py makemigrations 和 python manage.py migrate 两个命令生成数据库表 。
  5. 使用django ORM操作数据库表 。
Django ORM的用法数据库连接以MySQL为例,先创建test_orm数据库,在settings文件中配置:
DATABASES = {# 'default': {#'ENGINE': 'django.db.backends.sqlite3',#'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),# }'default': {'ENGINE': 'django.db.backends.mysql','HOST': '127.0.0.1','PORT': '3306','NAME': 'test_orm','USER': 'root','PASSWORD': '1234',}}创建数据模型创建一个group模型,有两个属性,即user和email 。在models.py中输入以下代码,假设在项目中有一个应用名称为employee 。
# 必须导入数据模型相关的模块from django.db import models# 数据模型一定要继承于models.Modelclass Group(models.Model):# group_name为团体名称,CharField为类型,max_length设置最大字符数# verbose_name设置在django Admin管理后台页面上显示的字段名group_name = models.CharField(max_length=32,verbose_name='团体名称')# 团体名称备注group_script = models.CharField(max_length=60,verbose_name='备注')group_name和group_script可以称作模型字段,每个字段在类中表现为一个类属性,根据映射关系,每个类属性映射为一个数据表字段 。
在命令行输入python manage.py makemigrations 和 python manage.py migrate生成数据表 。
DjangoORM Django-ORM

文章插图
Django ORM字段Django ORM字段在models中创建,按照固定格式在数据模型类中建立,主要包括指定字段名的字段类型、字段属性等 。
常用字段类型
  1. CharField:字符类型,必须提供max_length参数,表示字符长度 。verbose_name在Django Admin管理后台是字段的显示名称,可理解为字段别名,SQL层面没有具体体现,对数据库中的字段没有影响 。
    name = models.CharField(max_length=32,verbose_name='名称')
  2. EmailField:邮箱类型,实际上是字符类型,只是提供了邮箱格式的校验 。
    email = models.EmailField(verbose_name='邮箱')
  3. TextField:文本类型,存储大段文本字符串 。
    descript = models.IntegerField(verbose_name='简介')
  4. IntegerField:整数类型 。
    int = models.IntegerField()
  5. DateField:日期字段
    date = models.DateField(auto_now=True,auto_now_add=False)auto_now参数自动保存当前时间,一般用来表示最后修改时间 。在第一次创建记录的时候,django就将auto_now_add字段值自动设置为当前时间,用来表示记录对象的创建时间 。
  6. TimeField:时间字段
    time = models.TimeField(auto_now=False,auto_now_add=False)
  7. DateTimeField:日期时间字段,合并了日期字段与时间字段 。
    datetime = models.DateTimeField(auto_now=False,auto_now_add=False)
  8. FileField:实际上是字符串类型,用来把上传的文件的路径保存在数据库中 。文件上传到指定目录,主要参数upload_to指明上传文件的保存路径,这个路径与django配置文件的MEDIA_ROOT有关 。
    filetest = models.FileField(upload_to = 'tets/')如果MEDIA_ROOT = os.path.join(BASE_DIR,'upload/')这句代码设定MEDIA_ROOT值为/test_orm/upload/,假设在数据表中filetest的值是test.txt,那么文件路径为/test_orm/upload/test/test.txt 。
  9. ImageField
    picture = models.ImageField(upload_to = 'pic/')
常用字段属性
  1. db_index:等于True表示设置此字段为数据库表的索引 。
    title = models.CharField(max_length=32,db_index=True)
  2. unique:等于True表示该字段在数据库表中不能有重复值 。
  3. default:设置字段默认值,如default=’good’ 。
  4. auto_now_add:是DateTimeField、TimeField、DateField的独有属性,等于True表示把新建该记录的时间保存为该字段的值 。
  5. auto_now:是DateTimeField、TimeField、DateField的独有属性,等于True表示每次修改记录时,把当前时间存储到该字段 。
Django ORM基本数据操作通过数据模型的objects属性来提供数据操作的接口 。
  • 增加记录
    # 第一种方式new_emp = models.employee.objects.create(name = "tom",email = "tom123@163.com",dep_id = 66)# 第二种方式new_emp = models.employee(name = "tom",email = "tom123@163.com",dep_id=66)new_emp.save()
  • 删除记录,用filter()过滤出符合条件的记录后调用delete()删除 。
    models.employee.objects.filter(name='张三').delete()
  • 修改记录
    # 将指定条件的记录更新,并更新指定字段的值models.employee.objects.filter(name='tom').update(email='tom1234@163.com')# 修改单条数据obj = models.employee.objects.get(id=66)obj.email = 'tom1234@sine.com'obj.save()
  • 查询
    # 查询全部emp_list = models.employee.objects.all()# 获取单条数据,数据不存在则报错emp=models.employee.objects.get(id=123)# 获取指定条件的记录集emp_group = models.employee.objects.filter(name='张三')
Django ORM数据库操作常用函数下面列举的5个函数的返回值都是QuerySet对象集 。
  • all()函数,返回符合条件的全部记录 。
    objects = models.employee.objects.all()
  • filter()函数,返回指定条件的记录 。filter后面的括号内是过滤条件 。
    objects = models.employee.objects.filter(name='tom')过滤一般用“字段名+双下划线+条件名词” 。
    # 获取name字段包含tom的记录models.employee.objects.filter(name__contains="tom")# 获取name字段包含tom的记录,忽略大小写models.employee.objects.filter(name__icontains="tom")# 获取employee数据表中id=10、20、66的数据models.employee.objects.filter(id__in=[10,20,66])# 获取employee数据表中id不等于10、20、66的数据models.employee.objects.exclude(id__in=[10,20,66])# 获取employee数据表中id大于1且小于10的记录models.employee.objects.filter(id_gt=1,id_lt=10)# 获取employee数据表中id在1~66内的记录models.employee.objects.filter(id_range=[1,66])# 获取employee数据表中birthday字段月份为9的记录models.employee.objects.filter(birthday_month=9)
  • exclude()函数,返回不符合括号内条件的记录,和filter相反 。
    objects = models.employee.objects.exclude(name='tom')
  • order_by()函数,按照括号内的字段排序 。
    objects = models.employee.objects.exclude(name='tom').order_by('name','id')字段名中加-,表示按该字段倒序排序 。如下按name字段倒序排列列表 。
    objects = models.employee.objects.order_by('-name')
  • distinct()函数,去掉记录集合中完全一样的记录再返回 。
    objects = models.employee.objects.filter(name='tom').distinct()
以下三个函数返回其他数据类型,可以理解为特殊的QuerySet类型 。
  • values()函数,返回一个字典类型序列 。
    objects = models.employee.objects.values('id','name','email')<QuerySet[{'id':1,'name':'大华','email':'1@1.com'},{'id':2,'name':'大d','email':'1@2.com'}]>
  • values_list()函数,返回一个元组类型序列,返回一个元组类型序列 。
    objects = models.employee.objects.values_list('id','name','email')<QuerySet[('id':1,'name':'大华','email':'1@1.com'),('id':2,'name':'大d','email':'1@2.com')]>
  • get()、first()、last()返回单个对象,可以理解为返回数据表中的一条记录 。
    # 返回id为1的记录,括号内是过滤条件object1=models.employee.objects.get(id=1)# 返回数据集的第一条记录object2=models.employee.objects.first()# 返回数据集的最后一条记录object3=models.employee.objects.last()# 返回数据集的个数object4=models.employee.objects.count()
样例1:数据库表操作准备工作
  1. 先建立一个test_orm项目 。输入django-admin startproject test_orm,生成项目 。这个test_orm就是项目的根目录,里面包括一个test_orm/项目目录和一个manage.py,里面包括生成django应用程序、数据库表等命令集 。
  2. 在命令行终端输入python manage.py startapp employee,生成一个应用程序 。
  3. 以MySQL作为后台数据库,新建数据库名称为test_orm 。
  4. 如果没有pymysql模块先安装,然后在/test_orm//test_orm/__init__.py文件中输入以下代码,使用pymysql代替Django MySQL客户端模块 。
    import pymysqlpymysql.install_as_MySQLdb()
  5. 在settings里修改配置,一是在INSTALLED_APPS里加入employee,二是在DATABASES里把数据库配置为MySQL类型:
    DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','HOST': '127.0.0.1','PORT': '3306','NAME': 'test_orm','USER': 'root','PASSWORD': '1234',}}
  6. 在models中输入数据模型代码:
    from django.db import models# 员工数据模型(员工数据表)class employee(models.Model):name = models.CharField(max_length=32,verbose_name='姓名')email = models.EmailField(verbose_name='邮箱')# 员工部门,Foreignkey类型,与department表中记录形成多对一关系# on_delete = models.CASCADE表示如果外键所关联的department表中的一条记录被删除# 本表中与这条记录有关的记录将全被删除# 有外键的表是多,关联的表是一# 外键在数据库表中以外键名_id形式命名字段dep = models.ForeignKey(to="department",on_delete=models.CASCADE)# 员工加入的团体,多对多关系group = models.ManyToManyField(to="group")salary = models.DecimalField(max_digits=8, decimal_places=2)info = models.OneToOneField(to="employeeinfo",on_delete=models.CASCADE,null=True)# 部门数据模型(部门数据表)class department(models.Model):dep_name = models.CharField(max_length=32,verbose_name='部门名称')dep_script = models.CharField(max_length=60, verbose_name='备注')# 团体数据表class group(models.Model):group_name = models.CharField(max_length=32,verbose_name='团体名称')group_script = models.CharField(max_length=60,verbose_name='备注')# 员工补充信息数据表class employeeinfo(models.Model):phone = models.CharField(max_length=11)address = models.CharField(max_length=50)
  7. 终端输入python manage.py makemigrations和python manage.py migrate生成数据表,第一个命令对数据模型代码进行检查,出错时返回相关信息,第二个命令真正建立数据表 。
    提示:如果出错,去应用里的migrations里面删除__pycache__和0001_initial即可 。
建立路由与视图函数对应关系Django是在urls中设立路由与视图函数的对应关系 。用户在浏览器地址栏中输入网址,django通过URL配置关系找到对应函数,这个函数接受请求,运行其中的逻辑代码并生成响应发回浏览器,从而完成一次用户业务访问过程 。
为了层次清晰,我们建立两级URL配置文件 。先建一级配置文件,在urls中输入:
urlpatterns = [path('admin/', admin.site.urls),# 用include()函数把二级配置包含进来path('test_orm_old/', include('employee.urls')),]说明:
  • include函数的参数是一个字符串,这个字符串指定二级URL配置文件的位置,用点作为分隔符,并且最后的文件名不包含扩展名 。
  • 如果URL配置文件分级,那么在匹配URL时,要把各级配置文件中URL表达式合并成一个完整的URL表达式进行匹配 。
在employee文件夹下新建一个urls文件,输入:
from django.urls import path,include# 导入视图函数from employee.views import *urlpatterns = [# 操作员工数据表相关URL配置项path('list_employee_old/',list_employee_old),path('add_employee_old/',add_employee_old),path('edit_employee_old/<int:emp_id>/',edit_employee_old),path('del_employee_old/<int:emp_id>/',delete_employee_old),# 操作部门数据表相关URL配置项path('add_dep_old/',add_dep_old),path('list_dep_old/',list_dep_old),path('del_dep_old/<int:dep_id>/',del_dep_old),path('edit_dep_old/<int:dep_id>/',edit_dep_old),# 操作团体数据表相关URL配置项path('add_group_old/',add_group_old),path('list_group_old/',list_group_old),path('del_group_old/<int:group_id>/',del_group_old),path('edit_group_old/<int:group_id>/',edit_group_old),# 操作员工补充信息数据表相关URL配置项path('add_employeeinfo_old/', add_employeeinfo_old),#增加一条用户补充信息(employeeinfo表)path('list_employeeinfo_old/', list_employeeinfo_old),#用户补充信息列表(employeeinfo表)path('del_employeeinfo_old/<int:info_id>/', del_employeeinfo_old),#删除一条用户补充信息(employeeinfo表)path('edit_employeeinfo_old/<int:info_id>/', edit_employeeinfo_old),#修改一条用户补充信息(employeeinfo表)]说明:
  • 以上代码分别建立员工、部门、团体、员工补充信息的增删改查配置项 。path()的两个参数一个用来匹配路径,被称作URL表达式,它匹配网址的方式类似于正则表达式;另一个是视图函数名,在views中定义 。
  • 我们在URL表达式和视图函数名后面都加了_old,因为这是初始版本,没有对页面进行美化,后续会有新样例 。
编写视图函数在urls中建立对应关系后还需建立相应的视图函数,函数名与path第二个参数相同 。
打开views,编写对部门数据表department进行列表查询 。
from django.shortcuts import render,redirect,HttpResponsefrom .models import employee,department,group,employeeinfo# 对部门数据表的增删改查def list_dep_old(request):# 取得数据库表全部记录dep_list = department.objects.all()return render(request,'test_orm_old/list_dep_old.html',{'dep_list':dep_list})说明:
首先导入模块和4个数据模型 。dep_list保存部门表的全部记录,再通过render函数发送给list_dep_old.html 。render有三个参数,第一个request是固定的,第二个是html文件,第三个是字典类型,这个参数传值给html文件,在网页中以模板变量形式放置在相应的位置 。
下面是list_dep_old.html文件的代码,存放在templates/list_dep_old文件夹中 。
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>部门列表</title><script src="http://img.qxzm.cc/220531/0H45225W-1.jpg"></script></head><body><div align="center"><h1>部门列表</h1><hr><div><a href="https://tazarkount.com/test_orm_old/add_dep_old/">增加一条记录</a></div><table border="1"><thead><tr><td>部门名称</td><td>备注说明</td><td colspan="2">操作</td></tr></thead><tbody>{% for dep in dep_list %}<tr><td>{{ dep.dep_name }}</td><td>{{ dep.dep_script }}</td><td><a href="https://tazarkount.com/test_orm_old/del_dep_old/{{ dep.id }}/">删除</a></td><td><a href="https://tazarkount.com/test_orm_old/edit_dep_old/{{ dep.id }}">修改</a></td></tr>{% empty %}<tr><td colspan="4">无相关记录!</td></tr>{% endfor %}</tbody></table></div></body></html>说明:
  • 视图函数传入的变量dep_list是一个QuertSet对象,它是一个数据集,实际包含数据表中一行一行的记录,所以在HTML文件中用{% for dep in dep_list %}取出每一行记录存在dep中,然后通过{{ dep.字段名 }}取出每个字段的值 。
    {% for dep in dep_list %}......{% empty %}是模板标签,是一个循环语句代码块 。
  • <td><a href="https://tazarkount.com/test_orm_old/del_dep_old/{{ dep.id }}/">删除</a></td>中的{{ dep.id }}获取department数据表的id值 。/test_orm_old/与一级URL配置文件/test_orm/test_orm/urls.py中path('test_orm_old/', include('employee.urls'))配置项有关,它匹配path函数的第一个参数;del_dep_old/{{ dep.id }}/与二级URL配置文件/test_orm/employee/urls.py中path('del_dep_old/<int:dep_id>/',del_dep_old)配置项有关,它匹配path函数第一个参数 。可以理解为单击这个a标签,django会用views中的del_dep_old视图函数,这个函数由path函数第二个参数指定 。
总结:实现以上功能需要在urls、views中编写代码,还需建立一个HTML文件:
  • 在一级配置文件的urls中加入path('test_orm_old/', include('employee.urls'))配置项 。
  • 在二级配置文件的urls中加入path('list_dep_old/',list_dep_old)配置项 。
  • 在views中建立视图函数def list_dep_old(request),编写逻辑代码 。
  • 在templates/list_dep_old文件夹下建立list_dep_old.html 。
开启django,地址栏输入http://127.0.0.1:8000/test_orm_old/list_dep_old/
DjangoORM Django-ORM

文章插图
增加部门视图函数add_dep_old()的代码如下:
def add_dep_old(request):# 判断请求方式,如果是post,说明前端页面要提交数据if request.method == 'POST':dep_name = request.POST.get('dep_name')dep_script = request.POST.get('dep_script')if dep_name.strip() == '':return render(request, 'test_orm_old/add_dep_old.html', {'error_info':'部门名称不能为空'})try:# 用create函数新建一条记录,这条记录会自动保存,不用调用save函数p = department.objects.create(dep_name=dep_name,dep_script=dep_script)return redirect('/test_orm_old/list_dep_old/')except Exception as e:return render(request,'test_orm_old/add_dep_old.html',{'error_info':'输入部门名称重复或信息有误'})finally:passreturn render(request,'test_orm_old/add_dep_old.html')说明:
提交数据一般用POST,通过request.POST.get取得HTML文件中form的input标签中的值,request.POST.get函数中的参数就是HTML文件中input标签的name属性 。
代码把request.POST.get取得的值传递给django orm的create函数,生成一条数据记录 。代码中p = department.objects.create(dep_name=dep_name,dep_script=dep_script)也可以用下面两种方式代替:
# 一:obj = department(dep_name=dep_name,dep_script=dep_script)obj.save()# 二:dic = {"dep_name":dep_name,"deo_script":dep_script}department.create(**dic)在生成新的记录之后,通过return redirect('/test_orm_old/list_dep_old/')重定向到部门列表页面;redirect函数的参数是一个字符串,匹配的是URL配置项,不是HTML文件名 。即views的list_deo_old视图函数 。
add_dep_old.html文件:
<html lang="en"><head><meta charset="UTF-8"><title>增加部门</title></head><body><div align="center"><h1>增加部门</h1><hr><form action="" method="post">{% csrf_token %}<input type="hidden" name="id" id="id" value="https://tazarkount.com/read/{{ department.id }}" ><div><label>部门:</label><input type="text" name="dep_name" id="dep_name" ></div><br><div><label>备注:</label><input type="text" name="dep_script" id="dep_script" ></div><br><div><input type="submit" value="https://tazarkount.com/read/保存"></div></form>{{ error_info }}</div></body></html>说明:
form标签中的每个input标签中的输入的值会随着POST请求传给视图函数,视图函数通过request.POST.get('xxx')取得输入的值,xxx是input标签name的值 。
{% csrf_token %}是为了防止CSRF所做的保护,是一种安全机制 。
下面是删除部门记录的视图函数 。根据传入参数,获取id字段等于参数值的记录对象,然后删除这个对象 。视图函数del_dep_old的第二个参数是在urls文件配置项的path函数中定义的 。而path('del_dep_old/<int:dep_id>/', del_dep_old)中的int指明数据类型,dep_id指明视图函数del_dep_old()第二个参数的名称 。参数值来自部门列表文件list_dep_old.html中的{{ dep.id }} 。
def del_dep_old(request,dep_id):dep_object = department.objects.get(id=dep_id)dep_object.delete()return redirect('/test_orm_old/list_dep_old/')视图函数edit_dep_old()实现修改功能 。首先判断请求方式是不是POST,是则通过dep_object=department.objects.get(id=id)取出数据表记录,然后给每一个字段赋值,这些值是POST请求传递过来的 。如果不是POST请求就推断是第一次请求页面,首先根据参数dep_id(来自部门列表文件list_dep_old.html中的{{ dep.id }}取出记录放到变量dep_object中,通过render函数传递到edit_dep_old.html文件中,代码如下:
def edit_dep_old(request, dep_id):if request.method == 'POST':id = request.POST.get('id')# 获取前端页面提交的数据dep_name = request.POST.get('dep_name')dep_script = request.POST.get('dep_script')dep_object = department.objects.get(id=id)# 给字段赋值dep_object.dep_name = dep_namedep_object.dep_script = dep_script# 保存数据到数据表dep_object.save()return redirect('/test_orm_old/list_dep_old/')else:dep_object = department.objects.get(id=dep_id)return render(request,'test_orm_old/edit_dep_old.html',{'department':dep_object})视图函数edit_dep_old通过render(request,'test_orm_old/edit_dep_old.html',{'department':dep_object})传递参数给edit_dep_old.html文件,这个文件部分代码如下:
<html lang="en"><head><meta charset="UTF-8"><title>修改部门</title></head><body><div align="center"><h1>修改部门</h1><hr><form action="" method="post">{% csrf_token %}<input type="hidden" name="id" id="id" value="https://tazarkount.com/read/{{ department.id }}" ><div><label>部门:</label><input type="text" name="dep_name" id="dep_name" value="https://tazarkount.com/read/{{ department.dep_name }}"></div><br><div><label>备注:</label><input type="text" name="dep_script" id="dep_script" value="https://tazarkount.com/read/{{ department.dep_script }}"></div><br><div><input type="submit" value="https://tazarkount.com/read/保存"></div></form>{{ error_info }}</div></body></html>说明:
  • 以上代码与add_dep_old.html相似,只是在input标签中给value属性进行了赋值 。
  • 隐含的input标签用于保存数据库表记录主键id的值,并提供给视图函数修改记录 。
以上是部门数据表增删查改功能的实现,总结如下:
  • 在urls中建立URL与视图函数的一一对应关系 。
  • 在views中建立函数,实现业务逻辑,传递变量给HTML 。
  • 在HTML文件设计网页结构,接收视图函数传递变量,通过模板语言进行渲染,形成用户需要的页面 。

DjangoORM Django-ORM

文章插图

DjangoORM Django-ORM

文章插图

DjangoORM Django-ORM

文章插图
group团体数据库表的增删改查视图函数代码如下:
#团队增删改查def list_group_old(request):group_list=group.objects.all()return render(request,'test_orm_old/list_group_old.html',{'group_list':group_list})def add_group_old(request):if request.method=='POST':group_name=request.POST.get('group_name')group_script = request.POST.get('group_script')if group_name.strip()=='':return render(request, 'test_orm_old/add_group.html', {'error_info': '团队名称不能为空!'})try:group.objects.create(group_name=group_name,group_script=group_script)return redirect('/test_orm_old/list_group_old/')except Exception as e:return render(request, 'test_orm_old/add_group_old.html',{'error_info':'录入团队名称重复或信息有错误!'})finally:passreturn render(request, 'test_orm_old/add_group_old.html')def del_group_old(request,group_id):group_object=group.objects.get(id=group_id)group_object.delete()return redirect('/test_orm_old/list_group_old/')def edit_group_old(request,group_id):if request.method=='POST':id=request.POST.get('id')group_name=request.POST.get('group_name')group_script=request.POST.get('group_script')group_object=group.objects.get(id=id)group_object.group_name=group_namegroup_object.group_script=group_scriptgroup_object.save()return redirect('/test_orm_old/list_group_old/')else:group_object=group.objects.get(id=group_id)return render(request,'test_orm_old/edit_group_old.html',{'group':group_object})以下是list_group_old.html代码:
<html lang="en"><head><meta charset="UTF-8"><title>团队列表</title></head><body><div align="center"><h1>团队列表</h1><hr><div><a href="https://tazarkount.com/test_orm_old/add_group_old/">增加一条记录</a></div><table border="1"><thead><tr><td>团队名称</td><td>备注说明</td><td colspan="2">操作</td></tr></thead><tbody>{% for group in group_list %}<tr><td>{{ group.group_name }}</td><td>{{ group.group_script }}</td><td><a href="https://tazarkount.com/test_orm_old/del_group_old/{{ group.id }}/">删除</a></td><td><a href="https://tazarkount.com/test_orm_old/edit_group_old/{{ group.id }}/">修改</a></td></tr>{% empty %}<tr><td colspan="4">无相关记录!</td></tr>{% endfor %}</tbody></table></div></body></html>以下是add_group_old.html代码:
<html lang="en"><head><meta charset="UTF-8"><title>增加团队</title></head><body><div align="center"><h1>增加团队</h1><hr><form action="/test_orm_old/add_group_old/" method="post">{% csrf_token %}<div><label>团队:</label><input type="text" name="group_name" id="group_name"></div><br><div><label>备注:</label><input type="text" name="group_script" id="group_script"></div><br><div><input type="submit" value="https://tazarkount.com/read/增加"></div></form><div style="color:red;">{{ error_info }}</div></div></body></html>以下是edit_group_old.html代码:
<html lang="en"><head><meta charset="UTF-8"><title>修改团队</title></head><body><div align="center"><h1>修改团队</h1><hr><form action="" method="post">{% csrf_token %}<input type="hidden" name="id" id="id" value="https://tazarkount.com/read/{{ group.id }}" ><div><label>团队:</label><input type="text" name="group_name" id="group_name" value="https://tazarkount.com/read/{{ group.group_name }}"></div><br><div><label>备注:</label><input type="text" name="group_script" id="group_script" value="https://tazarkount.com/read/{{ group.group_script }}"></div><br><div><input type="submit" value="https://tazarkount.com/read/保存"></div></form>{{ error_info }}</div></body></html>employeeinfo员工补充信息表的视图函数代码如下 。employee和employeeinfo两表有一对一关系,实际上相当于一个表分到了两个地方,这样的原因主要是表的字段访问频率不同,因此把访问频率高的字段放在一个表中 。
#employeeinf增删改查def list_employeeinfo_old(request):#员工补充信息列表info_list=employeeinfo.objects.all()return render(request,'test_orm_old/list_employeeinfo_old.html',{'info_list':info_list})def add_employeeinfo_old(request):#增加一条员工补充信息记录if request.method=='POST':phone=request.POST.get('phone')address = request.POST.get('address')if phone.strip()=='':return render(request, 'test_orm_old/add_employeeinfo_old.html', {'error_info': '电话不能为空!'})try:employeeinfo.objects.create(phone=phone,address=address)return redirect('/test_orm_old/list_employeeinfo_old/')except Exception as e:return render(request, 'test_orm_old/add_employeeinfo_old.html',{'error_info':'信息有错误!'})finally:passreturn render(request, 'test_orm_old/add_employeeinfo_old.html')def del_employeeinfo_old(request,info_id):#删除一条员工补充信息记录info_object=employeeinfo.objects.get(id=info_id)info_object.delete()return redirect('/test_orm_old/list_employeeinfo_old/')def edit_employeeinfo_old(request,info_id):#修改一条员工补充信息记录if request.method=='POST':id=request.POST.get('id')phone = request.POST.get('phone')address = request.POST.get('address')info_object=employeeinfo.objects.get(id=id)info_object.phone=phoneinfo_object.address=addressinfo_object.save()return redirect('/test_orm_old/list_employeeinfo_old/')else:info_object=employeeinfo.objects.get(id=info_id)return render(request,'test_orm_old/edit_employeeinfo_old.html',{'info':info_object})以下是list_employeeinfo_old.html代码:
<html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><div align="center"><h1>人员地址电话列表</h1><hr><div><a href="https://tazarkount.com/test_orm_old/add_employeeinfo_old/">增加一条记录</a></div><table border="1"><thead><tr><td>电话</td><td>地址</td><td colspan="2">操作</td></tr></thead><tbody>{% for info in info_list %}<tr><td>{{ info.phone }}</td><td>{{ info.address }}</td><td><a href="https://tazarkount.com/test_orm_old/del_employeeinfo_old/{{ info.id }}/">删除</a></td><td><a href="https://tazarkount.com/test_orm_old/edit_employeeinfo_old/{{ info.id }}/">修改</a></td></tr>{% empty %}<tr><td colspan="4">无相关记录!</td></tr>{% endfor %}</tbody></table></div></body></html>以下是add_employeeinfo_old.html代码:
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><div align="center"><h1>增加用户电话地址</h1><hr><form action="/test_orm_old/add_employeeinfo_old/" method="post">{% csrf_token %}<div><label>电话号码:</label><input type="text" name="phone" id="phone"></div><br><div><label>家庭住址:</label><input type="text" name="address" id="address"></div><br><div><input type="submit" value="https://tazarkount.com/read/增加"></div></form><div style="color:red;">{{ error_info }}</div></div></body></body></html>以下是edit_employeeinfo_old.html代码:
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><div align="center"><h1>修改电话地址</h1><hr><form action="" method="post">{% csrf_token %}<input type="hidden" name="id" id="id" value="https://tazarkount.com/read/{{ info.id }}" ><div><label>电话:</label><input type="text" name="phone" id="phone" value="https://tazarkount.com/read/{{ info.phone }}"></div><br><div><label>地址:</label><input type="text" name="address" id="address" value="https://tazarkount.com/read/{{ info.address }}"></div><br><div><input type="submit" value="https://tazarkount.com/read/保存"></div></form>{{ error_info }}</div></body> </html>employee数据模型的操作employee数据模型中有外键、多对多键、一对一键,对它的数据操作有个别不同之处,以下是员工数据表的删除操作的视图函数:
def list_employee_old(request):emp=employee.objects.all()return render(request,'test_orm_old/list_employee_old.html',{'emp_list':emp})def delete_employee_old(request,emp_id):emp=employee.objects.get(id=emp_id)emp.delete()return redirect('/test_orm_old/list_employee_old')list_employee_old.html文件如下:
<html lang="en"><head><meta charset="UTF-8"><title>员工列表</title></head><body><div align="center"><h1>员工列表</h1><hr><div><a href="https://tazarkount.com/test_orm_old/add_employee_old/">增加一条记录</a></div><table border="1"><thead><tr><td>姓名</td><td>邮件</td><td>薪水</td><td>地址</td><td>部门</td><td>团队</td><td colspan="2">操作</td></tr></thead><tbody>{% for emp in emp_list %}<tr><td>{{ emp.name }}</td><td>{{ emp.email }}</td><td>{{ emp.salary }}</td><td>{{ emp.info.address }}</td><td>{{ emp.dep.dep_name }}</td><td>{% for gp in emp.group.all %}{% if forloop.last %}{{ gp.group_name }}{% else %}{{ gp.group_name }},{% endif %}{% endfor %}</td><td><a href="https://tazarkount.com/test_orm_old/del_employee_old/{{ emp.id }}/">删除</a></td><td><a href="https://tazarkount.com/test_orm_old/edit_employee_old/{{ emp.id }}/">修改</a></td></tr>{% empty %}<tr><td colspan="7">无相关记录!</td></tr>{% endfor %}</tbody></table></div></body></html>说明:
  1. emp_list是视图函数传过来的变量,是一个Django QuerySet对象集,用{% for emp in emp_list %}取出每一个对象放到emp中,这样emp对象称为employee数据模型的实例化对象,外键dep、多对多键group、一对一键info这些关联关系也包含在emp对象中,因为Django ORM会自动把关联关系也放在Query Set对象中 。
  2. 在模板语法{{ emp.dep }}中可通过dep这个外键取得与它关联的department数据表中的一条记录,{{ emp.dep.dep_name }}可取得department数据表中关联的dep_name字段的值 。
  3. 同理{{ emp.group }}通过group这个多对多键可取得group数据表中的相关联的纪录,由于是多对多关系,这些关联的纪录不止一条,所以要用{% for gp in emp.group.all %}把记录一条条取出来放在gp中,这样{{ gp.group_name }}就可显示团体名称了 。
  4. <a href='https://tazarkount.com/read/test_orm_old/del_employee_old/{{ emp.id }}/'>删除</a>中的del_employee_old/{{ emp.id }}/匹配urls文件的配置项path('del_employee_old/<int:emp_id>/',delete_employee_old)语句中path函数的第一个参数 。
增加员工记录视图函数的代码:
def add_employee_old(request):if request.method=="POST":name=request.POST.get("name")email=request.POST.get("email")dep=request.POST.get("dep")info = request.POST.get("info")salary = request.POST.get("salary")groups=request.POST.getlist("group")new_emp=employee.objects.create(name=name,email=email,salary=salary,dep_id=dep,info_id=info)new_emp.group.set(groups)return redirect('/test_orm_old/list_employee_old/')dep_list=department.objects.all()group_list=group.objects.all()info_list = employeeinfo.objects.all()return render(request,'test_orm_old/add_employee_old.html',{'dep_list':dep_list,'group_list':group_list,'info_list':info_list})说明:
  1. employee数据库表有个多对多键group,要用getlist()取值 。
  2. 外键在数据表中产生的字段名为外键名_id 。因此在new_emp=employee.objects.create(name=name,email=email,salary=salary,dep_id=dep,info_id=info)语句中可以直接把变量值赋给dep_id和info_id 。
  3. 多对多键group涉及多个值,因此在生成一条记录new_emp后要通过new_emp.group.set(groups)进行赋值 。
  4. 如果是第一次打开网页需要将dep_list、group_list、info_list变量传递给HTML文件,通过render传到网页,通过语言模板放到select标签供用户使用 。
add_employee_old.html如下:
<html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><div align="center"><h1>增加员工</h1><hr><form action="/test_orm_old/add_employee_old/" method="post">{% csrf_token %}<div><label>姓名:</label><input type="text" name="name" id="name"></div><br><div><label>邮箱:</label><input type="text" name="email" id="email"></div><br><div><label>工资:</label><input type="text" name="salary" id="salary"></div><br><div><label>电话地址:</label><select name="info" id="info">{% for info in info_list %}<option value="https://tazarkount.com/read/{{ info.id}}"> {{ info.phone }}||{{ info.address }}</option>{% endfor %}</select></div><br><div><label>部门:</label><select name="dep" id="dep">{% for dep in dep_list %}<option value="https://tazarkount.com/read/{{ dep.id}}"> {{ dep.dep_name }}</option>{% endfor %}</select></div><br><div><label>团体:</label><select name="group" id="group"multiple="true" >{% for groupin group_list %}<option value="https://tazarkount.com/read/{{ group.id}}"> {{ group.group_name }}</option>{% endfor %}</select></div><br><div><input type="submit" value="https://tazarkount.com/read/增加"></div></form></div></body></html>edit_employee_old函数代码如下:
def edit_employee_old(request,emp_id):if request.method=="POST":id=request.POST.get('id')name=request.POST.get("name")email=request.POST.get("email")dep=request.POST.get("dep")info=request.POST.get("info")groups=request.POST.getlist("group")emp=employee.objects.get(id=id)emp.name=nameemp.email=emailemp.dep_id=depemp.info_id=infoemp.group.set(groups)emp.save()return redirect('/test_orm_old/list_employee_old/')emp=employee.objects.get(id=emp_id)dep_list = department.objects.all()group_list = group.objects.all()info_list = employeeinfo.objects.all()return render(request, 'test_orm_old/edit_employee_old.html',{'emp':emp,'dep_list':dep_list,'group_list':group_list,'info_list':info_list})edit_employee_old.html如下:
<html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><div align="center"><h1>修改员工信息</h1><hr><form action="" method="post">{% csrf_token %}<input type="hidden" name='id' id='id' value=https://tazarkount.com/read/{{ emp.id }}>