Django项目之图书管理系统

发布于:2024-04-29 ⋅ 阅读:(25) ⋅ 点赞:(0)

Django——图书管理系统

一、前期准备

1、创建好 Django 项目

2、准备好数据库 —— 创建数据库:book_system

3、配置项目中的数据库引擎

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'book_system',
        'HOST': '127.0.0.1',
        'USER': 'root',
        'PASSWORD': 'root'
    }
}

4、配置静态文件的搜索路径 , 以及在项目的根目录中创建一个 static 存放静态文件数据文件夹

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]

5、导入 html 模板文件和静态文件数据。

二、用户注册

1、响应用户注册页面的视图

# 路由
# 用户注册视图路由
path('register/' , views.RegisterView.as_view()),


# 响应视图
class RegisterView(View):
    '''
    用户注册页面视图
    '''
    def get(self , request):
        # 响应注册页面
        return render(request , 'register.html')

2、定义用户数据模型类 , 保存用户注册的个人数据信息

class User(models.Model):
    '''
    保存用户注册数据
    '''
    username = models.CharField(max_length=20)
    password = models.IntegerField()
    email = models.EmailField()

3、设置后端对用户注册数据进行验证 , 在对应的应用下创建一个 forms 的模块 , 实现数据验证

class RegisterForm(forms.Form):
    '''
    验证用户注册数据
    '''
    username = forms.CharField(min_length=3 , max_length=15,
                               error_messages={
                                   'min_length':'用户名长度不足',
                                   'max_length':'用户名长度超出',
                                   'required':'用户名不允许为空',
                               })
    password = forms.CharField(min_length=6 , max_length=15,
                               error_messages={
                                   'min_length':'密码长度不足',
                                   'max_length':'密码长度超出',
                                   'required':'密码不允许为空',
                               })
    resetpw = forms.CharField(min_length=6 , max_length=15,
                               error_messages={
                                   'min_length':'密码长度不足',
                                   'max_length':'密码长度超出',
                                   'required':'密码不允许为空',
                               })
    email = forms.EmailField(error_messages={'invalid':'邮箱格式不正确',
                                             'required':'邮箱不允许为空'})

    def clean(self):
        pwd1 = self.cleaned_data.get('password')
        pwd2 = self.cleaned_data.get('resetpw')
        if pwd1 != pwd2:
            self.add_error('resetpw' , '两次密码输入不一致')

        return self.cleaned_data

    def clean_username(self):
        name = self.cleaned_data.get('username')
        if not re.match(r'^[a-zA-Z0-9_]{3,15}$' , name):
            self.add_error('username' , '用户名格式不正确')
        return name

4、在注册视图中接收用户注册传递的数据 , 进行数据验证

class RegisterView(View):
    '''
    用户注册页面视图
    '''
    def get(self , request):
        # 响应注册页面
        return render(request , 'register.html')

    def post(self , request):
        # 接收用户注册输入的数据
        # 传递给 forms 组件进行数据验证
        register_form = RegisterForm(request.POST)
        # 判断 forms 组件是否返回异常信息
        if register_form.is_valid():
            # 说明数据合法 没有异常 , 将用户数据保存到数据库中
            # 用户数据要从 forms 组件中取
            username = register_form.cleaned_data.get('username')
            password = register_form.cleaned_data.get('password')
            email = register_form.cleaned_data.get('email')
            return HttpResponse('用户数据正常')
        else:
            # 用户数据不合法 , 将异常信息返回到前端页面中
            return render(request , 'register.html' , locals())

当用户数据异常不合法的情况下 ,后端将异常请求返回到前端 。在 html 页面中获取后端的异常数据信息

<div class="form-group">
    <i class="fa fa-user" aria-hidden="true"></i>
    用户名:<input class="form-control required" type="text" name="username" id="username" placeholder="请输入用户名" required>
    <span style="color:red;">{{ register_form.username.errors.0 }}</span>
</div>

5、实现图片验证码 , 进行验证用户输入的验证码 ,验证码正确数据保存到数据库中,注册成功;否则用户注册失败。

实现图片验证码的代码,直接使用之前写的。

