Python-S9——Day84-ORM项目实战之权限、form以及modelform

  • 01 权限菜单显示

  • 02 Django路径的自动添加问题

  • 03 原生form实现增删改查

  • 04 modelform实现增删改查

01 权限菜单显示

1.1 优先查找项目中的templates,如果没有,然后再去查找应用中的templates下的模板文件;

 1.1.2 如果每个应用下都有相同名称的templates或者templatetags,会根据应用的创建顺序进行查找;

 1.1.3 为避免以上情况发生,建议在templates或者templatestags目录下分别建立应用名称,然后再放置.html模板文件或者my_tag.py文件;

整个项目的完整目录结构:

总结一下整个项目的开发流程:

  • 使用Pycharm创建项目,进行项目的命名
  • 使用Pycharm下的Tools》Run manage.py task启动shell窗口
  • startapp app01
  • startapp rbac(Role-Based Access Control,即基于角色的访问权限控制)详情见:https://baike.baidu.com/item/RBAC/1328788?fr=aladdin
  • settings.py配置文件进行TEMPLATES以及INSTALLED_APPS的添加配置;
  • urls.py的配置;
  • app01/views.py的配置;
  • rbac/models.py的配置并进行数据库迁移操作 makemigrationsmigrate
  • rbac/admin.py的注册配置,并引入class类;
  • 进行程序的解耦合操作,进行rbac/service/permissions.py以及rbac/service/rbac.py的配置;
  • 进行自定义templatetags的自定义,my_tags.py的配置;
  • 分别添加base.html menu.html users.html roles.html 等模板文件,进行extends、include、block等方法进行关联;
  • 将基础模板文件从根目录的templates目录迁移至rbac/templates目录下

settings.py

"""
Django settings for s9day82_rbac project.

Generated by 'django-admin startproject' using Django 1.11.1.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '0s(th#!ewf^xik5n&bqkqqjadz#q*vt+!hq(kzk5*-!t6@^0^i'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'rbac.apps.RbacConfig',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'rbac.service.rbac.ValidPermission',
]
from django.middleware.security import SecurityMiddleware

ROOT_URLCONF = 's9day82_rbac.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 's9day82_rbac.wsgi.application'

# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'

urls.py

"""s9day82_rbac URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^users/$', views.users),
    url(r'^users/add', views.add_user),
    url(r'^users/delete/(d+)', views.del_user),
    url(r'^roles/', views.roles),
    url(r'^login/', views.login),
]

views.py

import re
from django.shortcuts import render, HttpResponse

# Create your views here.

from rbac.models import *
from rbac.service.permissions import *


class Per(object):
    def __init__(self, actions):
        self.actions = actions

    def add(self):
        return "add" in self.actions

    def delete(self):
        return "delete" in self.actions

    def edit(self):
        return "edit" in self.actions

    def list(self):
        return "list" in self.actions


def users(request):
    user_list = User.objects.all()
    # permission_list = request.session.get("permission_list")
    # print(permission_list)  # ['/users/', '/users/add', '/users/delete/(\d+)', '/users/edit/(\d+)']
    # 查询当前登录人的名字;
    id = request.session.get("user_id")
    user = User.objects.filter(id=id).first()
    per = Per(request.actions)
   
    return render(request, "users.html", locals())


def add_user(request):
    return HttpResponse("Add User......")


def del_user(request, id):
    return HttpResponse("Delete User..." + id)


def roles(request):
    role_list = Role.objects.all()
    per = Per(request.actions)
    return render(request, "roles.html", locals())


def login(request):
    if request.method == "POST":
        user_obj = request.POST.get("user")
        pwd = request.POST.get("pwd")
        user = User.objects.filter(name=user_obj, pwd=pwd).first()
        if user:
            # #################在session中注册用户ID###########################;
            request.session["user_id"] = user.pk
            initial_session(user, request)
            '''
            此处的values()相当于:
            temp = []#定义一个空列表;
            for role in user.roles.all();#values属性,相当于循环该对象[<Role: 保洁>, <Role: 销售>]>
                temp.append({
                "title":role.title,
                "permissions__url":role.permissions.all()
                })
            '''
            return HttpResponse("登录成功!")
    return render(request, "login.html")

