• django -- ORM实现作者增删改查


    前戏

    前面我们已经实现了出版社的增删改查,书的增删改查,书和出版社的对应关系。现在来写一下作者的增删改查和书的对应关系,那书和作者有什么关系呢?一个作者可以写多本书,一本书可以有多个作者,所以书和作者是多对多的关系,这样的话,我们就需要一张表来记录书和作者的关系,想一下sql语句是怎么创建表的

    -- 创建作者表
    create table author(
         id int primary key auto_increment,
         name varchar(32) not null
         );
    -- 创建作者和书的关系表
    create table author2book(
        id int primary key auto_increment,
        author_id int not null,
        book_id int not null,
        constraint fk_author foreign key (author_id) references author(id) on delete cascade on update cascade,
        constraint fk_book foreign key (book_id) references book(id) on delete cascade on update cascade
         );

    ORM创建表

    使用上面的SQL语句创建表是不是很麻烦,那我们使用ORM创建表怎么创建呢?这里有两种方法

    第一种:自己创建作者表和第三张关系表

    # 作者表
    class Author(models.Model):
        id = models.AutoField(primary_key=True)  # 自增id主键
        name= models.CharField(max_length=32)  # 作者名字
    
    
    # 创建作者和书籍的关系
    class Author2Book(models.Model):
        id = models.AutoField(primary_key=True)
        author = models.ForeignKey(to='Author', on_delete=models.CASCADE)
        book = models.ForeignKey(to='Book', on_delete=models.CASCADE)

    第二种:让ORM帮我们创建第三张关系表

    # 作者表
    class Author(models.Model):
        id = models.AutoField(primary_key=True)  # 自增id主键
        name= models.CharField(max_length=32)  # 作者名字
        books = models.ManyToManyField('Book') # ManyToManyField自动帮我们创建第三张表,只是ORM层面建立的一个多对多的关系,不存在于Author表中

      
      def __str__(self):
      return self.name
     

     books这个字段不会出现在Author表和Book表里,会另外创建一张表来存两者之间的关系,所以写在Author表或Book表里都可以,如果写在Book表里,里面就要写Author了

    我们使用第二种方法来创建数据表,因为如果我们要查作者和书的关系时,第二种方法对象.books就可以查到

    执行完生成数据表的命令后,查看数据库,发现ORM自动给我们生成了第三张表,我们在两张数据表里添加一些数

     

    用ORM查询

    先来看一下数据表里的数据

    作者表

    作者和书的对应关系表

    书表

    添加路由

    url(r'^author_list/', views.author_list),  # 作者列表

    添加对应函数

    def author_list(request):
        # 查询到所有的作者
        author_data = Author.objects.all()
    
        return render(request, 'author_list.html', {'author_list': author_data})

    这里需要说明的是author_data是所有作者的对象,

    print(author_data)  # <QuerySet [<Author: 邹邹>, <Author: 马云>, <Author: 范冰冰>, <Author: 刘亦菲>, <Author: 景甜>]>

    我们去循环author_data

    def author_list(request):
        # 查询到所有的作者
        author_data = Author.objects.all()
        print(author_data)  # <QuerySet [<Author: 邹邹>, <Author: 马云>, <Author: 范冰冰>, <Author: 刘亦菲>, <Author: 景甜>]>
        for author in author_data:
            print(author)  # 取到每个出版社的作者
            print(author.books)  # 是一个ORM提供的桥梁,帮我找对应关系
            print(author.books.all())  # 取到每个作者出版的书籍    取出来的是一个对象

    print('*'*50)

    结果

    <QuerySet [<Author: 邹邹>, <Author: 马云>, <Author: 范冰冰>, <Author: 刘亦菲>, <Author: 景甜>]>
    邹邹        
    appTest01.Book.None
    <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>]>    取出来的是一个对象
    **************************************************
    马云
    appTest01.Book.None
    <QuerySet [<Book: Book object>]>
    **************************************************
    范冰冰
    appTest01.Book.None
    <QuerySet [<Book: Book object>]>
    **************************************************
    刘亦菲
    appTest01.Book.None
    <QuerySet [<Book: Book object>]>
    **************************************************
    景甜
    appTest01.Book.None
    <QuerySet []>
    **************************************************

     在取添加author_list.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>作者列表</title>
    </head>
    <body>
    <table border="1">
        <thead>
        <tr>
            <th>序号</th>
            <th>作者id</th>
            <th>作者姓名</th>
            <th>作者作品</th>
        </tr>
    
        </thead>
        <tbody>
        {% for author in author_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ author.id }}</td>
                <td>{{ author.name }}</td>
                <td style="text-align: center">
                    {% for book in author.books.all %}
                        {% if forloop.last %}
                            《{{ book.title }}》
                        {% else %}
                            《{{ book.title }}》,
                        {% endif %}
    
                    {% empty %}
                        暂无作品
                    {% endfor %}
                </td>
    
            </tr>
    
        {% endfor %}
    
        </tbody>
    </table>
    </body>
    </html>

    代码解释:

    {% for book in author.books.all %} 在前面我们知道 author.books.all()取出来的是一个对象,因为一个作者可能有多个书,所以我们循环这个对象

    {% empty %}也是for循环里的,当循环出的book是一个空对象时,执行下面的代码”暂无作品“

    {% if forloop.last %}表示循环到最后一个执行下面的代码

     添加作者

    获取作者的功能已经实现了,那我们在写个添加作者的功能,添加作者,还要选择书,所以这里涉及了两张表,第一张是author表,第二张是author和book对应关系的那张表,先去添加路由

    url(r'^add_author/', views.add_author),  # 添加作者

    在去添加对应的函数

    # 添加作者
    def add_author(request):
        book_data = Book.objects.all()
        return render(request, 'add_author.html', {"book_list": book_data})

    添加add_author.html文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>添加作者</h1>
        <form action="" method="post">
            <input type="text" name="author_name">
            <select name="books" multiple>
                {% for book in book_list %}
                    <option value="{{book.id }}">{{ book.title }}</option>
                {% endfor %}
    
            </select>
            <input type="submit" value="提交">
        </form>
    </body>
    </html>

    因为一个作者可以有多本书,所以书籍是多选的,在去修改对应的函数

    # 添加作者
    def add_author(request):
        if request.method == 'POST':
            new_author_name = request.POST.get('author_name')  # 这个只能取到一个值
            book_ids = request.POST.getlist('books')  # 这个取多个值,取到的是一个列表
            author_obj = Author.objects.create(name=new_author_name)  #创建新的作者
            # author_obj.books.add(*book_ids)  # 参数是一个一个单独的书籍id值,打散传进去
            author_obj.books.set(book_ids)  # 参数是书籍id值的列表
            return redirect('/author_list/')
    
        book_data = Book.objects.all()
        return render(request, 'add_author.html', {"book_list": book_data})

    因为书籍是多选的,所以可能有多个书的id,所以要用到request.POST.getlist('books')

    author_obj = Author.objects.create(name=new_author_name) 返回的值是作者的名字

    author_obj.books.add(*book_ids)因为只能一个一个接收参数,所以这里需要打散,记得前面要加上表名

    a = [1, 2, 3]
    print(*a)
    
    结果:
    1 2 3

    打散

    author_obj.books.set(book_ids)接收的是一个列表,和上面的效果是一样的

    删除作者

    添加路由

    url(r'^delete_author/', views.delete_author),  # 删除作者

    添加对应的函数

    # 删除作者
    def delete_author(request):
        delete_author_id = request.GET.get('id')
        Author.objects.get(id=delete_author_id).delete()
        return redirect('/author_list/')

    html文件只需要更改下author_list.html里的代码即可

    <td>
         <a href="/delete_author/?id={{ author.id }}">删除</a>
         <a href="/edit_author/?id={{ author.id }}">编辑</a>
    </td>

    编辑作者

    添加路由

    url(r'^edit_author/', views.edit_author),  # 编辑作者

    添加对应的函数

    # 编辑作者
    def edit_author(request):
        edit_author_id = request.GET.get('id')  # 取到要编辑的作者id
        # edit_author_obj = Author.objects.get(id=edit_author_id)  # 取到要编辑的作者对象
        edit_author_obj = Author.objects.filter(id=edit_author_id)[0]  # 取到要编辑的作者对象
    
        if request.method == 'POST':
            new_book_ids = request.POST.getlist('book_ids')
            new_author_name = request.POST.get('author_name')
            edit_author_obj.name = new_author_name
            edit_author_obj.save()
            edit_author_obj.books.set(new_book_ids)  # 修改作者和书的关系表
            return redirect('/author_list/')
        book_data = Book.objects.all()
        return render(request, 'edit_author.html', {'author': edit_author_obj, 'book_list': book_data})

    说明:

    edit_author_obj.books.set(new_book_ids)意思是将这个作者和书的对应关系去掉,然后重新设置对应关系

    添加edit_author.html文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>编辑作者</title>
    </head>
    <body>
    <form action="" method="post">
        <input type="text" name="author_name" value="{{ author.name }}">
        <select name="book_ids" multiple>
            {% for book in book_list %}
                {% if book in author.books.all %}
                    <option selected value="{{ book.id }}">{{ book.title }}</option>
                {% else %}
                    <option value="{{ book.id }}">{{ book.title }}</option>
                {% endif %}
            {% endfor %}
    
        </select>
        <input type="submit" value="提交">
    </form>
    
    </body>
    </html>

    代码解释

    {% if book in author.books.all %} 这里的book是book这个表里的一项,在判断这一项在没在书和作者对应关系的那张表里,如果在,则设置成默认选中的

     上传文件

    上传文件需要在html文件里的form表单里指定  enctype="multipart/form-data"。这样Django才能正常接收文件

    添加路由

    url(r'^upload/', views.upload),  # 上传文件

    添加对应函数

    # 上传文件
    def upload(request):
        if request.method == 'POST':
            file_obj = request.FILES.get('file_name')  # 获取文件
            file_name = file_obj.name  # 取到文件名+后缀
            # 从上传文件对象里一点一点读取数据,写到本地
            with open(file_name, 'wb') as f:
                for line in file_obj:
                    f.write(line)
        return render(request, 'upload.html'

    说明:之前获取提交的数据用的是request.POST.get或者request.GET.get,但是获取文件信息要用request.FILES.get,返回的也是一个字典,key是input输入框里的name属性 

    添加对应的html文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>上传文件</title>
    </head>
    <body>
        <form action="" method="post" enctype="multipart/form-data">
            <input type="file" name="file_name">
            <input type="submit">
        </form>
    </body>
    </html> 

    改版:

    导入settings.py文件

    from django.conf import settings

    如果文件存在,重命名

    # 上传文件
    def upload(request):
        if request.method == 'POST':
            file_obj = request.FILES.get('file_name')  # 获取文件
            file_name = file_obj.name  # 取到文件名+后缀
            # 判断文件是否存在
            if os.path.exists(os.path.join(settings.BASE_DIR, file_name)):
                # 如果存在同名的文件
                name,suffix = file_name.split('.')
                name += '1'
                file_name = name + '.'+ suffix
            # 从上传文件对象里一点一点读取数据,写到本地
            with open(file_name, 'wb') as f:
                for line in file_obj:
                    f.write(line)
        return render(request, 'upload.html')
  • 相关阅读:
    计算机网络复习(二) 应用层
    JavaScript实战笔记(二) 数组去重
    计算机网络复习(一) 基本介绍
    计算机网络复习
    Git学习笔记(一) 常用命令
    Git学习笔记
    Python实战笔记(三) 多线程
    Python实战笔记(二) 网络编程
    Python学习笔记
    XBox360自制系统的更新(Update)
  • 原文地址:https://www.cnblogs.com/zouzou-busy/p/11147472.html
Copyright © 2020-2023  润新知