在当前应用下创建包 —— ImageCode

实现验证码的视图

# 路由
# 图片验证码
path('image_code/' , views.CodeImg),

# 视图
def CodeImg(request):
    # 响应图片验证码视图
    # 获取图片验证码以及验证码数据
    image , text = create_img()
    # session 会话
    # 将验证码数据保存到 session 会话中 , 以键值对的方式保存
    request.session['code'] = text
    # 将图片响应到出现
    return HttpResponse(image , content_type='image/png')

在注册是模板中添加验证码的文本框

<div class="form-group">
    <i class="fa fa-envelope" aria-hidden="true"></i>
    验证码:<input class="form-control required" type="text" name="img_code" id="img_code" placeholder="请输入验证码">
    <img src="/image_code/">
</div>

6、前端数据校验 , 使用 vue 的框架进行数据校验

在标签中绑定数据信息 ,以及对文本框绑定对应的方法

<div class="form-group">
    <i class="fa fa-user" aria-hidden="true"></i>
    用户名:<input class="form-control required" type="text" name="username" id="username" placeholder="请输入用户名"
               required v-model="username" @blur="check_name">
    <span style="color:red;">{{ register_form.username.errors.0 }}</span>
</div>

校验用户名是否重复的视图

# 路由
# 检验用户名是否重复
re_path('count/(?P<username>[a-zA-Z0-9_ ]{3,15})/' , views.username_count),

# 视图
def username_count(request , username):
    # 从数据库获取用户数据
    count = User.objects.filter(username=username).count()
    return JsonResponse({'code':200 , 'errmsg':"OK" , 'count':count})

在静态文件中创建 register.js 文件

let vm = new Vue({
    el:'#app',

    delimiters: ['[[' , ']]'],

    data:{
        username:'',
        password:'',
        resetpw:'',
        image_code_url:'',

        error_name:false,
        error_password:false,
        error_resetpw:false,

        error_name_message:'',
    },

    // 这个方法在 html 页面执行的时候 , 会被自动调用
    mounted(){
        this.image_code();
    },

    methods:{
        // 生成图片验证码
        image_code(){
            // 短时间内路由一致的情况下,会无法响应成功
            // 添加时间参数,保证在短时间内请求的路由不一致
            this.image_code_url = '/image_code/?'+ new Date().getTime()
        },

        // 验证用户名
        check_name(){
            // 定义用户名的规则范围
            let re = /^[a-zA-Z0-9_]{3,15}$/;
            // 判断用户名是否满足定义的规则
            if(re.test(this.username)){
                // 用户名合法
                this.error_name = false;
            } else {
                // 用户名不合法
                this.error_name = true;
                this.error_name_message = '用户名不合法';
            }
            // 判断用户名是否重复
            // 前提保证用户名合法
            if(this.error_name == false){
                // 发送 ajax 请求
                axios.get(
                    '/count/'+this.username+'/',
                    {responseType:'json'}
                )
                    // 请求成功
                    .then(response => {
                        if(response.data.count > 0){
                            // 用户已存在
                            this.error_name = true;
                            this.error_name_message = '用户名已存在';
                        } else {
                            this.error_name = false;
                        }
                    })
                    // 请求失败
                    .catch(error => {
                        console.log(error.response)
                    })
            }
        },

        // 校验密码
        check_password(){
            let re = /^[a-zA-Z0-9_]{6,15}$/;
            if(re.test(this.password)){
                // 密码字符合法
                this.error_password = false;
            } else {
                // 密码字符不合法
                this.error_password = true;
            }
        },

        // 校验两次密码是否一致
        check_resetpw(){
            if(this.password == this.resetpw){
                this.error_resetpw = false;
            } else {
                this.error_resetpw = true;
            }
        },

        // 表单是否允许提交的方法
        on_submit(){
            // 调用所有绑定的方法
            this.check_name();
            this.check_password();
            this.check_resetpw();
            // 判断 error 对应的值是否为 true , 如果其中有一个为 true 则不允许提交
            if(this.error_name == true || this.error_password == true || this.error_resetpw == true){
                // 数据问题 , 禁止表单提交
                window.event.returnValue = false;
            }
        }
    }
})

