Django基础四<二>(OneToMany和 ManyToMany,ModelForm)

上一篇博文是关于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=‘[email protected]‘,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:

python 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,就有一个简陋的页面了,我们可以添加一些标签最后差不多就是这个样子:

.

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

原文地址:https://www.cnblogs.com/hebilical/p/9093549.html

时间: 2024-10-09 17:09:09

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

Django基础四之模板系统

一 语法   模板渲染的官方文档 关于模板渲染你只需要记两种特殊符号(语法): {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 二 变量 在Django的模板语言中按此语法使用:{{ 变量名 }}. 当模版引擎遇到一个变量,它将计算这个变量,然后用结果替换掉它本身. 变量的命名包括任何字母数字以及下划线 ("_")的组合. 变量名称中不能有空格或标点符号. 深度查询据点符(.)在模板语言中有特殊的含义.当模版系统遇到点("."),它将以这样

Django基础(四)

Django-4 知识预览 分页器(paginator) COOKIE 与 SESSION Django的用户认证 FORM 回到顶部 分页器(paginator) 分页器的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 >>> from django.core.pag

Django基础知识二

别名 url views 写一个对应的reg函数,这个函数进来第一件事应该是给客户端返回一个页面. 所以先写一个Html 这个action写的是/reg/ 然后继续写函数 之所以上面的action处直接写/reg/可以使用,不用写上具体的ip+port是因为 当客户点击submit的时候,浏览器会将前面的Ip和端口自动补全,这个ip和端口是服务器提供的. ======================================= 别名这个操作是在url里写的. 因为url里的地址和html里

Django 基础(二)

1. 多对多表之间的保存 方式一: u2 = User.objects.get(id=2) g2 = Group.objects.get(id=2) u2.group_relation.add(g2) #在关系表中存入关联数据 方式二: name = request.POST.get('name',None) username = request.POST.get('username',None) password = request.POST.get('password',None) gpli

Django基础(二)-视图,template

一.Django Views http请求中产生两个核心对象: http请求:HttpRequest对象 http响应:HttpResponse对象 所在位置:django.http,之前我们用到的参数request就是HttpRequest    检测方法:isinstance(request,HttpRequest) 1.1.HttpRequest对象 path: #请求页面的全路径,不包括域名 method: #请求中使用的HTTP方法的字符串表示.全大写表示.例如 if req.meth

12.Django基础十之Form和ModelForm组件

一 Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确.如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.. Django form组件就实现了上面所述的功能. 总结一下,其实form组件的主要功能如下: 生成页面可用的HTML标签 对用户提交的数据进行校验 保留上次输入内容 普通方式手写注册功能

Django基础十之Form和ModelForm组件

一 Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确.如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.. Django form组件就实现了上面所述的功能. 总结一下,其实form组件的主要功能如下: 生成页面可用的HTML标签 对用户提交的数据进行校验 保留上次输入内容 普通方式手写注册功能

django基础知识 ~ ModelForm

一  语法    froms.py    class ModelForm(forms.ModelForm):      class Meta:         model=modelsname#指定模型         fields=1 "__all__" 全部 #指定字段值                   2 include=[column1,column2] #指定字段                   3 exclude=[column1,colum2] # 排查某些字段 

Python Day19-20(Django基础)

一.Django基础 1.基本配置补充 可以用pycharm一键创建工程和APP 其他常用命令: python manage.py runserver 1.1.1.1:8000 python manage.py startapp appname python manage.py syncdb python manage.py makemigrations python manage.py migrate python manage.py createsuperuser 数据库配置 setting