permissions.py

def initial_session(user, request):
    # 方案1
    # #################在session注册权限列表###########################;
    # 查询当前登录用户的所有角色;
    # ret = user.roles.all()
    # print("ret", ret)  # <QuerySet [<Role: 保洁>, <Role: 销售>]>
    #
    # # 查询当前用户的所有权限;
    # permissions = user.roles.all().values(
    #     "permissions__url").distinct()  # ret_role <QuerySet [{'permissions__url': '/users/'},
    # #  {'permissions__url': '/users/add'}]>
    #
    # # 进行数据的处理,生成列表;
    # permission_list = []
    # for item in permissions:
    #     permission_list.append(item["permissions__url"])
    # print("permission_list", permission_list)  # permission_list ['/users/', '/users/add']
    #
    # request.session["permission_list"] = permission_list

    # 方案2;
    permissions = user.roles.all().values("permissions__url", "permissions__group_id", "permissions__action").distinct()
    print("permissions   ", permissions)  # <QuerySet [{'permissions__url': '/users/',
    # 'permissions__group_id': 1, 'permissions__action': 'list'}]>
    permission_dict = {}
    for item in permissions:
        gid = item.get('permissions__group_id')
        if not gid in permission_dict:

            permission_dict[gid] = {
                "urls": [item["permissions__url"], ],
                "actions": [item["permissions__action"], ]
            }
        else:
            permission_dict[gid]["urls"].append(item["permissions__url"])
            permission_dict[gid]["actions"].append(item["permissions__action"])
    print(permission_dict)
    request.session["permission_dict"] = permission_dict
    # 注册菜单权限;
    permissions = user.roles.all().values("permissions__url", "permissions__action",
                                          "permissions__group__title").distinct()
    print("permissions", permissions)
    menu_permission_list = []
    for item in permissions:
        if item["permissions__action"] == "list":
            menu_permission_list.append((item["permissions__url"], item["permissions__group__title"]))
    print(menu_permission_list)
    request.session["menu_permission_list"] = menu_permission_list

admin.py

from django.contrib import admin

# Register your models here.

from .models import *


class PerConfig(admin.ModelAdmin):
    list_display = ["title", "url", "group", "action"]


admin.site.register(User)
admin.site.register(Role)
admin.site.register(Permission, PerConfig)
admin.site.register(PermissionGroup)

rbac.py

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirect
import re


 # 自定义中间件!
class ValidPermission(MiddlewareMixin):
    def process_request(self, request):
        # 当前访问权限;
        current_path = request.path_info
        # 1、校验权限,是否是与白名单;
        valid_url_list = ["/login/", "/reg/", "/admin/.*"]
        for valid_url in valid_url_list:
            ret = re.match(valid_url, current_path)
            if ret:
                return None
        user_id = request.session.get("user_id")
        if not user_id:
            return redirect("/login/")
        # # 2、判断是否登录
        # permission_list = request.session.get(
        #     "permission_list",
        #     [])  # permission_list ['/users/', '/users/add', '/users/delete/(\d+)', '/users/edit/(\d+)']
        #
        # flag = False
        # for permission in permission_list:
        #     permission = "^%s$" % permission
        #     ret = re.match(permission, current_path)
        #     if ret:
        #         flag = True
        #         break
        # if not flag:
        #
        # return None
        #   3、校验是否登录;
        permission_dict = request.session.get("permission_dict")
        for item in permission_dict.values():
            urls = item['urls']
            for reg in urls:
                reg = "^%s$" % reg
                ret = re.match(reg, current_path)
                if ret:
                    print("actions", item['actions'])
                    request.actions = item['actions']
                    return None
        return HttpResponse("没有访问权限!")

models.py

from django.db import models


# Create your models here.

class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    roles = models.ManyToManyField(to="Role")

    def __str__(self):
        return self.name