修改 图片验证码的 html 标签

<div class="form-group">
    <i class="fa fa-envelope" aria-hidden="true"></i>
    验证码:<input class="form-control required" type="img_code" name="img_code" id="img_code" placeholder="请输入验证码">
    <img v-bind:src="image_code_url" class="img_code" @click="image_code">
</div>

7、在注册视图中 , 实现图片验证码的校验 , 验证码校验正确,用户数据保存到数据库中,用户注册成功;否则注册失败。

class RegisterView(View):
    '''
    用户注册页面视图
    '''
    def get(self , request):
        # 响应注册页面
        return render(request , 'register.html')

    def post(self , request):
        # 接收用户注册输入的数据
        # 传递给 forms 组件进行数据验证
        register_form = RegisterForm(request.POST)
        # 判断 forms 组件是否返回异常信息
        if register_form.is_valid():
            # 说明数据合法 没有异常 , 将用户数据保存到数据库中
            # 用户数据要从 forms 组件中取
            username = register_form.cleaned_data.get('username')
            password = register_form.cleaned_data.get('password')
            email = register_form.cleaned_data.get('email')

            # 校验验证码 , 获取用户数输入的验证码
            img_code = request.POST.get('img_code')
            # 从 session 会话中获取保存的验证码
            code = request.session['code']
            if img_code == code:
                # 验证码正确 , 将用户拒数据保存到数据库中,用户注册成功
                User.objects.create(username=username , password=password , email=email)
                # 注册成功重定向首页
                return redirect('/index/')
            else:
                # 验证码错误
                return render(request , 'register.html' , {'code_error':'验证码错误'})
        else:
            # 用户数据不合法 , 将异常信息返回到前端页面中
            return render(request , 'register.html' , locals())

8、实现首页

# 网站首页
path('index/' , views.index),

def index(request):
    # 响应首页
    return render(request , 'index.html')

三、用户登录

响应登录页面数据 , 接收用户登录的数据。

# 用户登录
path('login/' , views.LoginView.as_view()),

class LoginView(View):
    '''
    用户登录视图
    '''
    def get(self , request):
        return render(request , 'login.html')

    def post(self , request):
        # 校验用户输入的数据
        login_form = LoginForm(request.POST)
        if login_form.is_valid():
            username = login_form.cleaned_data.get('username')
            password = login_form.cleaned_data.get('password')
            # 到数据库中进行查询用户数据是否存在
            user = User.objects.filter(username=username , password=password)
            if user:
                # 用户登录成功
                return redirect('/index/')
            else:
                return render(request, 'login.html', {'errormsg': '账号或者密码错误'})
        else:
            return render(request , 'login.html' , {'errormsg':'账号或者密码错误'})

四、出版社信息

1、 定义出版社模型类

class PublishingHouse(models.Model):
    '''
    出版社信息模型类
    '''
    # 出版社名称
    name = models.CharField(max_length=20)
    # 出版社类型
    publisher_type = models.CharField(max_length=15)
    # 出版社成立时间
    create_time = models.DateField()
    # 出版社位置
    address = models.CharField(max_length=30)

2、设置出版社模板页面

{% block main%}
<table border="1" class="table table-hover table-bordered">
    <thead>
        <tr>
            <td>序号</td>
            <td>出版社名称</td>
            <td>出版社类型</td>
            <td>出版社成立时间</td>
            <td>出版社地址</td>
            <td>操作</td>
        </tr>
    </thead>
    <tbody>
        {% for foo in publisher %}
            <tr>
                <td>{{ foo.id }}</td>
                <td>{{ foo.name }}</td>
                <td>{{ foo.publisher_type }}</td>
                <td>{{ foo.create_time }}</td>
                <td>{{ foo.address }}</td>
                <td>
                    <a href="#">修改</a>
                    <a href="#">删除</a>
                </td>
            </tr>
        {% endfor %}
    </tbody>
</table>
{% endblock %}

3、 响应视图

# 出版社列表响应
path('publisher_list/' , views.publisher_list),

