上一篇博文是关于setting.py文件数据库的配置以及model与数据库表关系,实现了通过操作BlogUser,把BlogUser的信息存入后台数据库中.实际开发中有许多东西是相互联系的,除了数据的显示和存储之外,我们也要理清各种数据对象之间的关系.Django框架定义了三种关系模型:

OneToOne

OneToOne(一对一) :这种对应关系最简单,就是字面的意思一对一.django用OneToOneField来表示这种对应关系.

OneToMany

OneToMany(一对多) :也是常见关系中的一种,现实生活中有很多一对多的关系,例如:学生与书本的关系:一个学生可以有很多本书,但是一本书的持有者一般只有一个.这种关系也比较容易理解,Django用ForeignKey来表示一对多的关系.

ManyToMany

ManyToMany(多对多):这个也很常见,比如学生和任课老师之间的关系.一个学生一般有多个任课老师,任课老师也教授多个学生.Django用ManyToManyField表示多对多的关系

本文主要关注OneToMany和ManyToMany这两中关系.

1 添加model

我们定义一个标签类别的model(例如数学,语文,编程等),再定义一个博客标签model.标签类别对象下面可以有多个博客标签(例如编程类别下面可以分为:C ,C++,C#,Java,Python等),一个博客标签下可以有多个博客.然后再定义一个博客model,一个博客可以有多个标签(这篇博文就贴了Django和python两个标签);

编辑myBlog文件目录下的models.py定义'TagType','BlogTag','Blog'三个model:


class TagType(models.Model):#文章大类
DEL_CHOICES=(
('YES','已停用'),
('NO','正常使用'),
)
typename=models.CharField('类别',max_length=100)
createDate=models.DateTimeField('创建时间',auto_now_add=True)
isdeleted=models.CharField('删除标志',max_length=10,default='NO',choices=DEL_CHOICES)
deleteDate=models.DateTimeField('删除时间',blank=True,null=True)
def __str__(self):
return self.typename class BlogTag(models.Model):#标签子类
DEL_CHOICES=(
('YES','已停用'),
('NO','正常使用'),
)
tagtype=models.ForeignKey(TagType,on_delete=models.SET_NULL,blank=True,null=True)#on_delete=models.SET_NULL删除父级记录时该字段置空,保留记录
tagename=models.CharField('标签名',max_length=100)
createDate=models.DateTimeField('创建时间',auto_now_add=True)
isdeleted=models.CharField('删除标志',max_length=10,default='NO',choices=DEL_CHOICES)
deleteDate=models.DateTimeField('删除时间',blank=True,null=True)
def __str__(self):
return self.tagtype.typename+self.tagename class Blog(models.Model):#博客
title=models.CharField('标题',max_length=200)
tag=models.ManyToManyField(BlogTag)
content=models.TextField('正文',blank=True,null=True)
author=models.ForeignKey(BlogUser,on_delete=models.SET_NULL,blank=True,null=True)
createDate=models.DateTimeField('创建时间',auto_now_add=True)
lastmdfDate=models.DateTimeField('上次修改时间',blank=True,null=True)
def __str__(self):
return self.title +'作者:'+ self.author.username

这里主要说明一下models.ForeignKey()的参数,第一个参数是'一对多'关系中的'一'所对应的类别,BlogTag model的代码段.

tagtype=models.ForeignKey(TagType,on_delete=models.SET_NULL,blank=True,null=True)

的意思就是BlogTag实例的tagtype属性只能指向一个TagType类的实例.在BlogTag的tagtype属性指向同一个TagType类实例的情况下,我们可以创建多个BlogType类的实例.这样就可以实现一个TagType对应多个BlogTag的关系.

Blog model 中的代码段:

tag=models.ManyToManyField(BlogTag)

是指Blog的tag属性指向多个BlogTag的实例,创建Blog实例的时候(ManyToManyField的指向默认是空).



这里需要注意:每次修改或者新增model之后,都要执行python manage.py makemigrationspython manage.py migrate把修改或者新增的model同步到数据库中!

2 TestCase单元测试

数据库同步完成之后,就是做单元测试,不要觉得繁琐,一定要养成这样的习惯!!编辑myBlog文件目录下的tests.py,增加对'TagType','BlogTag','Blog'三个model的测试类(因为这三类是有联系的,我把关于他们的测试都写在了一个测试类里):

class BlogTestCase(TestCase):
def create_test(self):
test_user,created=BlogUser.objects.update_or_create(username='test_blog_user',email='test@.163.com',password='test',gender='M')
print(test_user)
test_type1,created=TagType.objects.update_or_create(typename='数学')#添加数学这个大类
test_type2,created=TagType.objects.update_or_create(typename='编程')#添加编程大类
print(TagType.objects.all())#TagType.objects.all()意思是取当前所有的TagType的实例 mat_test_tag1,created=BlogTag.objects.update_or_create(tagtype=test_type1,tagename='高等数学')
mat_test_tag2,created=BlogTag.objects.update_or_create(tagtype=test_type1,tagename='线性代数')
prm_test_tag1,created=BlogTag.objects.update_or_create(tagtype=test_type2,tagename='python')
prm_test_tag2,created=BlogTag.objects.update_or_create(tagtype=test_type2,tagename='Django')
print(BlogTag.objects.all())
print(BlogTag.objects.filter(tagtype=test_type1))#取高数大类下的所有标签
print(BlogTag.objects.filter(tagtype=test_type2))#取编程大类下的所有标签
test_blog,created=Blog.objects.update_or_create(title='测试博客',author=test_user)#创建测试Blog实例
print(test_blog)
print(test_blog.tag.all())#列出test_blog实例的所有标签
test_blog.tag.add(prm_test_tag1,prm_test_tag2)#为test_blog添加标签
print(test_blog.tag.all())

./manage.py test myBlog.tests.BlogTestCase.create_test 结果如图:.

3 ModelForm

之前的博文说过了自定义form,这里再说另一类:ModelForm.

ModelForm是针对model的一种表单灵活性没有自定义Form那么高.ModelFrom也是Form的子类.编辑

myBlog文件目录下forms.py,

首先要导入Model:

from myBlog.models import Blog, BlogTag, TagType

然后添加下面的代码,针对'TagType','BlogTag','Blog'三个model定义三个form:

class TagTypeForm(forms.ModelForm):
class Meta:
model=TagType#指向TagType这个model
fields=['typename']#前台的input框输入的是内容对应typename字段 class BlogTagForm(forms.ModelForm):
class Meta:
model=BlogTag
fields=['tagtype','tagename'] class BlogForm(forms.ModelForm):
class Meta:
model=Blog
fields=['title','tag','content','author']

4 template模板页面

在template文件目录下新增一个blog.html文件,用来显示form:

<!DOCTYPE html>
<html lang="en" dir="ltr">
{% load static %}
<head>
<meta charset="utf-8">
<title>编辑标签</title>
<script type="text/javascript",src="{% static 'JS/jquery-3.2.1.min.js' %}"> </script>
<script type="text/javascript"> </script>
</head>
<body>
<div class="">
<form class="tag_type_form" action="" method="post">
{% csrf_token %}
{{ type_form }}
<button type="submit" name="sub_btn">添加类别</button>
</form>
</div> <div class="">
<form class="blog_tag_form" action="{% url 'btag' %}" method="post"><!--action="{% url 'btag' %}"是把请求提交到urls.py文件urlpatterns这个list中name='btag'对应的url -->
{% csrf_token %}
{{tag_form}}
<button type="submit" name="tag_btn" id='tag_btn'>添加标签</button>
</form> </div> <div class="">
<h4>现有博客:</h4>
{% for blog in blogs %}
{{blog.title}}<br>
{% endfor %}
</div>
<div class="">
<form class="" action="{% url 'blogedit' %}" method="post">
{% csrf_token %}
{{blog_form}}
<button type="submit" name="button">编辑完成</button>
</form> </div> </body>
</html>

5 views.py定义视图类

还是先导入model和form:

 from myBlog.forms import RegisterForm, TagTypeForm,BlogTagForm,BlogForm#导入我们在forms.py自定义的form表单
from myBlog.models import BlogUser, TagType, BlogTag, Blog

我们后面会用重定向,这里也先一并导入:

from django.http import  HttpResponse,HttpResponseRedirect #导入HttpResponse对象
from django.urls import reverse

然后开始定义视图类:

class TagView(View):
'''处理关于大类别的请求'''
def get(self,request):
template_name='blog.html'
type_form=TagTypeForm()
tag_form=BlogTagForm()
blog_form=BlogForm() blog_tags=BlogTag.objects.all()
blogs=Blog.objects.all()
form_dict={
'type_form':type_form,
'tag_form':tag_form,
'blog_form':blog_form,
'blogs':blogs,
}
return render(request,template_name,form_dict) def post(self,request):
template_name='blog.html'
type_form=TagTypeForm()
tag_form=BlogTagForm()
blog_form=BlogForm()
form=TagTypeForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('tag'))#重定向到urls.py文件中name='tag'的url class BlogTagView(View):
def get(self,request):
pass def post(self,request):
form=BlogTagForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('tag')) class BlogView(View):
"""docstring for BlogView."""
def get(self,request):
pass def post(self,request):
form=BlogForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('tag'))

