第六章 Django数据模型系统(多表操作)

2023-12-13 23:50:46

第一章 Django 基本使用
第二章 Django URL路由系统
第三章 Django 视图系统
第四章 Django 模板系统
第五章 Django 数据模型系统(基本使用)
第六章 Django 数据模型系统(多表操作)
第七章 Django 用户认证与会话技术
第八章 Django CSRF防护



数据模型关系

  • 一对一(OneToOneField)

    一对一关系:是指在数据库中两个表中,数据是一一对应的。例如,一个账户对应着一个联系人,而一个联系人也只对应一个账户

  • 一对多(ForeignKey)

    一对多关系:多个表之间,通过一张表中的数据与另一张表中的多条数据进行匹配。比如,一个班级有多个学生,但每个学生只能属于一个班级

  • 多对一(OneToOneField)

    多对一关系:它是一对一关系的反向操作,即多张表中的数据对应一张表中的一条数据

  • 多对多(ManyToMany)

    多对多关系:就是多张表中的数据与另外一张表中的多条数据进行匹配,典型的例子就是学生和课程的关系,一个学生可以选修多门课程,同时一门课程也可能被多个学生选修

一对一:增删改查

准备工作

增加账户表

# myorm/models.py
from django.db import models

# 定义一个用户表,继承model类
class User(models.Model):
    user = models.CharField(max_length=30) # 定义user字段,并定义为字符串以及设置长度
    name = models.CharField(max_length=30) # 定义name字段,并定义为字符串以及设置长度
    sex = models.CharField(max_length=10) # 定义sex字段,并定义为字符串以及设置长度
    age = models.IntegerField() # 定义age字段,并定义为整型
    label = models.CharField(max_length=100) # 定义label字段,并定义为字符串以及设置长度
    
    class Meta:
        app_label = "myorm" # 指定APP名称
        db_table = 'user'   # 自定义生成的表名
        managed = True     # Django自动管理数据库表
        verbose_name = '用户表'  # 对象的可读名称
        verbose_name_plural = '用户表'  # 名称复数形式
        ordering = ["sex"] # 对象的默认顺序,用于获取对象列表时

    def __str__(self):
        return self.name
    
# 账户表
class accounttable(models.Model):
    account = models.CharField(max_length=20,verbose_name="账户表")
    types = models.CharField(max_length=20,default="账户类型")
    user= models.OneToOneField(User,on_delete=models.CASCADE) # 定义一对一的模型关系

    class Meta:
        app_label = "myorm" # 指定APP名称
        db_table = 'accounttable'
        managed = True
        verbose_name = '账户表'
        verbose_name_plural = '账户表'

    def __str__(self):
        return self.account
python3 manage.py makemigrations
python3 manage.py migrate

image-20231130131401437

image-20231130132207476

注册Django后台管理界面

# myorm/admin.py
from django.contrib import admin
from myorm import models

# Register your models here.

admin.site.register(models.User) # 把User表注册到django的管理后台中
admin.site.register(models.accounttable) # 把accounttable表注册到django的管理后台中

image-20231130131837780

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
urlpatterns = [
    re_path('onemode/$',views.onemode)
]

视图

# myorm/views.py
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse
from myorm.models import User,accounttable
from django.core import serializers

# Create your views here.

def onemode(request):
    if request.method == "GET":
        return render(request, "onemode.html")
    elif request.method == "POST":
        user = request.POST.get('user', '')
        name = request.POST.get('name', '')
        sex = request.POST.get('sex', '')
        age = request.POST.get('age', '')
        label = request.POST.get('label', '')
        account = request.POST.get('account', '')
        types = request.POST.get('types', '')

        new_user, created_user = User.objects.get_or_create(user=user, name=name, sex=sex, age=age, label=label)

        new_account, created_account = accounttable.objects.get_or_create(account=account, types=types, user=new_user)

        if created_user and created_account:
            return HttpResponse("添加成功")
        else:
            return HttpResponse("已存在相同的用户或账户")

网页

<!-- myrom/templates/onemodel.html -->
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>一对一用户增加</title>
    </head>
    <body>
        <form action="" method="post">
            <h1>一对一用户增加</h1>
            用户名:<input type="text" name="user"><br>
            姓名:<input type="text" name="name"><br>
            性别:<select name="sex" required>
                <option value=""></option>
                <option value=""></option>
            </select><br>
            年龄:<input type="text" name="age"><br>
            标签:<input type="text" name="label"><br>
            条件:<input type="text" name="tiaojian"><br>
            ---<br>
            账户:<input type="text" name="account"><br>
            类型:<input type="text" name="types"><br>
            <button type="submit">提交</button>
        </form>        
    </body>
