【武沛齐Django】图书管理系统的刻意练习(第12个网站)--20230406

武沛齐课程笔记链接https://poker.blog.csdn.net/article/details/128073474

图书管理系统地址

github地址https://github.com/Seasonzhang-0503/library
实现书籍的借订和归还。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Form类

Form类:表单的增删改查

models.py以theBook为例子

THEBOOK_TYPE = (('电子书', '电子书'), ('纸质书', '纸质书'), ('PPT', 'PPT'),('项目', '项目'), ('视频', '视频'),('其他', '其他'))
THESTATUS_TYPE = (('已借订', '已借订'), ('未借订', '未借订'))

class theBook(models.Model):
    bid = models.AutoField(primary_key=True)
    theBook_name = models.CharField(max_length=500,verbose_name=('图书名称'),)
    theBook_location = models.ForeignKey(location,blank=True, null=True, on_delete=models.CASCADE,related_name='Book_location')
    theBook_type = models.CharField(max_length=500, verbose_name=('电子书/纸质书'),choices=THEBOOK_TYPE,)
    theBook_category = models.ForeignKey(category,blank=True, null=True, on_delete=models.CASCADE,related_name='Book_category')
    theBook_logo = models.ImageField(max_length=500, verbose_name=('图书照片1'),upload_to='images/')
    theBook_attachment = models.FileField(max_length=10000,verbose_name=('图书附件(备用)'),blank=True, null=True,upload_to='file')
    theBook_status1 = models.CharField(max_length=500,verbose_name=('图书状态1'),choices=THESTATUS_TYPE,)
    theBook_status2 = models.CharField(max_length=500,verbose_name=('图书状态2(备用)'),blank=True, null=True,)
    theBook_status3 = models.CharField(max_length=500,verbose_name=('图书状态3(备用)'),blank=True, null=True,)
    theBook_id = models.CharField(max_length=500,verbose_name=('图书编号(备用)'),blank=True, null=True,)
    theBook_information1 = models.TextField(max_length=10000,verbose_name=('图书信息1'),blank=True, null=True,)
    theBook_information2 = models.TextField(max_length=10000,verbose_name=('图书信息2(备用)'),blank=True, null=True,)
    theBook_information3 = models.TextField(max_length=10000,verbose_name=('图书信息3(备用)'),blank=True, null=True,)
    theBook_information4 = models.TextField(max_length=10000,verbose_name=('图书信息4(备用)'),blank=True, null=True,)
    theBook_information5 = models.TextField(max_length=10000,verbose_name=('图书信息5(备用)'),blank=True, null=True,)

    class Meta:
        verbose_name = ('图书')
        verbose_name_plural = ('图书')
        ordering = ['theBook_category'] # 返回值排序


    def __str__(self):
        return str(self.theBook_name)

forms.py把model转化为表单

class theBookForm(ModelForm):
    class Meta:
        model = theBook
        fields = '__all__'
        exclude = ['theBook_id','theBook_attachment','theBook_status1','theBook_status2','theBook_status3','theBook_information2',
                   'theBook_information3','theBook_information4','theBook_information5',]
        error_messages = {
            'theBook_name':{'required':"theBook_name不能为空",},
        }

        widgets = {
            "theBook_name":wid.Input(attrs={"class":"c1"}) #还可以自定义属性
        }


    # 循环找到所有的插件,加入css样式,添加 "class": "form-control"
    bootstrap_exclude_fields = ['theBook_logo',]
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
            if name in self.bootstrap_exclude_fields:
                continue
            # class属性追加form-control,其他属性保留
            if field.widget.attrs:
                field.widget.attrs["class"] = field.widget.attrs.get('class','') + ' ' + 'form-control'
            else:
                field.widget.attrs = {
                    "class": "form-control",
                }

views.py处理theBook的增删改查

def theBooklist_show(request,page):
    theBooklist_all = theBook.objects.all()
    print('request.POST',request.POST.get('querybookcategory'))
    querybookname = request.POST.get('querybookname')
    # getlist呈现多选值
    querybookcategory = request.POST.get('querybookcategory')
    querybooktype = request.POST.get('querybooktype')
    print('querybookname',querybookname,'querybookcategory',querybookcategory,'querybooktype',querybooktype)

    theBooklist = theBooklist_all
    if querybookname:
        theBooklist = theBooklist_all.filter(theBook_name__icontains=querybookname)
    if querybookcategory:
        theBooklist = theBooklist.filter(theBook_category__category_keyname__icontains=querybookcategory)
    if querybooktype:
        theBooklist = theBooklist.filter(theBook_type__icontains=querybooktype)

    # 添加分页功能
    paginator = Paginator(theBooklist, 5)
    try:
        page_obj = paginator.page(page)
    except PageNotAnInteger:
        # 如果参数page 的数据类型不是整型,就返回第一页数据
        page_obj = paginator.page(1)
    except EmptyPage:
        # 若用户访问的页数大于实际页数,则返回最后一页的数据
        page_obj = paginator.page(paginator.num_pages) 

    # context = {
    #     'theBooklist':theBooklist,
    # }

    return render(request,'theBooklist_show.html',locals())



def theBooklist_new(request):

    if request.method == "GET":
        form = theBookForm()
        return render(request,'theBooklist_new.html',{'form':form})
    
    # 用户POST请求提交数据,需要进行数据校验
    form = theBookForm(data=request.POST,files=request.FILES)
    if form.is_valid():
        # print(form.cleaned_data)
        # 直接保存至数据库
        form.save()
        return redirect("/theBooklist_show/")

    return render(request,'theBooklist_new.html',{'form':form})



def theBooklist_edit(request,bid):
    row_obj = theBook.objects.filter(bid=bid).first()

    if request.method == "GET":
        form = theBookForm(instance=row_obj)

        # 三元表达式:判断是否存在借订记录
        theBook_fk_theBorrow_status1 = ''
        if row_obj.theBook_type == '纸质书':
            theBook_fk_theBorrow_status1 = row_obj.theborrow_set.first().theBorrow_status1 if row_obj.theborrow_set.first() else 'no-data'
        print(theBook_fk_theBorrow_status1)
        return render(request,'theBooklist_edit.html',{'form':form,'theBook_fk_theBorrow_status1':theBook_fk_theBorrow_status1,})
    
    # 用户POST请求提交数据,需要进行数据校验
    form = theBookForm(data=request.POST,files=request.FILES, instance=row_obj)
    if form.is_valid():
        print(form.cleaned_data)
        # 直接保存至数据库
        form.save()
        return redirect("/theBooklist_show/")

    return render(request,'theBooklist_edit.html',{'form':form})


def theBooklist_delete(request,bid):
    theBook.objects.get(bid=bid).delete()
    return redirect("/theBooklist_show/")

templates展示增删改查的表单

theBooklist_show.html

{% extends 'base.html' %}
{% load static %}

{% block body_block %}
<div class="container">
    <div class="row py-4 align-items-center">
        
        <!--展示显示人员-->
        <div class="col-lg-12 col-md-12 mt-0 table-responsive"  style="background-color: #fff;">
            <!--表单-->
            <h3 class="font-weight-bold">图书清单<a class="ml-4 btn btn-light" href="/theBooklist_new/">+</a></h3>
            <table class="table table-striped table-sm table-bordered ">
                <thead>
                    <tr style="color:White;background-color:#3366FF;font-family:微軟正黑體,Tahoma,Arial,微軟雅黑體;font-size:15px;">
                        <th scope="col">#</th>
                        <th scope="col" style="width:20%">图书名称</th>
                        <th scope="col">地点</th>
                        <th scope="col">电子书/纸质书</th>
                        <th scope="col" style="width:20%">分类</th>
                        <th scope="col">图书照片</th>
                        <th scope="col">借订(外键)</th>
                        <th scope="col">操作</th>
                    </tr>
                </thead>

                <!-- for theBook in theBooklist -->
                {% for theBook in page_obj.object_list %}
                <tr valign="middle" style="color:Black;border-color:#E0E0E0;font-size:15px;"></tr>
                    <td>{{ theBook.bid }}</td>
                    <td>{{ theBook.theBook_name }}</td>
                    <td>{{ theBook.theBook_location }}</td>
                    <td>{{ theBook.theBook_type }}</td>
                    <td>{{ theBook.theBook_category }}</td>
                    <td class="" style="width:100px; height:100px">
                        {% if theBook.theBook_logo %}
                        <a target="_blank" href="{{theBook.theBook_logo.url}}" >
                            <img src="{{theBook.theBook_logo.url}}" alt="{{theBook.theBook_logo.url}}" width="100px" height="100px"></img>
                        </a>
                        {% endif %}
                    </td>
                    <!-- 如果是电子书,则不用记录状态了 -->
                    {% if theBook.theBook_type == '纸质书' %}
                        <td>{{ theBook.theborrow_set.first.theBorrow_status1|default:'no-data' }}</td>
                    {% else %}
                        <td></td>
                    {% endif %}
                    <td>
                        <a class="btn btn-primary btn-xs" href="/theBooklist_edit/{{ theBook.bid }}/">编辑</a>
                        <a class="btn btn-danger btn-xs" href="/theBooklist_delete/{{ theBook.bid }}/">删除</a>
                        <a class="btn btn-info btn-xs" href="/theBorrowlist_new_default/{{ theBook.bid }}/">借订</a>
                    </td>
                </tr>
                {% endfor %}
                
            </table>

                <!--分页功能-->
                <div class="pagination">
                    <span class="step-links">
                        {% if page_obj.has_previous %}
                            <a href="/theBooklist_show/1/">&laquo; first</a>
                            <a href="/theBooklist_show/{{ page_obj.previous_page_number }}/">previous</a>
                        {% endif %}
                
                        <span class="current">
                             {{ page_obj.number }} / {{ page_obj.paginator.num_pages }}
                        </span>
                
                        {% if page_obj.has_next %}
                            <a href="/theBooklist_show/{{ page_obj.next_page_number }}/">next</a>
                            <a href="/theBooklist_show/{{ page_obj.paginator.num_pages }}/">last &raquo;</a>
                        {% endif %}
                    </span>
                </div>


        </div>
    </div>