# 视图
def publisher_list(request):
    # 响应出版社列表
    # 从数据库中获取出版社的所有信息
    publisher = PublishingHouse.objects.all()
    return render(request , 'publisher_list.html' , locals())

4、添加出版社信息操作

实现添加数据的模板页面

{% block main%}
    <form method="post">
        {% csrf_token %}
        <p>出版社名称<input type="text" name="name"></p>
        <p>出版社类型<input type="text" name="publisher_type"></p>
        <p>出版社成立时间<input type="date" name="create_time"></p>
        <p>出版社地址<input type="text" name="address"></p>
        <p><button type="submit" class="btn">提交</button></p>
    </form>
{% endblock main %}

# 添加出版社数据
path('add_publisher/' , views.AddPublisher.as_view()),

# 视图
class AddPublisher(View):
    '''
    添加出版社数据视图
    '''
    def get(self , request):
        return render(request , 'add_publisher.html')

    def post(self , request):
        name = request.POST.get('name')
        publisher_type = request.POST.get('publisher_type')
        create_time = request.POST.get('create_time')
        address = request.POST.get('address')

        # 将数据保存到数据库中
        PublishingHouse.objects.create(
            name=name,
            publisher_type=publisher_type,
            create_time=create_time,
            address=address
        )
        # 数据保存成功 , 重定向到列表页
        return redirect('/publisher_list/')

5、修改出版社信息

获取要修改的出版社信息 , 要知道是哪个出版社信息需要修改

获取要修改的出版社信息 , 响应到页面中。

重新接收用户修改好的出版社数据保存到数据库中。

实现修改数据模板页

{% block main %}
    <form method="post">
        {% csrf_token %}
        <p>出版社名称<input type="text" name="name" value="{{ edit.name }}"></p>
        <p>出版社类型<input type="text" name="publisher_type" value="{{ edit.publisher_type }}"></p>
        <p>出版社成立时间<input type="date" name="create_time" value="{{ edit.create_time }}"></p>
        <p>出版社地址<input type="text" name="address" value="{{ edit.address }}"></p>
        <p><button type="submit" class="btn">提交</button></p>
    </form>
{% endblock main %}

# 路由
# 修改出版社信息
path('edit_publisher/' , views.EditPublisher.as_view()),

# 视图
class EditPublisher(View):
    '''
    修改出版社信息的视图
    '''
    def get(self , request):
        # 获取用户要修改的出版社信息
        id = request.GET.get('id')
        edit = PublishingHouse.objects.get(id=id)
        return render(request , 'edit_publisher.html' , locals())

    def post(self , request):
        id = request.GET.get('id')
        name = request.POST.get('name')
        publisher_type = request.POST.get('publisher_type')
        create_time = request.POST.get('create_time')
        address = request.POST.get('address')
        edit_data = PublishingHouse.objects.filter(id=id)
        edit_data.update(
            name=name,
            publisher_type=publisher_type,
            create_time=create_time,
            address=address
        )
        return redirect('/publisher_list/')

6、删除出版社信息

# 路由
# 删除出版社信息
path('del_publisher/' , views.del_publisher),

# 视图
def del_publisher(request):
    # 获取要删除的出版社信息:id
    id = request.GET.get('id')
    PublishingHouse.objects.filter(id=id).delete()
    return redirect('/publisher_list/')

五、图书信息

1、图书模型类

class Book(models.Model):
    '''
    图书信息模型类
    '''
    name = models.CharField(max_length=20)
    carrier = models.CharField(max_length=10)
    number_of_words = models.IntegerField()
    publisher_time = models.DateField()
    book_image = models.CharField(max_length=20)
    book_intro = models.CharField(max_length=300)
    price = models.DecimalField(max_digits=5 , decimal_places=2)
    inventory = models.IntegerField()
    publisher = models.ForeignKey(to='PublishingHouse' , on_delete=models.CASCADE)

2、图书列表页