</html>

验证

image-20231130140324756

image-20231130140350955

image-20231130140414126

image-20231130140502813

已有用户增加

路由
# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
urlpatterns = [
    re_path('added/$',views.added)
]
视图
# myorm/views.py
from django.shortcuts import redirect, render, HttpResponse
from myorm.models import User,accounttable


def added(request):
    have_user = User.objects.get(user="wang")
    accounttable.objects.create(user=have_user, account="444444444", types="打工银行4")
    have_user = User.objects.get(user="wang2")
    accounttable.objects.create(user=have_user, account="555555555", types="打工银行5")
    have_user = User.objects.get(user="zhao")
    accounttable.objects.create(user=have_user, account="666666666", types="打工银行4")
    return HttpResponse("已用用户增添成功")
验证

image-20231130142347603

查询分为正向查询以及反向查询

正向:通过用户查到账户信息

反向:通过账户信息查到用户

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
urlpatterns = [
    re_path('onecheck/$',views.onecheck)
]

视图

# myorm/views.py
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse
from myorm.models import User,accounttable
from django.core import serializers
from django.core.exceptions import ObjectDoesNotExist
# Create your views here.

def onecheck(request):
    result = {}
    # 正向查询
    try:
        zheng = User.objects.get(user="wang")
        result['zheng'] = {
            'account': zheng.accounttable.account,
            'types': zheng.accounttable.types,
        }
    except ObjectDoesNotExist:
        result['zheng'] = None

    # 反向查询
    try:
        fan = accounttable.objects.get(user_id=30)
        result['fan'] = {
            'user': fan.user.user,
            'name': fan.user.name,
        }
    except ObjectDoesNotExist:
        result['fan'] = None

    return JsonResponse(result)

验证

image-20231130144338304

image-20231130144406071

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
urlpatterns = [
    re_path('onechange/$',views.onechange)
]

视图

# myorm/views.py
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse
from myorm.models import User,accounttable
from django.core import serializers
from django.core.exceptions import ObjectDoesNotExist
# Create your views here.

def onechange(request):
    cha = User.objects.get(user="three")
    # 修改账户信息
    cha.accounttable.types="管理银行3"
    cha.accounttable.save()
    # 修改用户信息
    cha.age = 100
    cha.save()

    result = {}
    # 修改后查询
    try:
        zheng = User.objects.get(user="three")
        result['修改后查询'] = {
            'account': zheng.accounttable.account,
            'types': zheng.accounttable.types,
            'name':zheng.name,
            'age':zheng.age,
            'label':zheng.label,
            'sex':zheng.sex
        }
    except ObjectDoesNotExist:
        result['zheng'] = None
        
    return JsonResponse(result)

验证

image-20231130151007850

image-20231130151033348

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
urlpatterns = [
    re_path('onedelete/$',views.onedelete)
]

视图

# myorm/views.py
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse
from myorm.models import User,accounttable
from django.core import serializers
from django.core.exceptions import ObjectDoesNotExist
# Create your views here.

def onedelete(request):
    User.objects.filter(user="two").delete()
    return HttpResponse("删除成功")

验证

image-20231130151635623

image-20231130151644537

一对多介绍与定义

在Django中,一对多(OneToMany)关系是常见的模型关系之一。这意味着一个模型的实例可以关联到另一个模型的多个实例

以下是一个简单的示例:

假设你有一个博客系统,其中有三个模型:Author(作者)和 Post(帖子)和评论(Comment)

  • Author 模型代表作者,每个作者可以有多篇帖子。
  • Post 模型代表帖子,每篇帖子都关联到一个作者,而且每篇帖子可以有多个评论。
  • Comment 模型代表评论,每个评论都关联到一篇帖子。

一对多:添加记录并关联

准备工作

# myorm/models.py
from django.db import models

# 作者表
class Author(models.Model):
    name = models.CharField(max_length=100)

    class Meta:
        app_label = "myorm"
        db_table = 'author'
        managed = True
        verbose_name = '作者'
        verbose_name_plural = '作者'

    def __str__(self):
        return self.name

# 帖子表
class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='posts')

    class Meta:
        app_label = "myorm"
        db_table = 'post'
        managed = True
        verbose_name = '帖子'
        verbose_name_plural = '帖子'

    def __str__(self):
        return self.title
# 评论表
class Comment(models.Model):
    text = models.TextField()
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')

    class Meta:
        app_label = "myorm"
        db_table = 'comment'
        managed = True
        verbose_name = '评论'
        verbose_name_plural = '评论'

    def __str__(self):
        return self.text