</div>

<br>
<br>
<br>
<br>
<br>
{% endblock %}


theBooklist_edit.html


{% extends 'base.html' %}
{% load static %}

{% block body_block %}
<div class="container">
    <div class="row py-4 align-items-center">
        
        <!--展示显示人员-->
        <div class="col-lg-12 col-md-12 mt-0 table-responsive"  style="background-color: #fff;">
            <!--表单-->
            <h3 class="font-weight-bold">图书-编辑</h3>
            <div class="modal-body">
                <form method="post" id="formSave" enctype="multipart/form-data">
                    {% csrf_token %}
                    <div>
                        {% for item in form %}
                        <div class="col-xs-6">
                            <div class="form-group" style="position: relative; margin-top: 5px">
                                <label>{{ item.label }}</label>
                                {{ item }}
                                <span class="error_msg" style="color: red;position: absolute;">{{ item.errors.0 }}</span>
                            </div>
                        </div>
                        {% endfor %}

                        <!-- 手动添加外键的借订状态 -->
                        <div class="col-xs-6">
                            <div class="form-group" style="position: relative; margin-top: 5px">
                                <div>借订状态</div>
                                <input type="text" value="{{ theBook_fk_theBorrow_status1 }}" readonly="true" class="form-control">
                            </div>
                        </div>
                    </div>
                    <button type="submit" class="btn btn-primary">保存</button>
                </form>
            </div>

        </div>
    </div>
</div>

<br>
<br>
<br>
<br>
<br>
{% endblock %}


theBooklist_new.html

{% extends 'base.html' %}
{% load static %}

{% block body_block %}
<div class="container">
    <div class="row py-4 align-items-center">
        
        <!--展示显示人员-->
        <div class="col-lg-12 col-md-12 mt-0 table-responsive"  style="background-color: #fff;">
            <!--表单-->
            <h3 class="font-weight-bold">图书-添加</h3>
            <div class="panel-body">
                <form method="post" id="formSave" enctype="multipart/form-data">
                    {% csrf_token %}
                    <div>
                        {% for item in form %}
                        <div class="col-xs-6">
                            <div class="form-group" style="position: relative; margin-top: 5px">
                                <label>{{ item.label }}</label>
                                {{ item }}
                                <span class="error_msg" style="color: red;position: absolute;">{{ item.errors.0 }}</span>
                            </div>
                        </div>
                        {% endfor %}
                    </div>
                    <button type="submit" class="btn btn-primary">保存</button>
                </form>
            </div>

        </div>
    </div>
</div>

<br>
<br>
<br>
<br>
<br>
{% endblock %}


theBooklist_query.html

{% extends 'base.html' %}
{% load static %}

{% block body_block %}
<div class="container">
    <div class="row py-4 align-items-center">
        
        <!--展示显示人员-->
        <div class="col-lg-12 col-md-12 mt-0 table-responsive"  style="background-color: #fff;">
            <!--表单-->
            <h3 class="font-weight-bold">图书清单-查询</h3>
            <br>
            <form action="/theBooklist_show/1/" method="post" novalidate>
                {% csrf_token %}
                {{ form_obj.as_p }}
                <button type="submit" class="btn btn-primary">query</button>
            </form>
        </div>
    </div>
</div>

<br>
<br>
<br>
<br>
<br>
{% endblock %}

urls.py配置路由

    # theBook增删改查
    # path('theBooklist_show/', views.theBooklist_show, name='theBooklist_show'),
    path('theBooklist_show/<int:page>/',views.theBooklist_show,name='theBooklist_show'),
    path('getQueryBookForm/', views.getQueryBookForm, name='getQueryBookForm'),
    path('theBooklist_new/', views.theBooklist_new, name='theBooklist_new'),
    path('theBooklist_edit/<int:bid>/', views.theBooklist_edit,name='theBooklist_edit'),
    path('theBooklist_delete/<int:bid>/', views.theBooklist_delete,name='theBooklist_delete'),

Form类:动态多选框

在这里插入图片描述

views.py 查询后端数据,动态生成多选框

#想办法取出多选框的选项
#querylist <QuerySet [{'category_keyname': '人力资源'}, {'category_keyname': '人力资源'}, {'category_keyname': '后端'}, {'category_keyname': '前端'}, {'category_keyname': '前端'}, {'category_keyname': '人力资源'}, {'category_keyname': '后端'}, {'category_keyname': '前端'}, {'category_keyname': '后端'}, {'category_keyname': 'Git'}, {'category_keyname': '后端'}, {'category_keyname': '服务器'}, {'category_keyname': '数据'}]>
querylist = category.objects.all().order_by('category_keyname').distinct().values('category_keyname')
query_set = set()
querybookcategory_choices = [('',''),]
for q in querylist:
    query_set.add(q['category_keyname'])
for qs in query_set:
    querybookcategory_choices.append((qs,qs))
# querybookcategory_choices = [('人力资源', '人力资源'), ('后端', '后端')]
print('querybookcategory_choices',querybookcategory_choices)

# querytheBookcategory_choices = [('', ''),('电子书', '电子书'), ('纸质书', '纸质书')]
querytheBookcategory_list = theBook.objects.all().order_by('theBook_type').distinct().values('theBook_type')
print('querytheBookcategory_list',querytheBookcategory_list)
query_set = set()
querytheBookcategory_choices = [('',''),]
for q in querytheBookcategory_list:
    query_set.add(q['theBook_type'])
for qs in query_set:
    querytheBookcategory_choices.append((qs,qs))


class QueryBookForm(forms.Form):
    querybookname = forms.CharField(label='图书名称')
    querybookcategory = forms.ChoiceField(label='图书分类',choices=querybookcategory_choices)
    querybooktype = forms.ChoiceField(label='图书类型',choices=querytheBookcategory_choices,)

theBooklist_query.html

{% extends 'base.html' %}
{% load static %}

{% block body_block %}
<div class="container">
    <div class="row py-4 align-items-center">
        
        <!--展示显示人员-->
        <div class="col-lg-12 col-md-12 mt-0 table-responsive"  style="background-color: #fff;">
            <!--表单-->
            <h3 class="font-weight-bold">图书清单-查询</h3>
            <br>
            <form action="/theBooklist_show/1/" method="post" novalidate>
                {% csrf_token %}
                {{ form_obj.as_p }}
                <button type="submit" class="btn btn-primary">query</button>
            </form>
        </div>
    </div>
</div>

{% endblock %}

ORM

ORM:values()和values_list()

1、values返回是字典列表
2、values_list返回的是元组列表

#querylist <QuerySet [{'category_keyname': '人力资源'}, {'category_keyname': '人力资源'}, {'category_keyname': '后端'}, {'category_keyname': '前端'}, {'category_keyname': '前端'}, {'category_keyname': '人力资源'}, {'category_keyname': '后端'}, {'category_keyname': '前端'}, {'category_keyname': '后端'}, {'category_keyname': 'Git'}, {'category_keyname': '后端'}, {'category_keyname': '服务器'}, {'category_keyname': '数据'}]>
querylist = category.objects.all().order_by('category_keyname').distinct().values('category_keyname')

# querylist2 <QuerySet [('Git',), ('人力资源',), ('前端',), ('后端',), ('数据',), ('服务器',)]>
# querylist2 = category.objects.all().order_by('category_keyname').distinct().values_list('category_keyname')

ORM:外键的关联查询

1.外键的关联查询:外键 __ 属性
2.外键的外键的关联查询:外键 __ 外键 __ 属性(理论上外键可以一直连下去)
在这里插入图片描述

models.py有外键关系

class theBook(models.Model):
	......
    theBook_category = models.ForeignKey(category,blank=True, null=True, on_delete=models.CASCADE,related_name='Book_category')
    ......

class category(models.Model):
	......
    category_keyname = models.CharField(max_length=500,verbose_name=('分类主名称'),)
	......

views.py中有theBooklist = theBooklist.filter(theBook_category__category_keyname__icontains=querybookcategory),通过查找外键的属性。