6 urls.py配置

修改myBlog文件目录下的urls.py文件,导入刚刚定义的视图类.

from myBlog.views import RegisterView, TagView, BlogView, BlogTagView

配置路由,在path()最后添加一个关键字参数name并且赋值:

urlpatterns=[
path('registe',RegisterView.as_view(),name='registe'),
path('tag',TagView.as_view(),name='tag'),#reserve('tag')和页面中{% url 'tag'%}与这个url对应
path('btag',BlogTagView.as_view(),name='btag'),
path('blogedit',BlogView.as_view(),name='blogedit'), ]

是时候检验成果了,python manage.py runserver 8080启动服务,然后访问127.0.0.1:8080/blog/tag,就有一个简陋的页面了,我们可以添加一些标签最后差不多就是这个样子:

.

这个页面是不是太简陋了?我也觉得太丑了.下一篇博文就是关于静态文件,我们可以通过静态文件把这个页面弄得稍微整齐一些!

Django基础四<二>(OneToMany和 ManyToMany,ModelForm)的更多相关文章

  1. Django基础四之测试环境和ORM查询

    Django基础四之测试环境和ORM查询 目录 Django基础四之测试环境和ORM查询 1. 搭建测试环境 1.1 测试环境搭建方法: 1.2 使用测试环境对数据库进行CURD 1.3 返回Quer ...

  2. day 68 Django基础四之模板系统

      Django基础四之模板系统   本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法   模板渲染的官方文档 关 ...

  3. day 54 Django基础四之模板系统

    Django基础四之模板系统   本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法   模板渲染的官方文档 关于模 ...

  4. Django基础(二)

    Django基础(二) http://www.cnblogs.com/wupeiqi/articles/4508271.html

  5. Django基础四之模板系统

    一 语法   模板渲染的官方文档 关于模板渲染你只需要记两种特殊符号(语法): {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 二 变量 在Django的模板语言中按此语法使 ...

  6. 04.Django基础四之模板系统

    一 语法 模板渲染的官方文档 关于模板渲染你只需要记两种特殊符号(语法): {{ }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 二 变量 在Django的模板语言中按此语法使用:{ ...

  7. Django基础(四)

    Django-4 知识预览 分页器(paginator) COOKIE 与 SESSION Django的用户认证 FORM 回到顶部 分页器(paginator) 分页器的使用 1 2 3 4 5 ...

  8. django基础之二

    一.什么是架构? 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演. 对于所有的We ...

  9. Django基础之forms组件中的ModelForm组件

    Django的model form组件 这是一个神奇的组件,通过名字我们可以看出来,这个组件的功能就是把model和form组合起来,先来一个简单的例子来看一下这个东西怎么用:比如我们的数据库中有这样 ...

随机推荐

  1. 在MinGW下编译ffmpeg

    因为需要使用ffmpeg的相关库和执行文件,所以需要编译最新的ffmpeg代码.为了能在编译成Windows native执行程序(需要在.net中调用该执行程序),这里我们使用MinGW. 1,安装 ...

  2. 原生Eclipse下Java服务器调试的一个问题

    当你对Server的配置修改以后,最好到 workspacedir\.metadata\.plugins\org.eclipse.wst.server.core\tmp0目录下把缓存文件给删除了,否则 ...

  3. The note of Developing Innovative Ideas for New Companies Course

    This course is free on the Coursera Site,But it only has English version Threee pieces of the course ...

  4. 使用 Babylon.js 在 HTML 页面加载 3D 对象

    五一 Windwos Blogs 推了一篇博客, Babylon.js v3.2 发布了.因为一直有想要在自己博客上加载 3D 对象的冲动,这两天正好看到了,就动手研究研究.本人之前也并没有接触过 W ...

  5. Python 30分钟入门指南

    Python 30分钟入门指南 为什么 OIer 要学 Python? Python 语言特性简洁明了,使用 Python 写测试数据生成器和对拍器,比编写 C++ 事半功倍. Python 学习成本 ...

  6. C游新官网总结

    从2017年9月18号,我开始独立做C游新官网项目.第一次独立完成项目,压力还是挺大的,毕竟还要自己去写前端,前端我已经忘了差不多了. 做这个网站主要是公司开始转型,开始自己建立渠道倒量,这样网站的S ...

  7. 连接Access数据遇到的问题总览!

    由于要访问一个厂商的access数据,所以要写一个对于access的demo,相对于mysql.sqlserver来说,连接access花费了不少精力,现在将遇到的问题分享出来,以后大家遇到类似问题时 ...

  8. PAT1002:A+B for Polynomials

    1002. A+B for Polynomials (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue T ...

  9. selenium+python自动化测试

    F12: 右键   选择复制  path 在selenium+python自动化测试(一)–环境搭建中,运行了一个测试脚本,脚本内容如下: from selenium import webdriver ...

  10. ajax如何实现、readyState五中状态的含义

    转载:http://www.cnblogs.com/teroy/p/3917439.html 熟悉web开发的程序员想必对Ajax也不会陌生.现在已经有很多js框架封装了ajax实现,例如JQuery ...