python3 manage.py makemigrations
python3 manage.py migrate

image-20231130155211917

image-20231130155231878

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
urlpatterns = [
    path('add_post/', views.add_post_view, name='add_post'),
]

视图

# myorm/views.py
from django.shortcuts import render, HttpResponse
from .models import Author, Post,Comment

def add_post_view(request):
    if request.method == 'POST':
        # 从表单获取数据
        title = request.POST.get('title')
        content = request.POST.get('content')
        author_name = request.POST.get('author_name')
        comment_text = request.POST.get('comment_text')


        # 查找作者或创建新作者
        author, created = Author.objects.get_or_create(name=author_name)

        # 创建新帖子并关联到作者
        post = Post.objects.create(title=title, content=content, author=author)

        # 创建帖子的评论
        Comment.objects.create(text=comment_text, post=post)

        return HttpResponse('提交成功')

    return render(request, 'add_post.html')  # 显示添加帖子的表单页面

网页

<!-- myapp/templates/add_post.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Add Post</title>
</head>
<body>
    <h1>Add Post</h1>
    <form method="post" action="{% url 'add_post' %}">
        {% csrf_token %}
        <label for="title">标题:</label>
        <input type="text" name="title" required><br>
        <br>
        <label for="content">内容:</label>
        <textarea name="content" required></textarea><br>
        <br>
        <label for="author_name">作者:</label>
        <input type="text" name="author_name" required><br>
        <br>
        <label for="comment_text">评论:</label>
        <textarea name="comment_text" required></textarea><br>
        <button type="submit">提交</button>
    </form>
</body>
</html>

验证

http://49.232.221.200:8080/myorm/add_post/

image-20231130161228449

image-20231130161237389

image-20231130161401460

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
urlpatterns = [
    path('view_posts/', views.view_posts, name='view_posts'),
]

视图

# myorm/views.py
from django.shortcuts import render
from .models import Author, Post, Comment

def view_posts(request):
    # 正向查询获取所有帖子
    all_posts = Post.objects.all()

    # 正向查询获取所有作者
    all_authors = Author.objects.all()

    # 反向查询获取帖子的所有评论
    post_with_comments = Post.objects.prefetch_related('comments').all()

    # 反向查询获取作者的所有帖子
    author_with_posts = Author.objects.prefetch_related('posts').all()

    return render(request, 'view_posts.html', {
        'all_posts': all_posts,
        'all_authors': all_authors,
        'post_with_comments': post_with_comments,
        'author_with_posts': author_with_posts,
    })

网页

<!-- myapp/templates/view_posts.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>View Posts</title>
</head>
<body>
    <h1>全部作者</h1>
    <ul>
        {% for author in all_authors %}
            <li>{{ author.name }}</li>
        {% endfor %}
    </ul>

    <h1>标题by作者</h1>
    <ul>
        {% for post in all_posts %}
            <li>{{ post.title }} by {{ post.author.name }}</li>
        {% endfor %}
    </ul>

    <h1>标题&评论</h1>
    {% if post_with_comments %}
        <h2>{{ post_with_comments.title }}</h2>
        <ul>
            {% for x in post_with_comments %}
                <li>{{ x.title }}</li>
                <ul>
                {% for comment in x.comments.all %}
                    <li>{{ comment.text }}</li>
                {% endfor %}
                </ul>
            {% endfor %}
        </ul>
    {% else %}
        <p>No posts with comments found.</p>
    {% endif %}

    <h1>作者和标题</h1>
    {% if author_with_posts %}
        <h2>{{ author_with_posts.name }}</h2>
        <ul>
            {% for x in author_with_posts %}
            <li>{{ x.name }}</li>
                <ul>
                {% for post in x.posts.all %}
                    <li>{{ post.title }}</li>
                {% endfor %}
                </ul>
            {% endfor %}
        </ul>
    {% else %}
        <p>No author with posts found.</p>
    {% endif %}
</body>
</html>

验证

http://49.232.221.200:8080/myorm/view_posts/

image-20231130175102834

image-20231130175122273

原始数据

image-20231201095322359

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
urlpatterns = [
    path('view_posts/', views.view_posts, name='view_posts'),
    path('edit_post/', views.edit_post, name='edit_post'),
]

视图

# myorm/views.py
from django.shortcuts import render,redirect
from .models import Author, Post, Comment

def edit_post(request):
    cha = Comment.objects.get(text="世上还是好人多")
    # 修改账户信息
    cha.post.author.name="笔名"
    cha.post.author.save()
    # # 修改用户信息
    cha.post.content = "人人都有笔名"
    cha.post.save()
    cha.text = "地球好人"
    cha.save()

    return redirect('view_posts')  # 重定向到查看帖子的页面或其他页面