def theBooklist_show(request,page):
    theBooklist_all = theBook.objects.all()
    print('request.POST',request.POST.get('querybookcategory'))
    querybookname = request.POST.get('querybookname')
    # getlist呈现多选值
    querybookcategory = request.POST.get('querybookcategory')
    querybooktype = request.POST.get('querybooktype')
    print('querybookname',querybookname,'querybookcategory',querybookcategory,'querybooktype',querybooktype)

    theBooklist = theBooklist_all
    if querybookname:
        theBooklist = theBooklist_all.filter(theBook_name__icontains=querybookname)
    if querybookcategory:
        theBooklist = theBooklist.filter(theBook_category__category_keyname__icontains=querybookcategory)
    if querybooktype:
        theBooklist = theBooklist.filter(theBook_type__icontains=querybooktype)

    # 添加分页功能
    paginator = Paginator(theBooklist, 5)
    try:
        page_obj = paginator.page(page)
    except PageNotAnInteger:
        # 如果参数page 的数据类型不是整型,就返回第一页数据
        page_obj = paginator.page(1)
    except EmptyPage:
        # 若用户访问的页数大于实际页数,则返回最后一页的数据
        page_obj = paginator.page(paginator.num_pages) 

    # context = {
    #     'theBooklist':theBooklist,
    # }

    return render(request,'theBooklist_show.html',locals())

非ORM:操作原始SQL语句

Django web开发(二) - Mysql数据库

执行原生 SQL 查询
在这里插入图片描述

方式1:views.py执行原生SQL查询生成 RawQuerySet
# 练习原始SQL
def categorylist_show(request):    
    # categorylist = category.objects.all()
    # 练习原始SQL
    categorylist = category.objects.raw('SELECT * FROM book_category')
    
    context = {
        'categorylist':categorylist,
    }

    return render(request,'categorylist_show.html',context)

在这里插入图片描述

方式2:views.py直接执行自定义 SQL


# 直接执行自定义 SQL
# (2, '000001', 'Django基础教程(Tango with Django)', 5, 'images/tangowithdjango.png', '', '已借订', None, None, 'D:\\我的U盘-20220812\\ABE-Python\\4.python网页前后端\\Django基础教程', '', '', '', '', 3, '电子书')
def dictfetchall(cursor):
    "Return all rows from a cursor as a dict"
    columns = [col[0] for col in cursor.description]
    return [
        dict(zip(columns, row))
        for row in cursor.fetchall()
    ]

from django.db import connection
def my_custom_sql(request):
    with connection.cursor() as cursor:
        cursor.execute("SELECT * FROM book_thebook")
        rows = dictfetchall(cursor)
        print(rows)
        for row in rows:
            print('row.theBook_name',row['theBook_name'])
        
    # return HttpResponse('rows',rows)
    return HttpResponse('rows')

在这里插入图片描述

数据库操作(不用django,在数据库中直接增删改查)

https://poker.blog.csdn.net/article/details/128250617

增加数据

insert into 表名称(字段1, 字段2, ...) values(1, "张三", ...);

insert into tb1(name,age) values("张三",25);

删除数据

delete from 表名称;				--删除所有数据
delete from 表名称 where 条件;	--删除指定数据


delete from tb1 where id = 1;
delete from tb1 where id = 1 and name = "张三";
delete from tb1 where id = 1 or id = 100;
delete from tb1 where id > 100;
delete from tb1 where id != 50;
delete from tb1 where id in (10,15);

修改数据

update 表名称 set=;				--修改一列
update 表名称 set=,=;		--修改多列
update 表名称 set=where 条件;		--修改某行某列

update tb1 set name="李四" where id = 1;
update tb1 set age=age+10 where name=""李四;

查询数据

select 字段名(或者*) from 表名称;
select 字段名(或者*) from 表名称 where 条件;

select * from tb1;
select name from tb1;
select * from tb1 where id = 1;

分页

【Django 分页】Django 中的分页功能–20230403

在这里插入图片描述

自定义用户-AbstractUser模型

自定义用户:重写abstractuser模型

【Django User】Django 中的拓展自定义用户user模型–20230403

在这里插入图片描述

自定义用户:密码加密

在这里插入图片描述

settings.py默认首选第一个加密方式,其他加密方式只是第二顺位,都可以使用。

from django.conf import settings
settings.configure(DEBUG=True)

PASSWORD_HASHERS = (
    'django.contrib.auth.hashers.MD5PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
    'django.contrib.auth.hashers.BCryptPasswordHasher',
    'django.contrib.auth.hashers.SHA1PasswordHasher',
    'django.contrib.auth.hashers.CryptPasswordHasher',
)

forms.py–theUserForm增加clean_password()方法。

class theUserForm(ModelForm):
    class Meta:
        model = User
        #fields = '__all__'
        fields = ['username','password','dept','age','mobilenumber','role','theUser_status1',]
        exclude = []

        widgets = {
            "password":wid.PasswordInput(render_value = True) # render_value = True显示值
        }

        labels= {
            "username":"用户名",
            "password":"密码",
        }

        
    # 循环找到所有的插件,加入css样式,添加 "class": "form-control"
    bootstrap_exclude_fields = []
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
            if name in self.bootstrap_exclude_fields:
                continue
            # class属性追加form-control,其他属性保留
            if field.widget.attrs:
                field.widget.attrs["class"] = field.widget.attrs.get('class','') + ' ' + 'form-control'
            else:
                field.widget.attrs = {
                    "class": "form-control",
                }

    def clean_password(self):
        pwd = self.cleaned_data.get("password")
        # return什么.password字段保存什么
        return make_password(pwd)

自定义用户:theUserForm和theUserNoPasswordForm

theUserForm用于注册,含密码。
在这里插入图片描述

theUserNoPasswordForm用于修改非密码的其他信息。
在这里插入图片描述

forms.py:定义好theUserForm和theUserNoPasswordForm

class theUserForm(ModelForm):
    class Meta:
        model = User
        #fields = '__all__'
        fields = ['username','password','dept','age','mobilenumber','role','theUser_status1',]
        exclude = []

        widgets = {
            "password":wid.PasswordInput(render_value = True) # render_value = True显示值
        }

        labels= {
            "username":"用户名",
            "password":"密码",
        }

        
    # 循环找到所有的插件,加入css样式,添加 "class": "form-control"
    bootstrap_exclude_fields = []
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
            if name in self.bootstrap_exclude_fields:
                continue
            # class属性追加form-control,其他属性保留
            if field.widget.attrs:
                field.widget.attrs["class"] = field.widget.attrs.get('class','') + ' ' + 'form-control'
            else:
                field.widget.attrs = {
                    "class": "form-control",
                }

    def clean_password(self):
        pwd = self.cleaned_data.get("password")
        # return什么.password字段保存什么
        return make_password(pwd)



class theUserNoPasswordForm(ModelForm):
    class Meta:
        model = User
        fields = ['username','dept','age','mobilenumber','role','theUser_status1',]
        exclude = []

        labels= {
            "username":"用户名",
        }

        
    # 循环找到所有的插件,加入css样式,添加 "class": "form-control"
    bootstrap_exclude_fields = []
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
            if name in self.bootstrap_exclude_fields:
                continue
            # class属性追加form-control,其他属性保留
            if field.widget.attrs:
                field.widget.attrs["class"] = field.widget.attrs.get('class','') + ' ' + 'form-control'
            else:
                field.widget.attrs = {
                    "class": "form-control",
                }

views.py:theUserlist_edit使用theUserNoPasswordForm。


def theUserlist_new(request):

    if request.method == "GET":
        form = theUserForm()
        return render(request,'theUserlist_new.html',{'form':form})
    
    # 用户POST请求提交数据,需要进行数据校验
    form = theUserForm(data=request.POST,files=request.FILES)
    if form.is_valid():
        print(form.cleaned_data)
        
        # 直接保存至数据库
        form.save()
   
        return redirect("/theUserlist_show/")

    return render(request,'theUserlist_new.html',{'form':form})



def theUserlist_edit(request,id):
    row_obj = User.objects.filter(id=id).first()

    if request.method == "GET":
        form = theUserNoPasswordForm(instance=row_obj)
        # 判断是否存在借订记录
        theUser_fk_theBorrow_fk_theBook = []
        for fk in row_obj.theborrow_set.all():
            booklist = fk.theBorrow_theBook.theBook_name if fk else 'no-data'
            theUser_fk_theBorrow_fk_theBook.append(booklist)
            print(theUser_fk_theBorrow_fk_theBook)
        return render(request,'theUserlist_edit.html',{'form':form,'theUser_fk_theBorrow_fk_theBook':theUser_fk_theBorrow_fk_theBook,})
    
    # 用户POST请求提交数据,需要进行数据校验
    form = theUserNoPasswordForm(data=request.POST,files=request.FILES, instance=row_obj)
    if form.is_valid():
        # print(form.cleaned_data)
        
        # 直接保存至数据库
        form.save()

        return redirect("/theUserlist_show/")

    return render(request,'theUserlist_edit.html',{'form':form})

自定义用户-全新User模型

自定义用户:新增newUser模型、用户与密码验证

参考Django web 开发(四) - Django项目实践(七)-账户登录

在这里插入图片描述

forms.py:利用forms.Form建立登录表单