{% block main %}
    <table border="1" class="table table-hover table-bordered">
        <thead>
            <tr>
                <td>序号</td>
                <td>图书名称</td>
                <td>图书价格</td>
                <td>库存</td>
                <td>查询详情</td>
                <td>操作</td>
            </tr>
        </thead>
        <tbody>
            {% for foo in book %}
                <tr>
                    <td>{{ foo.id }}</td>
                    <td>{{ foo.name }}</td>
                    <td>{{ foo.price }}</td>
                    <td>{{ foo.inventory }}</td>
                    <td><a href="/check_book/?id={{ foo.id }}">查看</a></td>
                    <td>
                        <a href="#">修改</a>
                        <a href="#">删除</a>
                    </td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
{% endblock main %}

# 查看图书列表页
path('book_list/' , views.book_list),

def book_list(request):
    book = Book.objects.all()
    return render(request , 'book_list.html' , locals())

3、添加图书数据

{% block main%}
    <form method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <p>图书名称<input type="text" name="name"></p>
        <p>图书载体<input type="text" name="carrier"></p>
        <p>图书字数<input type="text" name="number"></p>
        <p>图书发表时间<input type="date" name="time"></p>
        <p>图书图片<input type="file" name="book_image"></p>
        <p>图书简介<textarea rows="10" cols="20" name="book_intro"></textarea></p>
        <p>图书价格<input type="text" name="price"></p>
        <p>图书库存<input type="text" name="inventory"></p>
        <p>出版社<select multiple name="publisher_id">
            {% for foo in publisher %}
                <option value="{{ foo.id }}">{{ foo.name }}</option>
            {% endfor %}
        </select>
        </p>
        <p><button type="submit" class="btn">提交</button></p>
    </form>
{% endblock main %}

# 添加图书信息
path('add_book/' , views.AddBook.as_view()),

class AddBook(View):
    '''
    添加图书信息
    '''
    def get(self , request):
        # 获取出版社数据
        publisher = PublishingHouse.objects.all()
        return render(request , 'add_book.html' , locals())

    def post(self , request):
        name = request.POST.get('name')
        carrier = request.POST.get('carrier')
        number = request.POST.get('number')
        time = request.POST.get('time')
        book_image = request.FILES.get('book_image')
        book_intro = request.POST.get('book_intro')
        price = request.POST.get('price')
        inventory = request.POST.get('inventory')
        publisher_id = request.POST.get('publisher_id')

        # 在项目的静态文件夹中 , 创建一个文件夹保存图书的图片
        if book_image:
            # 获取文件名
            book_image_name = book_image.name
            # 将图片保存到指定位置
            image_dir = os.path.join(STATICFILES_DIRS[0] , 'book_image' , book_image_name)
            with open(image_dir , 'wb') as f:
                for i in book_image:
                    f.write(i)
                else:
                    book_image = '暂无.jpg'

                    if not book_intro:
                        book_intro = '暂无作品介绍,正在整理中……'

                        Book.objects.create(
                            name=name,
                            carrier=carrier,
                            number_of_words=number,
                            publisher_time=time,
                            book_image=book_image,
                            book_intro=book_intro,
                            price=price,
                            inventory=inventory,
                            publisher_id=publisher_id
                        )
                        return redirect('/book_list/')

4、查看图书详情

{% block main %}
    <h1>图书名称:{{ book.name }}</h1>
    <h2>图书作者:</h2>
    <table border="1" class="table table-hover table-bordered">
        <tr>
            <th>图书简介</th>
            <td>{{ book.book_intro }}</td>
            <th>图书图片</th>
            <td><img src="/static/book_image/{{ book.book_image }}"></td>
        </tr>
        <tr>
            <th>文学载体</th>
            <td>{{ book.carrier }}</td>
            <th>图书字数</th>
            <td>{{ book.number_of_words }}</td>
        </tr>
        <tr>
            <th>发表时间</th>
            <td>{{ book.publisher_time }}</td>
            <th>图书出版社</th>
            <td>{{ book.publisher.name }}</td>
        </tr>
    </table>
{% endblock main %}

# 查看图书详情
path('check_book/' , views.book_particulars),

def book_particulars(request):
    id = request.GET.get('id')
    book = Book.objects.get(id=id)
    return render(request , 'book_particulars.html' , locals())

5、删除图书信息

def del_book(request):
    id = request.GET.get('id')
    Book.objects.filter(id=id).delete()
    return redirect('/book_list/')