def view_posts(request):
    # 正向查询获取所有帖子
    all_posts = Post.objects.all()

    # 正向查询获取所有作者
    all_authors = Author.objects.all()

    # 反向查询获取帖子的所有评论
    post_with_comments = Post.objects.prefetch_related('comments').all()

    # 反向查询获取作者的所有帖子
    author_with_posts = Author.objects.prefetch_related('posts').all()

    return render(request, 'view_posts.html', {
        'all_posts': all_posts,
        'all_authors': all_authors,
        'post_with_comments': post_with_comments,
        'author_with_posts': author_with_posts,
    })

验证

访问:http://49.232.221.200:8080/myorm/edit_post/修改成功后,会跳转至http://49.232.221.200:8080/myorm/view_posts/

image-20231201095551779

image-20231201095615099

说明

是因为做了一对多的ForeignKey,所以cha.post.author.name=“笔名”,cha.post.content = "人人都有笔名"进行修改

image-20231201095650673

原始数据

image-20231201100426287

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
urlpatterns = [
    path('view_posts/', views.view_posts, name='view_posts'),
    path('edit_post/', views.edit_post, name='edit_post'),
    path('delete_post/', views.delete_post, name='delete_post'),
]

视图

# myorm/views.py
from django.shortcuts import render,redirect
from .models import Author, Post, Comment

def delete_post(request):
    Author.objects.filter(name="笔名").delete()
    return redirect('view_posts')  # 重定向到查看帖子的页面或其他页面

def edit_post(request):
    cha = Comment.objects.get(text="世上还是好人多")
    # 修改账户信息
    cha.post.author.name="笔名"
    cha.post.author.save()
    # # 修改用户信息
    cha.post.content = "人人都有笔名"
    cha.post.save()
    cha.text = "地球好人"
    cha.save()

    return redirect('view_posts')  # 重定向到查看帖子的页面或其他页面

def view_posts(request):
    # 正向查询获取所有帖子
    all_posts = Post.objects.all()

    # 正向查询获取所有作者
    all_authors = Author.objects.all()

    # 反向查询获取帖子的所有评论
    post_with_comments = Post.objects.prefetch_related('comments').all()

    # 反向查询获取作者的所有帖子
    author_with_posts = Author.objects.prefetch_related('posts').all()

    return render(request, 'view_posts.html', {
        'all_posts': all_posts,
        'all_authors': all_authors,
        'post_with_comments': post_with_comments,
        'author_with_posts': author_with_posts,
    })

验证

访问:http://49.232.221.200:8080/myorm/delete_post/删除成功后,会跳转至http://49.232.221.200:8080/myorm/view_posts/

image-20231201100530228

image-20231201100549196

多对多介绍、定义

多对多关系介绍和定义:

在数据库设计中,多对多关系表示两个实体之间存在复杂的多对多连接。这种关系通常通过中间表(关联表)来实现,中间表包含两个实体的外键,以建立它们之间的关联。

在 Django 中,多对多关系使用 ManyToManyField 字段来定义。这个字段可以在一个模型中引用另一个模型,建立两者之间的多对多关系。中间表由 Django 自动生成,无需直接定义它

准备工作

创建数据表

# myorm/models.py

from django.db import models

# 学生表
class Student(models.Model):
    name = models.CharField(max_length=100)

    class Meta:
        app_label = "myorm"
        db_table = 'student'
        managed = True
        verbose_name = '学生'
        verbose_name_plural = '学生'

    def __str__(self):
        return self.name
    
# 课程表
class Course(models.Model):
    name = models.CharField(max_length=100)
    students = models.ManyToManyField(Student)

    class Meta:
        app_label = "myorm"
        db_table = 'course'
        managed = True
        verbose_name = '课程'
        verbose_name_plural = '课程'

    def __str__(self):
        return self.name
python3 manage.py makemigrations
python3 manage.py migrate

image-20231201110256487

image-20231201110342973

image-20231201110350320

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
urlpatterns = [
    path('create_cs/', views.create_cs, name='create_cs'),
]

视图

# myorm/views.py
from django.shortcuts import render, get_object_or_404,redirect,HttpResponse
from .models import Course, Student