# 这一次不使用ModelForm,使用Form来实现
class LoginForm(forms.Form):
    username = forms.CharField(
        label="用户名",
        widget=forms.TextInput(attrs={"class": "form-control"}),
        required=True,
    )
    password = forms.CharField(
        label="用户名",
        # render_value=True 表示当提交后,如果密码输入错误,不会自动清空密码输入框的内容
        widget=forms.PasswordInput(attrs={"class": "form-control"}, ),
        required=True,
    )

    def clean_password(self):
        pwd = self.cleaned_data.get("password")
        return pwd

views.py

def admin_login(request):
    """admin登录"""
    print('admin_login')
    if request.method == "GET":
        form = LoginForm(auto_id=True)
        return render(request, 'admin_login.html', {"form": form})

    form = LoginForm(data=request.POST)
    if form.is_valid():
        # 去数据库校验用户名和密码是否正确
        admin_object = Admin.objects.filter(**form.cleaned_data).first()
        # print('**form.cleaned_data',**form.cleaned_data)
        # 如果数据库中没有查询到数据
        if not admin_object:
        	# 手动抛出错误显示在"password"字段下
            form.add_error("password", "用户名或密码错误")
            return render(request, 'admin_login.html', {"form": form})
        return redirect("/")

    return render(request, 'admin_login.html', {"form": form})

urls.py

    # admin自定义用户登录
    path('admin_login/', views.admin_login,name='admin_login'),

admin_login.html

{% extends 'base.html' %}
{% load static %}


{% block body_block %}
<div class="container card mt-3">
    <div class="card-body">
        <h2 class="card-title">用户登录</h2>
        <div class="card-text">
            <form method="post" novalidate>
                {% csrf_token %}
                <div class="form-group">
                    <label>用户名</label>
                    {{ form.username }}
                    <span style="color: red;">{{ form.errors.username.0 }}</span>
                    
                </div>
                <div class="form-group">
                    <label>密码</label>
                    {{ form.password }}
                    <span style="color: red;">{{ form.errors.password.0 }}</span>
                </div>
                
                <button type="submit" class="btn btn-primary center-block" style="width: 80px;">登录</button>
            </form>
        </div>
    </div>
</div>
{% endblock %}

自定义用户:显示用户信息

因为在login函数中request.session中定义的username字段对应的名称为name,所以我们可以在前端代码中直接调用。

                <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                    <a class="dropdown-item" href="/admin_login/">admin自主用户登录</a>
                    <div class="dropdown-divider"></div>
                    <a class="dropdown-item" href="/admin_logout/">admin自主用户登出</a>
                    <div class="dropdown-divider"></div>
                    <a class="dropdown-item" href="#">{{ request.session.info.name|default:'未登陆' }}</a>
                </div>

在这里插入图片描述

自定义用户:注册功能和MD5加密

在这里插入图片描述
在这里插入图片描述

encrypt.py实现md5加密。

import hashlib
from django.conf import settings

def md5(data_string):
    obj = hashlib.md5(settings.SECRET_KEY.encode('utf-8'))
    obj.update(data_string.encode('utf-8'))
    return obj.hexdigest()

forms.py使用md5加密函数和modelform。

class AdminAddForm(ModelForm):
    class Meta:
        model = Admin
        fields = ["username", "password","permission",]
        widgets = {
            "password": forms.PasswordInput
        }

    def clean_password(self):
        pwd = self.cleaned_data.get("password")
        return md5(pwd)

views.py 套用模板即可

def admin_add(request):
    """添加管理员"""

    if request.method == "GET":
        form = AdminAddForm()
        return render(request, "admin_add.html", {"form": form})

    # 如果是POST请求
    form = AdminAddForm(data=request.POST)
    print('request.POST',request.POST)
    context = {
        "form": form,
    }
    
    if form.is_valid():
        form.save()
        return redirect("/")

    return render(request, "admin_add.html", context)

urls.py

    path('admin_add/', views.admin_add),

自定义用户:登录Session和cookies

request.session[“info”] = {‘id’: admin_object.id, ‘name’: admin_object.username}

views.py:如果用户名密码正确,网站生成随机字符创,写到用户浏览器的cookie中,再写入到服务器的session中。

def admin_login(request):
    """admin登录"""
    print('admin_login')
    if request.method == "GET":
        form = LoginForm(auto_id=True)
        return render(request, 'admin_login.html', {"form": form})

    form = LoginForm(data=request.POST)
    if form.is_valid():
        # 去数据库校验用户名和密码是否正确
        admin_object = Admin.objects.filter(**form.cleaned_data).first()
        # print('**form.cleaned_data',**form.cleaned_data)
        # 如果数据库中没有查询到数据
        if not admin_object:
        	# 手动抛出错误显示在"password"字段下
            form.add_error("password", "用户名或密码错误")
            return render(request, 'admin_login.html', {"form": form})
        
        # 如果用户名密码正确
        # 网站生成随机字符创,写到用户浏览器的cookie中,再写入到服务器的session中
        request.session["info"] = {'id': admin_object.id, 'name': admin_object.username}
        return redirect("/")

    return render(request, 'admin_login.html', {"form": form})

自定义用户:中间件实现登录

middleware\auth.py :你会发现只要你没登录过,不管你访问什么页面,都会跳转到login登录界面。

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


class AuthMiddleware(MiddlewareMixin):

    def process_request(self, request):

        # 0.排除不需要的页面
        if request.path_info == "/admin_login/":
            return

        # 1.读取当前访问的用户的session信息,如果能读到,说明已登录过,就可以继续向后走
        info_dict = request.session.get("info")
        if info_dict:
            return

        # 2.如果没有登录信息
        return redirect("/admin_login/")

settings.py注册中间件

MIDDLEWARE = [
	......
    'book.middleware.auth.AuthMiddleware',#自定义中间件
]

自定义用户:用户注销

views.py 删除session


def admin_logout(request):
    """ 注销 """

    # 清除当前session
    # request.session.clear()
    # 清除指定session
    del request.session['info'] 

    return redirect("/admin_login/")

urls.py

    path('admin_logout/', views.admin_logout),

echarts和ajax

Django web 开发(四) - Django项目实践(十)-数据统计

在这里插入图片描述

urls.py建立空页path和3个请求数据path。

    # 数据统计
    path('chart/list/', views.chart_list),
    path('chart/line/', views.chart_line),
    path('chart/bar/', views.chart_bar),
    path('chart/pie/', views.chart_pie),

views.py定义后端1个空页请求和3个数据请求。



def chart_list(request):
    """ 数据统计 """
    return render(request, 'chart_list.html')




def chart_line(request):
    """ 构造折线图的数据 """
    # 数据可以去数据库中获取
    legend = ['天津分公司', '北京分公司']
    xAxis = ['1月', '2月', '3月', '4月', '5月', '6月', '7月']
    series_list = [
            {
                'name': '天津分公司',
                'type': 'line',
                'data': [520, 132, 101, 134, 90, 230, 210]
            },
            {
                'name': '北京分公司',
                'type': 'line',
                'data': [220, 182, 191, 234, 290, 330, 310]
            },
            ]

    result = {
        "status": True,
        "data": {
            "legend": legend,
            "xAxis": xAxis,
            "series_list": series_list,
        }
    }

    return JsonResponse(result)



def chart_bar(request):
    """ 构造柱状图的数据 """

    # 数据可以去数据库中获取
    legend = ['销量', '价格']
    xAxis = ['1月', '2月', '3月', '4月', '5月', '6月']
    series_list = [
                {
                    "name": '销量',
                    "type": 'bar',
                    "data": [5, 20, 36, 10, 10, 20]
                },
                {
                    "name": '价格',
                    "type": 'bar',
                    "data": [25, 40, 80, 65, 70, 50]
                }
            ]

    result = {
        "status": True,
        "data": {
            "legend": legend,
            "xAxis": xAxis,
            "series_list": series_list,
        }
    }

    return JsonResponse(result)



def chart_pie(request):
    """ 构造饼图的数据 """
    data_list = [
                    { "value": 10, "name": '销售部' },
                    { "value": 735, "name": '运营部' },
                    { "value": 580, "name": '财务部' },
                ]

    result = {
        "status": True,
        "data_list": data_list,
    }

    return JsonResponse(result)

chart_list.html 利用ajax请求访问数据

{% extends 'base.html' %}
{% load static %}

{% block body_block %}
<div class="container">
    <h1>数据统计</h1>
    <div class="panel panel-default">
        <div class="panel-heading">
            <h3 class="panel-title">折线图</h3>
            <div class="panel-body">
                <div id="m1" style="width: 100%;height:400px;"></div>
            </div>
        </div>
        <div class="panel-body">
            
        </div>
    </div>
    <div class="row">
        <div class="col-sm-8">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h3 class="panel-title">柱状图</h3>
                </div>
                <div class="panel-body">
                    <div id="m2" style="width: 600px;height:400px;"></div>
                </div>
            </div>
        </div>
        <div class="col-sm-4">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h3 class="panel-title">饼图</h3>
                </div>
                <div class="panel-body">
                    <div id="m3" style="width: 300px;height:400px;"></div>
                </div>
            </div>
        </div>

    </div>
</div>


{% endblock %}



{% block script %}
<script src="/static/js/echarts.js"></script>