class Role(models.Model):
    title = models.CharField(max_length=32)
    permissions = models.ManyToManyField(to="Permission")

    def __str__(self):
        return self.title


class Permission(models.Model):
    title = models.CharField(max_length=32)
    url = models.CharField(max_length=32)
    action = models.CharField(max_length=32, default="")
    group = models.ForeignKey("PermissionGroup", default=1)

    def __str__(self):
        return self.title


class PermissionGroup(models.Model):
    title = models.CharField(max_length=32)

    def __str__(self):
        return self.title

base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <style>
        .header {
            width: 100%;
            height: 60px;
            background-color: #336699;

        }

        .menu {
            background-color: bisque;
            position: fixed;
            top: 60px;
            bottom: 0;
            left: 0;
            width: 200px;
        }

        .content {
            position: fixed;
            top: 60px;
            bottom: 0;
            right: 0;
            left: 200px;
            overflow: auto;
            padding: 30px;
        }

        .menu_btn {
            font-size: 18px;
            text-align: center;
            padding: 50px 0;
        }
    </style>
</head>
<body>
<div class="header">
    <p>{{ user.name }}</p>
</div>
<div class="contain">
    {% load my_tags %}
    <div class="menu">
        {% get_menu request %}
    </div>
    <div class="content ">
        {% block con %}

        {% endblock %}
    </div>

</div>
</body>
</html>

menu.html

<div>
    {% for item  in menu_permission_list %}
        <p class="menu_btn"><a href="{{ item.0 }}">{{ item.1 }}</a></p>
    {% endfor %} 
</div>

users.html

{% extends 'base.html' %}
{% block con %}
    <h4>用户列表</h4>
    {% if per.add  %}
        <a href="/users/add/" class="btn btn-primary">添加用户</a>
    {% endif %}

    <table class="table table-bordered table-striped">
        <thead>
        <tr>
            <th>序号</th>
            <th>姓名</th>
            <th>角色</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>

        {% for user in user_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ user.name }}</td>
                <td>
                    {% for role in user.roles.all %}
                        {{ role.title }}
                    {% endfor %}
                </td>
                <td>
                    {% if per.delete %}
                        <a href="/users/delete/{{ user.pk }}" class="btn btn-danger">删除</a>
                    {% endif %}
                    {% if per.edit %}
                        <a href="/users/edit/{{ user.pk }}" class="btn btn-info">编辑</a>
                    {% endif %}
                </td>
            </tr>
        {% endfor %}

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

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h4>登录页面</h4>

<form action="" method="post">
    {% csrf_token %}
    用户名:<input type="text" name="user">
    密码:<input type="password" name="pwd">
    <input type="submit">
</form>
</body>
</html>

my_tags.py

from django import template

register = template.Library()


@register.inclusion_tag("menu.html")
def get_menu(request, ):
    # 获取当前用户可以放到菜单栏中的权限;
    menu_permission_list = request.session["menu_permission_list"]
    return {"menu_permission_list": menu_permission_list}

02 Django路径的自动添加问题

2.1 settings.py文件中,APPEND_SLASH默认值为True;

2.2 在setings.py中,将APPEND_SLASH调整为False;

#设置项是否开启URL访问地址后面不为/跳转至带有/的路径;

03 原生form实现增删改查

3.1 创建Django项目并制定Python解释器下安装的Django==“1.11.1” version;

3.2 基于form实现的图书管理系统的增删改查步骤;

  • 创建django项目并指定app及Python内置解释器;
  • 检查settings.py是否配置了TEMPLATES以及INSTALLED_APPS;
  • 配置urls.py;
  • 编写视图函数views.py;
  • 编写ORM——models.py;
  • 进行admin.py的注册;
  • 通过Pycharm下的Run manage.py task进行数据库的迁移以及createsuperuser操作;
  • 编写模板——add.htmlooks.htmledit.html;

urls.py;