6、修改图书信息

class EditBook(View):
    def get(self , request):
        id = request.GET.get('id')
        book = Book.objects.get(id=id)
        publisher = PublishingHouse.objects.all()
        return render(request , 'edit_book.html' , locals())

    def post(self , request):
        id = request.GET.get('id')
        name = request.POST.get('name')
        carrier = request.POST.get('carrier')
        number = request.POST.get('number')
        time = request.POST.get('time')
        book_image = request.FILES.get('book_image')
        book_intro = request.POST.get('book_intro')
        price = request.POST.get('price')
        inventory = request.POST.get('inventory')
        publisher_id = request.POST.get('publisher_id')

        # 在项目的静态文件夹中 , 创建一个文件夹保存图书的图片
        if book_image:
            # 获取文件名
            book_image_name = book_image.name
            # 将图片保存到指定位置
            image_dir = os.path.join(STATICFILES_DIRS[0], 'book_image', book_image_name)
            with open(image_dir, 'wb') as f:
                for i in book_image:
                    f.write(i)
        else:
            book_image = '暂无.jpg'

        if not book_intro:
            book_intro = '暂无作品介绍,正在整理中……'
        edit_data = Book.objects.filter(id=id)
        edit_data.update(
            name=name,
            carrier=carrier,
            number_of_words=number,
            publisher_time=time,
            book_image=book_image,
            book_intro=book_intro,
            price=price,
            inventory=inventory,
            publisher_id=publisher_id
        )
        return redirect('/book_list/')

{% block main%}
    <form method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <p>图书名称<input type="text" name="name" value="{{ book.name }}"></p>
        <p>图书载体<input type="text" name="carrier" value="{{ book.carrier }}"></p>
        <p>图书字数<input type="text" name="number" value="{{ book.number_of_words }}"></p>
        <p>图书发表时间<input type="date" name="time" value="{{ book.publisher_time }}"></p>
        <p>图书图片<input type="file" name="book_image"></p>
        <p>图书简介<textarea rows="10" cols="20" name="book_intro">{{ book.book_intro }}</textarea></p>
        <p>图书价格<input type="text" name="price" value="{{ book.price }}"></p>
        <p>图书库存<input type="text" name="inventory" value="{{ book.inventory }}"></p>
        <p>出版社<select multiple name="publisher_id">
            {% for foo in publisher %}
                <option value="{{ foo.id }}">{{ foo.name }}</option>
            {% endfor %}
        </select>
        </p>
        <p><button type="submit" class="btn">提交</button></p>
    </form>
{% endblock main %}

六、作者信息

1、作者模型类

class Author(models.Model):
    '''
    作者信息
    '''
    # 作者姓名
    name = models.CharField(max_length=15)
    # 作者照片
    author_picture_name = models.CharField(max_length=20)
    # 作者简介
    author_intro = models.CharField(max_length=150)
    # 作者图书
    book = models.ManyToManyField(to='Book')

2、作者列表页响应

{% block main %}
    <table border="1" class="table table-hover table-bordered">
        <thead>
            <tr>
                <td>序号</td>
                <td>作者名称</td>
                <td>作者详情</td>
                <td>操作</td>
            </tr>
        </thead>
        <tbody>
            {% for foo in author %}
                <tr>
                    <td>{{ foo.id }}</td>
                    <td>{{ foo.name }}</td>
                    <td><a href="/check_author/?id={{ foo.id }}">查看</a></td>
                    <td>
                        <a href="/edit_author/?id={{ foo.id }}">修改</a>
                        <a href="/del_author/?id={{ foo.id }}">删除</a>
                    </td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
{% endblock main %}

def author_list(request):
    author = Author.objects.all()
    return render(request , 'author_list.html' , locals())

3、添加作者信息

{% block main%}
    <form method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <p>作者名称<input type="text" name="name"></p>
        <p>作者图片<input type="file" name="author_image"></p>
        <p>作者简介<textarea rows="10" cols="20" name="author_intro"></textarea></p>
        <p>作者作品
            {% for foo in book %}
                <input type="checkbox" value="{{ foo.id }}" name="books">{{ foo.name }}
            {% endfor %}
        </p>
        <p><button type="submit" class="btn">提交</button></p>
    </form>
{% endblock main %}