<script type="text/javascript">

    $(function () {
        initLine();
        initBar();
        iniPie();
    })

    function initLine() {
    var chartDom = document.getElementById('m1');
    var myChart = echarts.init(chartDom);
    var option;

    option = {
        title: {
            text: '分公司业绩图',
            left: "center",
        },
        tooltip: {
            trigger: 'axis'
        },
        legend: {
            // data: ['天津分公司', '北京分公司'],
            data:[],
            bottom: 0,
        },
        grid: {
            left: '3%',
            right: '4%',
            bottom: '12%',
            containLabel: true
        },
        toolbox: {
            feature: {
                saveAsImage: false,
            }
        },
        xAxis: {
            type: 'category',
            boundaryGap: false,
            // data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月'],
            data: [],
        },
        yAxis: {
            type: 'value'
        },
        series: [
            // {
            //     name: '天津分公司',
            //     type: 'line',
            //     stack: 'Total',
            //     data: [120, 132, 101, 134, 90, 230, 210]
            // },
            // {
            //     name: '北京分公司',
            //     type: 'line',
            //     stack: 'Total',
            //     data: [220, 182, 191, 234, 290, 330, 310]
            // },
        ],
    };
    $.ajax({
            url: "/chart/line/",
            type: "get",
            dataType: "JSON",
            success: function(res){
                if(res.status){
                    // 将获取到的数据更新到 option 中
                    option.legend.data = res.data.legend;
                    option.xAxis.data = res.data.xAxis;
                    option.series = res.data.series_list;

                    // 使用刚指定的配置项和数据显示图表。
                    myChart.setOption(option);
                }
            }
        })
}



    function initBar() {
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('m2'));

        // 指定图表的配置项和数据
        var option = {
            title: {
                text: '员工业绩年度汇总信息',
                subtext: "xxx公司",
                textAlign: "auto",
                left: "center",
            },
            tooltip: {},
            legend: {
                data: [],   // 后台获取
                bottom: 0,
            },
            xAxis: {
                data: []    // 后台获取
            },
            yAxis: {},
            series: []      // 后台获取
        };

        $.ajax({
            url: "/chart/bar/",
            type: "get",
            dataType: "JSON",
            success: function(res){
                if(res.status){
                    // 将获取到的数据更新到 option 中
                    option.legend.data = res.data.legend;
                    option.xAxis.data = res.data.xAxis;
                    option.series = res.data.series_list;

                    // 使用刚指定的配置项和数据显示图表。
                    myChart.setOption(option);
                }
            }
        })
    }

// 饼图
// function iniPie() {
//         var chartDom = document.getElementById('m3');
//         var myChart = echarts.init(chartDom);
//         var option;

//         option = {
//             title: {
//                 text: '部门预算占比',
//                 subtext: 'xxx公司',
//                 left: 'center'
//             },
//             tooltip: {
//                 trigger: 'item'
//             },
//             legend: {
//                 orient: 'vertical',
//                 bottom: 0,
//             },
//             series: [
//                 {
//                     name: 'Access From',
//                     type: 'pie',
//                     radius: '50%',
//                     data: [
//                         // { value: 1048, name: '销售部' },
//                         // { value: 735, name: '运营部' },
//                         // { value: 580, name: '财务部' },
//                     ],
//                     emphasis: {
//                         itemStyle: {
//                             shadowBlur: 10,
//                             shadowOffsetX: 0,
//                             shadowColor: 'rgba(0, 0, 0, 0.5)'
//                         }
//                     }
//                 }
//             ]
//         };
//         option && myChart.setOption(option);
//     }
function iniPie() {
    var chartDom = document.getElementById('m3');
    var myChart = echarts.init(chartDom);
    var option;

    option = {
        title: {
            text: '部门预算占比',
            subtext: 'xxx公司',
            left: 'center'
        },
        tooltip: {
            trigger: 'item'
        },
        legend: {
            orient: 'vertical',
            bottom: 0,
        },
        series: [
            {
                name: 'Access From',
                type: 'pie',
                radius: '50%',
                data: [],
                emphasis: {
                    itemStyle: {
                        shadowBlur: 10,
                        shadowOffsetX: 0,
                        shadowColor: 'rgba(0, 0, 0, 0.5)'
                    }
                }
            }
        ]
    };

    $.ajax({
        url: "/chart/pie/",
        type: "get",
        dataType: "JSON",
        success: function(res) {
            if(res.status){
                option.series[0].data = res.data_list;
                option && myChart.setOption(option);
            }
        }
    })
}

</script>

{% endblock %}

modal和ajax

思路:利用ajax技术,区分GET和POST方法,携带id参数,进行增删改查。利用全局变量EDIT_ID和DELETE_IDk,通过url?boid来传递。单独显示readonly字段,同时无法变更的值可以选择不显示。

在这里插入图片描述
在这里插入图片描述

step1:views.py

theBorrowlist_user方法用于展示列表。
theBorrowlist_user_modal_new方法用于弹出框新增数据。
theBorrowlist_user_modal_show方法用于弹出框展示数据细节。
theBorrowlist_user_modal_save方法用于弹出框保存数据。

def theBorrowlist_user(request):

    theBorrowlist = theBorrow.objects.all()
    AddForm = theBorrowModalAddForm()
    ShowForm = theBorrowModalShowForm()
    # EditForm = theBorrowModalEditForm()
        
    context = {
        'theBorrowlist':theBorrowlist,
        'AddForm':AddForm,
        'ShowForm':ShowForm,
        # 'EditForm':EditForm,
    }

    return render(request,'theBorrowlist_user.html',context)





@csrf_exempt
def theBorrowlist_user_modal_new(request):
    """ 新建 """
    form = theBorrowModalAddForm(data=request.POST)
    if form.is_valid():
        print('is_valid',request.POST)
        form.save()
        return JsonResponse({"status": True,"error":'fail',})

    return JsonResponse({"status": False,"error":'fail',})



@csrf_exempt
def theBorrowlist_user_modal_show(request):

    boid = request.GET.get('boid')
    print('show-boid',boid)

    # values方法形成一个对象
    row_obj = theBorrow.objects.filter(boid=boid).values("boid", "theBorrow_add_datetime", "theBorrow_theUser",
                                                         'theBorrow_theBook','theBorrow_duration','theBorrow_status1'
                                                         ).first()
    
    if not row_obj:
        return JsonResponse({"status": False, "error": "数据不存在!","boid":boid})
    else:
        # 从数据库中获取到一个对象 row_object
        result = {
            "status": True,
            "data": row_obj,
            "boid":boid,
        }
        print('result',result)

        return JsonResponse(result)


@csrf_exempt
def theBorrowlist_user_modal_save(request):
    data = request.POST
    print('save-data',data)
    boid = request.GET.get('boid')
    print('save-boid',boid)

    # values方法形成一个对象
    # row_obj = theBorrow.objects.filter(boid=boid).values("boid", "theBorrow_add_datetime", "theBorrow_theUser",'theBorrow_theBook','theBorrow_duration','theBorrow_status1').first()
    row_obj = theBorrow.objects.filter(boid=boid).first()


    if not row_obj:
        return JsonResponse({"status": False, "error": "数据不存在!"})
    print('row_obj',row_obj)

    form = theBorrowModalShowForm(data=data,instance=row_obj)
    if form.is_valid():
        print('is_valid',request.POST)
        form.save()
        return JsonResponse({"status": True,"error":'fail-valid',})
    
    return JsonResponse({"status": False,"error":'fail-invalid',})




@csrf_exempt
def theBorrowlist_user_modal_delete(request):
    data = request.GET
    boid = request.GET.get('boid')
    print('delete-boid',boid)

    row_obj = theBorrow.objects.filter(boid=boid).first()

    if not row_obj:
        return JsonResponse({"status": False, "error": "数据不存在!"})
    else:
        theBorrow.objects.filter(boid=boid).first().delete()
        return JsonResponse({"status": True,"error":'fail-valid',})

step2:forms.py

theBorrowModalAddForm是新增时用的表单。
theBorrowModalShowForm是查询和编辑时用的表单。

class theBorrowModalAddForm(ModelForm):
    class Meta:
        model = theBorrow
        fields = '__all__'
        exclude = ['theBorrow_status2','theBorrow_status3',]

        # widgets = {
        # }
        
    # 循环找到所有的插件,加入css样式,添加 "class": "form-control"
    bootstrap_exclude_fields = []
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
            if name in self.bootstrap_exclude_fields:
                continue
            # class属性追加form-control,其他属性保留
            if field.widget.attrs:
                field.widget.attrs["class"] = field.widget.attrs.get('class','') + ' ' + 'form-control'
            else:
                field.widget.attrs = {
                    "class": "form-control",
                }