def create_cs(request):
    if request.method == 'POST':
        student_name = request.POST.get('student_name')
        student, created = Student.objects.get_or_create(name=student_name)
        # 从数据库中获取具有给定名字的学生对象。学生不存在,将创建一个新的学生对象,函数返回一个元组,第一个元素是学生对象,第二个元素是一个布尔值,指示学生是否是新创建的

        course_name = request.POST.get('course_name')
        course, created = Course.objects.get_or_create(name=course_name)
        # 从数据库中获取具有给定名字的课程对象。课程不存在,将创建一个新的课程对象,函数返回一个元组,第一个元素是课程对象,第二个元素是一个布尔值,指示课程是否是新创建的
        
        course.students.add(student)
        # 前面获取或创建的学生对象添加到前面获取或创建的课程对象的学生列表中,因为在 Course 模型中,students 是一个 ManyToManyField,允许多个学生与一个课程相关联,反之亦然。

        return HttpResponse("添加成功")
        # return redirect('course_list')  # 重定向到课程列表页面或其他页面

    return render(request, 'create_cs.html')

网页

<!-- myrom/templates/create_course.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Create Course</title>
</head>
<body>
    <h1>增加学生</h1>
    <form method="post" action="{% url 'create_cs' %}">
        {% csrf_token %}
        <label for="student_name">学生名字:</label>
        <input type="text" name="student_name" required><br>
        {% csrf_token %}
        <label for="course_name">课程名字:</label>
        <input type="text" name="course_name" required>
        <button type="submit">提交</button>
    </form>
</body>
</html>

验证

http://49.232.221.200:8080/myorm/create_cs/

image-20231201131306877

image-20231201131313383

image-20231201131459974

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
from .views import view_course_students

urlpatterns = [
    path('view_course_students/<int:course_id>/', view_course_students, name='view_course_students'),
]

视图

# myorm/views.py
from django.shortcuts import render, get_object_or_404,redirect,HttpResponse
from .models import Course, Student

def view_course_students(request, course_id):
    course = get_object_or_404(Course, id=course_id)
    students = course.students.all()

    return render(request, 'view_course_students.html', {'course': course, 'students': students})

网页

<!-- myrom/templates/view_course_students.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>View Course Students</title>
</head>
<body>
    <h1>那些学生上{{ course.name }}</h1>
    <ul>
        {% for student in students %}
            <li>{{ student.name }}</li>
        {% endfor %}
    </ul>
</body>
</html>

验证

http://49.232.221.200:8080/myorm/view_course_students/6/

image-20231201132803171

image-20231201132438124

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
from .views import view_course_students,edit_student

urlpatterns = [
    path('edit_student/<int:student_id>/', edit_student, name='edit_student'),
]

视图

# myorm/views.py
from django.shortcuts import render, get_object_or_404,redirect,HttpResponse
from .models import Course, Student

def edit_student(request, student_id):
    student = get_object_or_404(Student, id=student_id)

    if request.method == 'POST':
        student.name = request.POST.get('new_name')
        student.save()
        return HttpResponse("修改成功")

    return render(request, 'edit_student.html', {'student': student})

网页

<!-- myrom/templates/edit_student.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改学生</title>
</head>
<body>
    <h1>修改学生</h1>
    <form method="post" action="{% url 'edit_student' student.id %}">
        {% csrf_token %}
        <label for="new_name">新名称:</label>
        <input type="text" name="new_name" value="{{ student.name }}" required>
        <button type="submit">提交</button>
    </form>
</body>
</html>

验证

http://49.232.221.200:8080/myorm/edit_student/8/

image-20231201134406796

image-20231201135001890

image-20231201134344395

image-20231201135053890

image-20231201135043072

路由

# myorm/urls.py
from django.urls import include, path, re_path
from myorm import views
from .views import view_course_students,drop_student
urlpatterns = [
    path('drop_student/<int:course_id>/<int:student_id>/', drop_student, name='drop_student'),
]

视图

# myorm/views.py
from django.shortcuts import render, get_object_or_404,redirect,HttpResponse
from .models import Course, Student

def drop_student(request, course_id, student_id):
    course = get_object_or_404(Course, id=course_id)
    student = get_object_or_404(Student, id=student_id)

    # if request.method == 'POST':
    course.students.remove(student)
    return HttpResponse("删除成功")

    # return render(request, 'drop_student.html', {'course': course})

网页

<!-- myrom/templates/drop_student.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Drop Student</title>
</head>
<body>
    <h1>Drop Student</h1>
    <form method="post" action="{% url 'drop_student' course.id student.id %}">
        {% csrf_token %}
        <p>Are you sure you want to drop {{ student.name }} from {{ course.name }}?</p>
        <button type="submit">Drop</button>
    </form>
</body>
</html>

验证

image-20231201141328592

http://49.232.221.200:8080/myorm/drop_student/6/7/

image-20231201141404338

image-20231201141422419

文章来源:https://blog.csdn.net/weixin_42434700/article/details/134982798
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。