"""FormsDemo URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^books/', views.books),
    url(r'^book/add', views.add_book),
    url(r'^book/edit/(d+)', views.edit_book),
]

views.py;

from django.shortcuts import render, redirect

# Create your views here.
from .models import *


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


def add_book(request):
    if request.method == "POST":
        title = request.POST.get("title")
        price = request.POST.get("price")
        date = request.POST.get("date")
        publish_id = request.POST.get("publish_id")
        author_pk_list = request.POST.getlist("author_pk_list")
        book_obj = Book.objects.create(title=title, price=price, date=date, publish_id=publish_id)
        book_obj.authors.add(*author_pk_list)
        return redirect('/books/')

    publish_list = Publish.objects.all()
    author_list = Author.objects.all()
    return render(request, "add.html", locals())


def edit_book(request, edit_book_id):
    if request.method == "POST":
        title = request.POST.get("title")
        price = request.POST.get("price")
        date = request.POST.get("date")
        publish_id = request.POST.get("publish_id")
        author_pk_list = request.POST.getlist("author_pk_list")

        Book.objects.filter(pk=edit_book_id).update(title=title, price=price, date=date, publish_id=publish_id)
        book_obj = Book.objects.filter(pk=edit_book_id).first()
        book_obj.authors.set(author_pk_list)
        return redirect('/books/')
    edit_book = Book.objects.filter(pk=edit_book_id).first()
    publish_list = Publish.objects.all()
    author_list = Author.objects.all()
    return render(request, "edit.html", locals())

models.py;

from django.db import models


# Create your models here.

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)  # 999999.99
    date = models.DateField()
    publish = models.ForeignKey("Publish")
    authors = models.ManyToManyField("Author")

    def __str__(self):
        return self.title


class Publish(models.Model):
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name

admin.py;

from django.contrib import admin

# Register your models here.
from .models import *

admin.site.register(Book)
admin.site.register(Author)
admin.site.register(Publish)

books.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Books</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<a href="/book/add"><button>添加书籍</button></a>
<ul>
    <table border="1">
        {% for book in book_list %}
            <tr>
                <td>{{ book.title }}</td>
                <td>{{ book.price }}</td>
                <td>{{ book.date|date:"Y-m-d" }}</td>
                <td>{{ book.publish.name }}</td>
                <td>{{ book.authors.all }}</td>
                <td><a href="/book/edit/{{ book.pk }}"><button>编辑</button></a></td>
            </tr>
        {% endfor %}

    </table>
</ul>
</body>
</html>

add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h3>添加页面</h3>
<form action="" method="post">
{% csrf_token %}
    <p>书籍名称<input type="text" name="title"></p>
    <p>价格<input type="text" name="price"></p>
    <p>日期<input type="date" name="date"></p>
    <p>出版社
        <select name="publish_id" id="">
            {% for publish in publish_list %}
                <option value="{{ publish.pk }}">{{ publish.name }}</option>
            {% endfor %}
        </select>
    </p>
    <p>作者
        <select name="author_pk_list" id="" multiple>
            {% for author in author_list %}
                <option value="{{ author.pk }}">{{ author.name }}</option>
            {% endfor %}

        </select>
    </p>
    <input type="submit">
</form>
</body>
</html>

 edit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h3>编辑页面</h3>
<form action="" method="post">
    {% csrf_token %}
    <p>书籍名称<input type="text" name="title" value="{{ edit_book.title }}"></p>
    <p>价格<input type="text" name="price" value="{{ edit_book.price }}"></p>
    <p>日期<input type="date" name="date" value="{{ edit_book.date|date:"Y-m-d" }}"></p>
    <p>出版社
        <select name="publish_id" id="">
            {% for publish in publish_list %}
                {% if edit_book.publish == publish %}
                    <option selected value="{{ publish.pk }}">{{ publish.name }}</option>
                {% else %}
                    <option value="{{ publish.pk }}">{{ publish.name }}</option>
                {% endif %}
            {% endfor %}
        </select>
    </p>
    <p>作者
        <select name="author_pk_list" id="" multiple>
            {% for author in author_list %}
                {% if author in edit_book.authors.all %}
                    <option selected value="{{ author.pk }}">{{ author.name }}</option>
                {% else %}
                    <option value="{{ author.pk }}">{{ author.name }}</option>
                {% endif %}

            {% endfor %}

        </select>
    </p>
    <input type="submit">
</form>
</body>
</html>

04 modelform实现增删改查

4.1 使用forms组件代替form表单;

class BookForm(forms.Form):
    title = forms.CharField(max_length=32, label="书籍名称")
    price = forms.DecimalField(max_digits=8, decimal_places=2, label="价格")  # 999999.99
    date = forms.DateField(label="日期",
                           widget=widgets.TextInput(attrs={"type": "date"})
                           )
    # gender = forms.ChoiceField(choices=((1, "男"), (2, "女"), (3, "其他"),))
    # publish = forms.ChoiceField(choices=Publish.objects.all().values_list("pk", "name"))
    publish = forms.ModelChoiceField(queryset=Publish.objects.all())
    authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())

4.2 基于ModelForm进行精简开发;

views.py

from django.shortcuts import render, redirect

# Create your views here.
from .models import *
from django import forms
from django.forms import widgets
from django.forms import ModelForm
from django.forms import widgets as wid

'''
class BookForm(forms.Form):
    title = forms.CharField(max_length=32, label="书籍名称")
    price = forms.DecimalField(max_digits=8, decimal_places=2, label="价格")  # 999999.99
    date = forms.DateField(label="日期",
                           widget=widgets.TextInput(attrs={"type": "date"})
                           )
    # gender = forms.ChoiceField(choices=((1, "男"), (2, "女"), (3, "其他"),))
    # publish = forms.ChoiceField(choices=Publish.objects.all().values_list("pk", "name"))
    publish = forms.ModelChoiceField(queryset=Publish.objects.all())
    authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
'''


class BookForm(ModelForm):
    class Meta:
        model = Book
        fields = "__all__"
        # fields = ["title", "price"]
        labels = {
            "title": "书籍名称",
            "price": "价格",
            "date": "书籍日期",
            "publish": "出版社",
            "authors": "作者",
        }
        widgets = {
            "title": wid.TextInput(attrs={"class": "form-control"}),
            "price": wid.TextInput(attrs={"class": "form-control"}),
            "date": wid.TextInput(attrs={"class": "form-control"}),
            "publish": wid.TextInput(attrs={"class": "form-control"}),
            "authors": wid.TextInput(attrs={"class": "form-control"}),
        }


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


def add_book(request):
    if request.method == "POST":
        form = BookForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("/books/")
    form = BookForm()
    return render(request, "add.html", locals())


def edit_book(request, edit_book_id):
    edit_book = Book.objects.filter(pk=edit_book_id).first()
    if request.method == "POST":
        form = BookForm(request.POST, instance=edit_book)
        form.save()
        return redirect("/books/")
    form = BookForm(instance=edit_book)
    return render(request, "edit.html", locals())

add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<h3>添加页面</h3>
<div class="col-md-4 col-md-offset-3">
    {% include 'form.html' %}
</div>

</body>
</html>

books.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Books</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<a href="/book/add"><button>添加书籍</button></a>
<ul>
    <table border="1">
        {% for book in book_list %}
            <tr>
                <td>{{ book.title }}</td>
                <td>{{ book.price }}</td>
                <td>{{ book.date|date:"Y-m-d" }}</td>
                <td>{{ book.publish.name }}</td>
                <td>{{ book.authors.all }}</td>
                <td><a href="/book/edit/{{ book.pk }}"><button>编辑</button></a></td>
            </tr>
        {% endfor %}

    </table>
</ul>
</body>
</html>

edit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h3>编辑页面</h3>
{% include 'form.html' %}
</body>
</html>

form.html

<form action="" method="post" novalidate>
    {% csrf_token %}
    {% for field in form %}
        <div>
            {{ field.label }}
            {{ field }}
        </div>
    {% endfor %}

    <input type="submit">
</form>
原文地址:https://www.cnblogs.com/tqtl911/p/9596198.html