class theBorrowModalShowForm(ModelForm):
    boid = forms.CharField(label='boid',widget=wid.Input(attrs={"class":'edit','readonly':True}))
    # theBorrow_add_datetime = forms.CharField(label='theBorrow_add_datetime',widget=wid.Input(attrs={"class":'edit'}))
    class Meta:
        model = theBorrow
        fields = '__all__'
        exclude = ['theBorrow_status2','theBorrow_status3',]
 
        widgets = {
            # "theBorrow_theUser":wid.Select(attrs={"class":'edit',"readonly":'true'}),
            # "theBorrow_theBook":wid.Select(attrs={"class":'edit'}),
            # "theBorrow_duration":wid.NumberInput(attrs={"class":'edit'}),
            # "theBorrow_status1":wid.Select(attrs={"class":'edit'}),
        } 

    # 循环找到所有的插件,加入css样式,添加 "class": "form-control"
    bootstrap_exclude_fields = []
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
            if name in self.bootstrap_exclude_fields:
                continue
            # class属性追加form-control,其他属性保留
            if field.widget.attrs:
                field.widget.attrs["class"] = field.widget.attrs.get('class','') + ' ' + 'form-control'+ ' ' + 'edit'
            else:
                field.widget.attrs = {
                    "class": "form-control"+ ' ' + 'edit',
                }

step3:theBorrowlist_user.html

jQuery监听 doAdd(), doEdit(), doDelete()方法。

{% extends 'base.html' %}
{% load static %}

{% block body_block %}
<div class="container" id='app'>
    <div class="row py-4 align-items-center">
        
        <!--展示显示人员-->
        <div class="col-lg-12 col-md-12 mt-0 table-responsive"  style="background-color: #fff;">
            <!--表单-->
            <h3 class="font-weight-bold">预订清单<button class="ml-4 btn btn-light btnAdd">+</button></h3>
            <table class="table table-striped table-sm table-bordered ">
                <thead>
                    <tr style="color:White;background-color:#3366FF;font-family:微軟正黑體,Tahoma,Arial,微軟雅黑體;font-size:15px;">
                        <th scope="col">#</th>
                        <th scope="col">借订创建日期</th>
                        <th scope="col">借订更新日期</th>   
                        <th scope="col">借订人</th>
                        <th scope="col">借订书籍</th>
                        <th scope="col">借订状态1</th>
                        <th scope="col">操作</th>
                    </tr>
                </thead>
            
                <!--for theBorrow in theBorrowlist-->
                {% for theBorrow in page_obj %}
                <tr valign="middle" style="color:Black;border-color:#E0E0E0;font-size:15px;"></tr>
                    <td>{{ theBorrow.boid }}</td>
                    <td>{{ theBorrow.theBorrow_add_datetime|date:"Y-m-d" }}</td>
                    <td>{{ theBorrow.theBorrow_update_datetime|date:"Y-m-d" }}</td>
                    <td>{{ theBorrow.theBorrow_theUser }}</td>
                    <td>{{ theBorrow.theBorrow_theBook }}</td>
                    <td>{{ theBorrow.theBorrow_status1 }}</td>
                    <td>
                        <button type="button" class="btn btn-primary btnEdit"  boid="{{ theBorrow.boid }}">编辑</button>
                        <button type="button" class="btn btn-secondary btnDelete"  boid="{{ theBorrow.boid }}">删除</button>
                    </td>
                </tr>
                {% endfor %}
                
            </table>


            <!--分页功能-->
            <div class="pagination">
                <span class="step-links">
                    {% if page_obj.has_previous %}
                        <a href="/theBorrowlist_user/1/">&laquo; first</a>
                        <a href="/theBorrowlist_user/{{ page_obj.previous_page_number }}/">previous</a>
                    {% endif %}
            
                    <span class="current">
                            {{ page_obj.number }} / {{ page_obj.paginator.num_pages }}
                    </span>
            
                    {% if page_obj.has_next %}
                        <a href="/theBorrowlist_user/{{ page_obj.next_page_number }}/">next</a>
                        <a href="/theBorrowlist_user/{{ page_obj.paginator.num_pages }}/">last &raquo;</a>
                    {% endif %}
                </span>
            </div>

  
        <!-- Modal -->
        <div class="modal fade" data-backdrop="static" id="myModal1" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
            <div class="modal-dialog modal-dialog-centered" role="document" style="max-width: 600px;">
            <div class="modal-content">
                <div class="modal-header">
                <h5 class="modal-title" id="exampleModalCenterTitle">新增预定</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                </div>
                <div class="modal-body">


                    <form method="post" id="formSave1" enctype="multipart/form-data">
                        <div>

                            {% for item in AddForm %}
                            <div class="col-12">
                                <div class="form-group" style="position: relative; margin-top: 5px">
                                    <label>{{ item.label }}</label>
                                    {{ item }}
                                    <span class="error_msg" style="color: red;position: absolute;">{{ item.errors.0 }}</span>
                                </div>
                            </div>
                            {% endfor %}
                        </div>
                    </form>

                </div>
                <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
                <button type="button" id="btnSave1" class="btn btn-primary btnSave1">保存</button>
                </div>
            </div>
            </div>
        </div>


        <!-- Modal -->
        <div class="modal fade" data-backdrop="static" id="myModal2" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
            <div class="modal-dialog modal-dialog-centered" role="document" style="max-width: 600px;">
            <div class="modal-content">
                <div class="modal-header">
                <h5 class="modal-title" id="exampleModalCenterTitle">查看预订情况</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                </div>
                <div class="modal-body">


                    <form method="post" id="formSave2" enctype="multipart/form-data">
                        <div>

                            {% for item in ShowForm %}
                            <div class="col-12">
                                <div class="form-group" style="position: relative; margin-top: 5px">
                                    <label>{{ item.label }}</label>
                                    {{ item }}
                                    <span class="error_msg" style="color: red;position: absolute;">{{ item.errors.0 }}</span>
                                </div>
                            </div>
                            {% endfor %}
                        </div>
                    </form>

                </div>
                <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
                <button type="button" id="btnSave2" class="btn btn-primary btnSave2">保存</button>
                </div>
            </div>
            </div>
        </div>


       
        <!-- Modal -->
        <div class="modal fade" id="myModalDelete" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
            <div class="modal-dialog modal-dialog-centered" role="document">
            <div class="modal-content">
                <div class="modal-header">
                <h5 class="modal-title" id="exampleModalLabel">是否确定删除?</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                </div>
                <div class="modal-body">
                    <p>删除后所有关联的相关数据都将被删除</p>
                </div>
                <div class="modal-footer">
                <button  type="button" class="btn btn-primary" data-dismiss="modal">取消</button>
                <button id="btnConfirmDelete" type="button" class="btn btn-danger">确定</button>
                </div>
            </div>
            </div>
        </div>


        </div>
    </div>
</div>

<br>
<br>
<br>
<br>
<br>
{% endblock %}



{% block script %}
  <script type="text/javascript">
    var DELETE_ID;
    var EDIT_ID;

    $(function(){
        doAdd();
        doEdit();
        doDelete();
    })

    
    function doAdd(){
        $(".btnAdd").click(function(){
            $("#formSave1")[0].reset();
            $("#myModal1").modal('show');
        });
        $("#btnSave1").click(function(){
            $.ajax({
                url: "/theBorrowlist_user_modal_new/",
                type: "post",
                data: $("#formSave1").serialize(),
                dataType: "JSON",
                success: function (res) {
                    if (res.status) {
                        $("#myModal1").modal('hide');
                        console.log('#btnSave1',res.status)
                        // 刷新页面
                        location.reload();
                    } else {
                        alert('form invalid')
                        $("#myModal1").modal('show');
                        console.log('#btnSave1',res.status)
                    }
                }
            })
        });
    }


    function doDelete(){

        $(".btnDelete").click(function () {
            // 显示删除对话框
            $("#myModalDelete").modal('show');

            //获取当前行的ID
            DELETE_ID = $(this).attr("boid")
            console.log('Delete-boid-unconfirmed',DELETE_ID)

        });

        $("#btnConfirmDelete").click(function(){
            console.log('Delete-boid-confirmed',DELETE_ID)
            $.ajax({
                url: "/theBorrowlist_user_modal_delete/",
                type: "get",
                data:{
                    boid : DELETE_ID,
                },
                dataType: "JSON",
                success: function (res) {
                    if (res.status) {
                        console.log('Delete',res.status)
                        // 刷新页面
                        location.reload();
                    } else {
                        alert('Delete失败')
                        console.log('Delete',res.status)
                    }
                }
            })
        });
    }

    function doEdit(){
        //弹出
        $(".btnEdit").click(function(){

            EDIT_ID = $(this).attr("boid")
            console.log('Edit-boid',EDIT_ID)

            $.ajax({
                url: "/theBorrowlist_user_modal_show/",
                type: "get",
                data:{
                    boid : EDIT_ID,
                },
                dataType: "JSON",
                success: function (res) {
                    console.log('res',res)
                    if (res.status) {
                        $("#formSave2")[0].reset();
                        $.each(res.data, function (name, value) {
                            //同时选择edit类和id
                            $(".edit#id_" + name).val(value);
                            console.log('edit-show:',name,value)
                        });
                        // 显示对话框
                        $("#myModal2").modal('show');                      
                    } else {
                        alert(res.error);
                        $("#myModal2").modal('hide');
                    }
                }
            })
        });

        //保存变更
        $("#btnSave2").click(function(){
            console.log('EDIT_ID',EDIT_ID)
            $.ajax({
                url: "/theBorrowlist_user_modal_save/?boid="+EDIT_ID,
                type: "post",
                data: $("#formSave2").serialize(),
                dataType: "JSON",
                success: function (res) {
                    console.log('res',res)
                    if (res.status) {
                        // 显示对话框
                        $("#myModal2").modal('hide');
                        // 刷新页面
                        location.reload();                
                    } else {
                        alert(res.error);
                        // 显示对话框
                        $("#myModal2").modal('show');
                    }
                }
            })
            });
    }

  </script>


