上一篇博文是关于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. JQuery DOM操作 、属性和CSS样式操作、其他函数

    DOM操作 1.在div1内部最后追加一个节点 $("#div1").append("<img src='../01-HTML基本标签/img/Male.gif'/ ...

  2. Java面试与回答技巧(1.如何正确的面试)

    在IT行业中,大部分公司很难用有效的方式招到合适的人.直接暴露出来的问题是:・花重金招了一个人,但实际的战斗力还比不上应届毕业生.・招聘了一个知名企业的高管,引入了一些高大上的技术,结果本来稳定的生产 ...

  3. HTML DOM innerHTML 属性及实现图片连续播放

    定义和用法 innerHTML 属性设置或返回表格行的开始和结束标签之间的 HTML. 语法 tablerowObject.innerHTML=HTML 实例 下面的例子返回了表格行的 inner H ...

  4. httpd基础配置和虚拟主机的配置方法

    RedHat6.5  httpd实验的大概步骤 #解包 tar zxf httpd-2.2.17.tar.gz -C /usr/src#切换到目录 cd /usr/src/httpd-2.2.17/# ...

  5. Caused by: android.view.InflateException: Binary XML file line #2: Error inflating class android.sup

    解决:找不到资源文件: 系统会根据分辨率来选择加载不同drawable下文件夹的资源,如果只在一个文件下放了资源文件,不同的分辨率设备的会报错.

  6. Xamarin.Android 使用AsyncTask提示上传动态

    我们有时候会通过WebServices上传数据,如果信息量过大并没有提示,用户会觉得是死机,或是系统崩溃,这时候我们可以用到AsyncTask(异步任务)来提示上传信息,例如:正在上传数据... 这里 ...

  7. Win10 UWP开发系列:解决Win10不同版本的Style差异导致的兼容性问题

    最近在开发一个项目时,遇到了一个奇怪的问题,项目依赖的最低版本是10586,目标版本是14393,开发完毕发布到商店后,很多用户报无法正常加载页面.经查,有问题的都是Win10 10586版本. 我上 ...

  8. .net Core 微服务框架 surging 使用

    surging 是一个分布式微服务框架,提供高性能RPC远程服务调用,采用Zookeeper.Consul作为surging服务的注册中心, 集成了哈希,随机,轮询作为负载均衡的算法,RPC集成采用的 ...

  9. 对C#热更新方案ILRuntime的探究

    转载请标明出处:http://www.cnblogs.com/zblade/ 对于游戏中的热更,目前主流的解决方案,分为Lua(ulua/slua/xlua/tolua)系和ILRuntime代表的c ...

  10. Codeforces Round #483 (Div. 2) C. Finite or not?

    C. Finite or not? time limit per test 1 second memory limit per test 256 megabytes input standard in ...