class AddAuthor(View):
    def get(self , request):
        book = Book.objects.all()
        return render(request , 'add_author.html' , locals())

    def post(self , request):
        name = request.POST.get('name')
        author_intro = request.POST.get('author_intro')
        author_image = request.FILES.get('author_image')
        # 前端中的多选框 , 接受的是一个列表类型的数据
        # getlist 的方式接受
        books = request.POST.getlist('books')
        # 在项目的静态文件夹中 , 创建一个文件夹保存图书的图片
        if author_image:
            # 获取文件名
            author_image_name = author_image.name
            # 将图片保存到指定位置
            image_dir = os.path.join(STATICFILES_DIRS[0], 'author_image', author_image_name)
            with open(image_dir, 'wb') as f:
                for i in author_image:
                    f.write(i)
        else:
            author_image = '暂无.jpg'

        if not author_intro:
            author_intro = '暂无作者介绍,正在整理中……'

        author = Author.objects.create(
            name=name,
            author_picture_name=author_image,
            author_intro=author_intro)
        author.book.set(books)
        return redirect('/author_list/')

4、查看作者详情数据

def check_author(request):
    id = request.GET.get('id')
    author = Author.objects.get(id=id)
    book = Book.objects.filter(author__id=id)
    return render(request , 'check_author.html' , locals())

{% block main %}
    <h1>作者:{{ author.name }}</h1>
    <table border="1" class="table table-hover table-bordered">
        <tr>
            <th>作者简介</th>
            <td>{{ author.author_intro }}</td>
            <th>作者图片</th>
            <td><img src="/static/author_image/{{ author.author_picture_name }}"></td>
        </tr>
    </table>
    <table border="1" class="table table-hover table-bordered">
        <thead>
            <tr>
                <td>作品</td>
            </tr>
        </thead>
        <tbody>
            <tr>
                {% for foo in book %}
                    <td>{{ foo.name }}</td>
                {% endfor %}

            </tr>
        </tbody>
    </table>
{% endblock main %}

5、修改作者信息

{% block main%}
    <form method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <p>作者名称<input type="text" name="name" value="{{ author.name }}"></p>
        <p>作者图片<input type="file" name="author_image"></p>
        <p>作者简介<textarea rows="10" cols="20" name="author_intro">{{ author.author_intro }}</textarea></p>
        <p>作者作品
            {% for foo in book %}
                <input type="checkbox" value="{{ foo.id }}" name="books">{{ foo.name }}
            {% endfor %}
        </p>
        <p><button type="submit" class="btn">提交</button></p>
    </form>
{% endblock main %}

class EditAuthor(View):
    def get(self , request):
        id = request.GET.get('id')
        author = Author.objects.get(id=id)
        book = Book.objects.all()
        return render(request , 'edit_author.html' , locals())

    def post(self , request):
        id = request.GET.get('id')
        name = request.POST.get('name')
        author_intro = request.POST.get('author_intro')
        author_image = request.FILES.get('author_image')
        # 前端中的多选框 , 接受的是一个列表类型的数据
        # getlist 的方式接受
        books = request.POST.getlist('books')
        # 在项目的静态文件夹中 , 创建一个文件夹保存图书的图片
        if author_image:
            # 获取文件名
            author_image_name = author_image.name
            # 将图片保存到指定位置
            image_dir = os.path.join(STATICFILES_DIRS[0], 'author_image', author_image_name)
            with open(image_dir, 'wb') as f:
                for i in author_image:
                    f.write(i)
        else:
            author_image = '暂无.jpg'

        if not author_intro:
            author_intro = '暂无作者介绍,正在整理中……'
        edit_data = Author.objects.get(id=id)
        edit_data.name = name
        edit_data.author_intro = author_intro
        edit_data.author_picture_name = author_image
        edit_data.book.set(books)
        edit_data.save()
        return redirect('/author_list/')

6、删除作者

def del_author(request):
    id = request.GET.get('id')
    Author.objects.filter(id=id).delete()
    return redirect('/author_list/')