{% endblock %}

step4:urls.py

需定义好ajax请求的url path。

    # theBorrow_user增删改查
    path('theBorrowlist_user/', views.theBorrowlist_user, name='theBorrowlist_user'),
    path('theBorrowlist_user_modal_show/', views.theBorrowlist_user_modal_show, name='theBorrowlist_user_modal_show'),
    path('theBorrowlist_user_modal_new/', views.theBorrowlist_user_modal_new, name='theBorrowlist_user_modal_new'),
    path('theBorrowlist_user_modal_save/', views.theBorrowlist_user_modal_save, name='theBorrowlist_user_modal_save'),
    path('theBorrowlist_user_modal_delete/', views.theBorrowlist_user_modal_delete, name='theBorrowlist_user_modal_delete'),

step5:无法变更的值可以选择不显示

form.py利用exclude 属性隐藏不可修改的属性。


class theBorrowModalShowForm(ModelForm):
    boid = forms.CharField(label='boid',widget=wid.Input(attrs={"class":'edit','readonly':True}))
    # theBorrow_add_datetime = forms.CharField(label='theBorrow_add_datetime',widget=wid.Input(attrs={"class":'edit'}))
    class Meta:
        model = theBorrow
        fields = '__all__'

        # 无法更改的值直接不要显示
        exclude = ['theBorrow_theUser','theBorrow_theBook','theBorrow_duration','theBorrow_status2','theBorrow_status3',]
        # widgets = {
        #     "theBorrow_theUser":wid.Select(attrs={"class":'edit',"readonly":'true'}),
        #     "theBorrow_theBook":wid.Select(attrs={"class":'edit',"readonly":'true'}),
        #     "theBorrow_duration":wid.NumberInput(attrs={"class":'edit',"readonly":'true'}),#disabled
        # }
        

    # 循环找到所有的插件,加入css样式,添加 "class": "form-control"
    bootstrap_exclude_fields = []
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
            if name in self.bootstrap_exclude_fields:
                continue
            # class属性追加form-control,其他属性保留
            if field.widget.attrs:
                field.widget.attrs["class"] = field.widget.attrs.get('class','') + ' ' + 'form-control'+ ' ' + 'edit'
            else:
                field.widget.attrs = {
                    "class": "form-control"+ ' ' + 'edit',
                }

在这里插入图片描述

step6:单独显示readonly字段

在这里插入图片描述

theBorrowlist_user.html单独显示readonly字段,并利用ajax额外传值。

...

        <!-- Modal -->
        <div class="modal fade" data-backdrop="static" id="myModal2" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
            <div class="modal-dialog modal-dialog-centered" role="document" style="max-width: 600px;">
            <div class="modal-content">
                <div class="modal-header">
                <h5 class="modal-title" id="exampleModalCenterTitle">查看预订情况</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                </div>
                <div class="modal-body">


                    <form method="post" id="formSave2" enctype="multipart/form-data">
                        <div>
                            <div class="col-12">
                                <div class="form-group" style="position: relative; margin-top: 5px">
                                    <label >名字</label>
                                    <input class="form-control" type="text" id="theBorrow_theUser" readonly >                  
                                </div>
                            </div>

                            <div class="col-12">
                                <div class="form-group" style="position: relative; margin-top: 5px">
                                    <label >书籍</label>
                                    <input class="form-control" type="text" id="theBorrow_theBook" readonly >                  
                                </div>
                            </div>

                            {% for item in ShowForm %}
                            <div class="col-12">
                                <div class="form-group" style="position: relative; margin-top: 5px">
                                    <label>{{ item.label }}</label>
                                    {{ item }}
                                    <span class="error_msg" style="color: red;position: absolute;">{{ item.errors.0 }}</span>
                                </div>
                            </div>
                            {% endfor %}
                        </div>
                    </form>

                </div>
                <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
                <button type="button" id="btnSave2" class="btn btn-primary btnSave2">保存</button>
                </div>
            </div>
            </div>
        </div>

....
{% endblock %}



{% block script %}
  <script type="text/javascript">
    var DELETE_ID;
    var EDIT_ID;

    $(function(){
        doAdd();
        doEdit();
        doDelete();
    })

......

    function doEdit(){
        //弹出
        $(".btnEdit").click(function(){

            EDIT_ID = $(this).attr("boid")
            console.log('Edit-boid',EDIT_ID)

            $.ajax({
                url: "/theBorrowlist_user_modal_show/",
                type: "get",
                data:{
                    boid : EDIT_ID,
                },
                dataType: "JSON",
                success: function (res) {
                    console.log('res',res)
                    if (res.status) {
                        $("#formSave2")[0].reset();
                        //额外传值
                        $("#theBorrow_theUser").val(res.readonly_data.theBorrow_theUser);
                        $("#theBorrow_theBook").val(res.readonly_data.theBorrow_theBook);
                        //表单循环赋值
                        $.each(res.data, function (name, value) {
                            //同时选择edit类和id
                            $(".edit#id_" + name).val(value);
                            console.log('edit-show:',name,value)
                        });
                        // 显示对话框
                        $("#myModal2").modal('show');                      
                    } else {
                        alert(res.error);
                        $("#myModal2").modal('hide');
                    }
                }
            })
        });

.....
    }

  </script>


{% endblock %}

views.py利用row_obj2 = theBorrow.objects.filter(boid=boid).first()来实现额外传值

@csrf_exempt
def theBorrowlist_user_modal_show(request):

    boid = request.GET.get('boid')
    print('show-boid',boid)

    # values方法形成一个对象
    row_obj = theBorrow.objects.filter(boid=boid).values("boid", "theBorrow_add_datetime", "theBorrow_theUser",
                                                         'theBorrow_theBook','theBorrow_duration','theBorrow_status1'
                                                         ).first()
    row_obj2 = theBorrow.objects.filter(boid=boid).first()
    
    if not row_obj:
        return JsonResponse({"status": False, "error": "数据不存在!","boid":boid})
    else:
        # 从数据库中获取到一个对象 row_object
        result = {
            "status": True,
            "data": row_obj,
            "boid":boid,
            "readonly_data":{
                'theBorrow_theUser':str(row_obj2.theBorrow_theUser),
                'theBorrow_theBook':str(row_obj2.theBorrow_theBook),
            },
        }
        print('result',result)

        return JsonResponse(result)

参考文档

1.Django web 开发(四) - Django项目实践(九)-订单管理
2.https://docs.djangoproject.com/zh-hans/3.2/topics/forms/modelforms/#modelform
在这里插入图片描述
3.Django: Disabled Dropdown 不会将信息发送回 POSThttps://devpress.csdn.net/python/6300b81c7e66823466196d6e.html

  1. tips: save的功能实现时,ORM不要用value_list,否则会报错AttributeError:‘dict’对象没有属性’_meta’
    python - 在Django ModelAdmin中推进queryset。 AttributeError:‘dict’对象没有属性’_meta’

  2. 用Jquery取label标签时要用$(“#ID名称”).text()取值
    https://blog.csdn.net/zgf_along/article/details/6553045

数据验证

在这里插入图片描述

forms.py利用clean_theBorrow_status1(self)来实现,触发表单is_valid的认证。

class theBorrowModalShowForm(ModelForm):
    # boid = forms.CharField(label='boid',widget=wid.Input(attrs={"class":'edit','readonly':True}))
    # theBorrow_add_datetime = forms.CharField(label='theBorrow_add_datetime',widget=wid.Input(attrs={"class":'edit'}))
    class Meta:
        model = theBorrow
        fields = '__all__'

        # 无法更改的值直接不要显示
        exclude = ['theBorrow_theUser','theBorrow_theBook','theBorrow_duration','theBorrow_status2','theBorrow_status3',]

    # 循环找到所有的插件,加入css样式,添加 "class": "form-control"
    bootstrap_exclude_fields = []
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
            if name in self.bootstrap_exclude_fields:
                continue
            # class属性追加form-control,其他属性保留
            if field.widget.attrs:
                field.widget.attrs["class"] = field.widget.attrs.get('class','') + ' ' + 'form-control'+ ' ' + 'edit'
            else:
                field.widget.attrs = {
                    "class": "form-control"+ ' ' + 'edit',
                }

    # 数据校验: 验证方式2
    def clean_theBorrow_status1(self):
        theBorrow_status1 = self.cleaned_data['theBorrow_status1']
        if theBorrow_status1 == '借订中':
            # 验证不通过
            raise ValidationError('只能填写借订中')
        # 验证通过
        return theBorrow_status1

views.py

@csrf_exempt
def theBorrowlist_user_modal_save(request):
    data = request.POST
    print('save-data',data)
    boid = request.GET.get('boid')
    print('save-boid',boid)

    # values方法形成一个对象
    # row_obj = theBorrow.objects.filter(boid=boid).values("boid", "theBorrow_add_datetime", "theBorrow_theUser",'theBorrow_theBook','theBorrow_duration','theBorrow_status1').first()
    row_obj = theBorrow.objects.filter(boid=boid).first()


    if not row_obj:
        return JsonResponse({"status": False, "error": "数据不存在!"})
    print('row_obj',row_obj)

    form = theBorrowModalShowForm(data=data,instance=row_obj)
    if form.is_valid():
        print('is_valid',request.POST)
        form.save()
        return JsonResponse({"status": True,"error":'fail-valid',})
    
    return JsonResponse({"status": False,"error":'请检查借订状态',})

手机号搜索

Django web 开发(四) - Django项目实践(五)-靓号管理的【手机号搜索】
关键点在于:pretty_data = PrettyNum.objects.filter(**data_dict)

文件上传

文件上传(见武沛齐链接)

https://poker.blog.csdn.net/article/details/128736292

import re
from django.shortcuts import render,HttpResponse


def upload_list(request):

    if request.method == "GET":
        return render(request, "upload_list.html")

    # 声明图片的对象
    file_object = request.FILES.get("avatar")
    
    # 分块进行存储
    # file_object.name 表示图片上传时图片本身是什么名字,保存图片时就用什么名字
    f = open(file_object.name, mode='wb')
    for chunk in file_object.chunks():
        f.write(chunk)
    f.close()

    return HttpResponse("上传成功")

Excel上传(见短信平台做法)

在这里插入图片描述

template:利用form的enctype=“multipart/form-data”,并使用input控件添加文件。

    <div class="p-3 m-3">
        <!-- <div class="p-1 m-1"><h3>WZS HR短信群发平台</h3></div> -->

        <div class="p-1 m-1"><h5>1.请按格式上传excel文件</h5></div>
        <div class="pl-5"><a class="btn btn-secondary" href="/download_format">下载模板</a></div>
        <br>
        <form enctype="multipart/form-data" action="" method="POST">
            {% csrf_token %}
            <div class="pl-5">{{uf.as_p}}</div>
            

            <div class="p-1 m-1"><h5>2.请填写短信文本</h5></div>
            <br>
            <textarea  rows="5" cols="20" class="form-control w-50" type="text" name="shortmail_text" style="font-size:10px;"></textarea>
            <br>

            <div class="p-1 m-1"><h5>3.发送结果保存地址(everyone权限的公共盘)</h5></div>
            <div class="p-1 m-1"><input name="result_address" class="form-control w-50" /></div>

            <div class="pl-5"><input class="btn btn-secondary" type="submit" value="确认群发短信"/></div>
            
         </form>
    </div>

views.py处理上传excel并存在数据库

# 群发消息
@login_required
def send_mail(request):
    if request.method == "POST":  #验证POST
        uf = UploadEmployeeForm(request.POST,request.FILES) #.post是获取post返回字段,.FILES是获取返回的文件
        # print(uf)
        print(request.FILES['uploadfile'])
        content = request.POST['shortmail_text']
        result_address = request.POST['result_address']
        print('content',content)
        print('result_address',result_address)
        print('-----------')

        # 定义log收集
        successful_logs = []
        failed_logs = []
        all_logs = []

        if uf.is_valid() and content: #判断前台返回的表单是否为有效的类型
            ShortMail_Mobile_list = []
            wb = load_workbook(filename=request.FILES['uploadfile'])
            print(wb)
            ws = wb.get_sheet_names()
            ws = wb.get_sheet_by_name(ws[0])
            max_row = ws.max_row
            for row in range(2,max_row+1):
                #获取表单元素
                ShortMail_Mobile = ws.cell(row=row,column=3).value
                #非空则放入列表
                if ShortMail_Mobile:
                    ShortMail_Mobile_list.append(ShortMail_Mobile)
                    print('ShortMail_Mobile',ShortMail_Mobile)
                    result = obtain_by_serial(ShortMail_Mobile, content)
                    # 结果写入表格
                    print('result',result)
                    ws.cell(row=row,column=10).value = str(result)
                    
                    # 结果存入列表中并返回前端
                    
                    if 'True' in str(result):
                        all_logs.append('手机号:'+str(ShortMail_Mobile)+',发送成功')
                        successful_logs.append(ShortMail_Mobile)
                    else:
                        all_logs.append('手机号:'+str(ShortMail_Mobile)+',发送失败')
                        failed_logs.append(ShortMail_Mobile)

            # 保存结果
            try:
                wb.save(result_address+'result.xlsx')
                print('ShortMail_Mobile-保存成功')
            except Exception as e:
                print('ShortMail_Mobile-保存不成功')
                print(e)

            return render(request,'successful.html',locals())
        
    else:
        uf = UploadEmployeeForm()
    return render(request,'send_shortmail.html',{'uf':uf})

ModelForm上传照片(图书管理系统做法)

在这里插入图片描述

models.py

THEBOOK_TYPE = (('电子书', '电子书'), ('纸质书', '纸质书'), ('PPT', 'PPT'),('项目', '项目'), ('视频', '视频'),('其他', '其他'))
THESTATUS_TYPE = (('已借订', '已借订'), ('未借订', '未借订'))

class theBook(models.Model):
    bid = models.AutoField(primary_key=True)
    theBook_name = models.CharField(max_length=500,verbose_name=('图书名称'),)
    theBook_location = models.ForeignKey(location,blank=True, null=True, on_delete=models.CASCADE,related_name='Book_location')
    theBook_type = models.CharField(max_length=500, verbose_name=('电子书/纸质书'),choices=THEBOOK_TYPE,)
    theBook_category = models.ForeignKey(category,blank=True, null=True, on_delete=models.CASCADE,related_name='Book_category')
    theBook_logo = models.ImageField(max_length=500, verbose_name=('图书照片1'),upload_to='images/')
    theBook_attachment = models.FileField(max_length=10000,verbose_name=('图书附件(备用)'),blank=True, null=True,upload_to='file')
    theBook_status1 = models.CharField(max_length=500,verbose_name=('图书状态1'),choices=THESTATUS_TYPE,)
    theBook_status2 = models.CharField(max_length=500,verbose_name=('图书状态2(备用)'),blank=True, null=True,)
    theBook_status3 = models.CharField(max_length=500,verbose_name=('图书状态3(备用)'),blank=True, null=True,)
    theBook_id = models.CharField(max_length=500,verbose_name=('图书编号(备用)'),blank=True, null=True,)
    theBook_information1 = models.TextField(max_length=10000,verbose_name=('图书信息1'),blank=True, null=True,)
    theBook_information2 = models.TextField(max_length=10000,verbose_name=('图书信息2(备用)'),blank=True, null=True,)
    theBook_information3 = models.TextField(max_length=10000,verbose_name=('图书信息3(备用)'),blank=True, null=True,)
    theBook_information4 = models.TextField(max_length=10000,verbose_name=('图书信息4(备用)'),blank=True, null=True,)
    theBook_information5 = models.TextField(max_length=10000,verbose_name=('图书信息5(备用)'),blank=True, null=True,)

    class Meta:
        verbose_name = ('图书')
        verbose_name_plural = ('图书')
        ordering = ['theBook_category'] # 返回值排序


    def __str__(self):
        return str(self.theBook_category)+str(self.theBook_name)

forms.py

class theBookForm(ModelForm):
    class Meta:
        model = theBook
        fields = '__all__'
        exclude = ['theBook_id','theBook_attachment','theBook_status1','theBook_status2','theBook_status3','theBook_information2',
                   'theBook_information3','theBook_information4','theBook_information5',]
        error_messages = {
            'theBook_name':{'required':"theBook_name不能为空",},
        }

        # labels= {
        #     "theBook_name":"自定义书名"
        # }

        widgets = {
            "theBook_name":wid.Input(attrs={"class":"c1"}) #还可以自定义属性
        }


    # 循环找到所有的插件,加入css样式,添加 "class": "form-control"
    bootstrap_exclude_fields = ['theBook_logo',]
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
            if name in self.bootstrap_exclude_fields:
                continue
            # class属性追加form-control,其他属性保留
            if field.widget.attrs:
                field.widget.attrs["class"] = field.widget.attrs.get('class','') + ' ' + 'form-control'
            else:
                field.widget.attrs = {
                    "class": "form-control",
                }

views.py直接引用ModelForm


def theBooklist_new(request):

    if request.method == "GET":
        form = theBookForm()
        return render(request,'theBooklist_new.html',{'form':form})
    
    # 用户POST请求提交数据,需要进行数据校验
    form = theBookForm(data=request.POST,files=request.FILES)
    if form.is_valid():
        # print(form.cleaned_data)
        # 直接保存至数据库
        form.save()
        return redirect("/theBooklist_show/")

    return render(request,'theBooklist_new.html',{'form':form})

参考文档

DjangoWeb框架基础

https://blog.csdn.net/qq_39330486/article/details/120292603
在这里插入图片描述

jQuery

Django web开发(一) - 前端中的【7.jQuery】

专业图标网fontawesome

【图标】fontawesome专业图标网–20230413

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值