第7次:表单

在Django框架中,有两种定义表单的方式。

  1. 在HTML中可使用<form>标签定义表单域,此表单域中再包含单选或多行文本框、密码框、单选按钮、复选按框、下拉选择框等元素。这种方式的特点是使用纯粹的HTML和CSS知识实现,学习的成本较低,更适用于对前端HTML比较擅长的同学。

  2. 在Python代码中通过Form类或其子类也可以定义表单。因表单类生成的表单不包含<form>标签,使用时须将其嵌入到<form>标签中。这种方式的特点是可复用表单类或表单类的部分属性,这种方式适用于喜欢写Python代码的同学。当然,这种实现方式同样可以使用CSS美化、装修。

本次学习的重点是表单类的实现方式。

7.1 继承Form类的表单

准备工作:创建Django项目chapter07,并创建应用app01,在此应用下创建forms.py模块,用于定义所有的表单。

第一步:在forms.py中定义表单类LoginForm类,

#forms.py
from django import forms
​
class LoginForm(forms.Form):
    username = forms.CharField(max_length=20, min_length=2, required=True,
                               label='用户名',
                               error_messages={
                                   'min_length': '用户名不能小于2个字符'
                               })
    password = forms.CharField(widget=forms.PasswordInput, label='密码')
第二步:定义视图函数
from django.http import HttpResponse
from django.shortcuts import render
​
from app01.forms import LoginForm
​
def login(request):
    # Post请求
    if request.method == 'POST':
        # 根据接收到的数据创建表单类对象
        loginForm = LoginForm(request.POST)
        if loginForm.is_valid():
            # 取数据的方法
            username = loginForm.cleaned_data.get('username')
            password = loginForm.cleaned_data.get('password')
            return HttpResponse(f'{username}--{password}')
        else:
            print(loginForm.errors)
            return HttpResponse('表单验证失败')
    # get 请求
    elif request.method == 'GET':
        # 创建空表单
        loginForm = LoginForm()
        return render(request, 'index.html', {'loginForm': loginForm})

第三步:定义路由,项目urls.py中

from django.urls import path
​
from app01.views import login
​
urlpatterns = [
    path('login/', login),
]

第四步:在templates中创建index.html模板

<body>
<h2>表单示例</h2>
<form action="" method="post">
    {% csrf_token %}
    {{ loginForm }}
    <input type="submit" value="提交">
</form>
</body>

7.2 继承ModelForm类的表单

为了方便对比,此处先用HTML表单实现,再改造为ModelForm表单。

7.2.1 HTML表单实现方式

在7.1项目基础上创建goods应用

python manage.py startapp goods

项目底下创建templates文件夹,在文件夹里创建goods.html文件

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>商品列表</title>
</head>
<body>
<div>
    <table id="myTable" cellpadding="1" cellspacing="0" border="1"
           style="width:100%;max-width: 100%;margin-bottom: 20px ">
        <caption align="top" style="font-size: 26px">商品列表</caption>
        <thead>
        <tr>
            <th>序号</th>
            <th>名字</th>
            <th>价格</th>
            <th>库存</th>
            <th>销量</th>
            <th>管理</th>
        </tr>
        </thead>
        <tbody>
        {% for row in goods %}
            <tr align="center">
                <td>{{ forloop.counter }}</td>
                <td>{{ row.name }}</td>
                <td>{{ row.price }}</td>
                <td>{{ row.stock }}</td>
                <td>{{ row.sales }}</td>
                <td>
                    <a href="goods/{{ row.id }}">删除</a>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
</div>
<div>
    {#  表单一:添加  #}
    <form method="post" action="/info/" cellpadding="1" cellspacing="0"
          border="1">
        {% csrf_token %}
        <input type="submit" value="添加">
        商品:<input type="text" name="good_name">
        价格:<input type="text" name="good_price">
        库存:<input type="text" name="good_stock">
        销量:<input type="text" name="good_sales">
    </form>
</div>
<div>
    {#                            表单二:修改                              #}
    <form method="post" action="/goods/" cellpadding="1" cellspacing="0"
          border="1">
        {% csrf_token %}
        <input type="submit" value="修改">
        序号:<input type="text" name="good_num">
        商品:<input type="text" name="good_name">
        价格:<input type="text" name="good_price">
        库存:<input type="text" name="good_stock">
        销量:<input type="text" name="good_sales">
    </form>
</div>
</body>
</html>

goods应用下的models里定义goods模型

from django.db import models

class Goods(models.Model):
    """商品SKU"""
    # 可以利用null和blank属性使部分字段留空
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    name = models.CharField(max_length=50, verbose_name='名字')
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='价格')
    stock = models.IntegerField(default=0, verbose_name='库存')
    sales = models.IntegerField(default=0, verbose_name='销量')

    class Meta:
        db_table = 'tb_goods'
        verbose_name = '商品'
        verbose_name_plural = verbose_name

    def __str__(self):
        return f'name: {self.name}, price: {self.price}, stock: {self.stock}, sales: {self.sales}'

生成迁移文件并执行迁移

python manage.py makemigrations
python manage.py migrate

在goods应用下的views.py文件里定义视图类,展示商品和删除商品的逻辑。然后分别在类GoodView和UpdateDestoryGood中实现商品展示和删除的功能。

from django.shortcuts import render, redirect, reverse
from django.views import View
from django import http
from .models import Goods
​
​
class GoodView(View):
    """商品视图类"""
​
    def get(self, request):
        """展示商品"""
        goods = Goods.objects.all()
        context = {
            'goods': goods,
        }
        return render(request, 'goods.html', context)
​
    def post(self, request):
        """添加商品"""
        good = Goods()
        try:
            good.name = request.POST.get('good_name')
            good.price = request.POST.get('good_price')
            good.stock = request.POST.get('good_stock')
            good.sales = request.POST.get('good_sales')
            good.save()
            # return redirect('goods/info/')  # 快捷方式
            return redirect(reverse('goods:info'))
        except Exception as e:
            print(e)
            return http.HttpResponseForbidden('数据错误')
​
​
class UpdateDestoryGood(View):
    """编辑或删除商品"""
​
    def get(self, request, gid):
        """删除商品数据"""
        try:
            good = Goods.objects.get(id=gid)
            good.delete()
        except Exception as e:
            print(e)
            return http.HttpResponseForbidden('删除失败')
        return redirect(reverse('goods:info'))
​
    def post(self, request, gid=0):
        """编辑商品"""
        num = request.POST.get('good_num')
        print(type(num))
        one_goods = Goods.objects.all()[int(num) - 1]
        print(one_goods)
        one_goods.name = request.POST.get('good_name')
        one_goods.price = request.POST.get('good_price')
        one_goods.stock = request.POST.get('good_stock')
        one_goods.sales = request.POST.get('good_sales')
        # one_goods.save()
        Goods.objects.filter(id=one_goods.id).update(price=one_goods.price, stock=one_goods.stock,
                                                     sales=one_goods.sales, name=one_goods.name)
        return redirect(reverse('goods:info'))

配置根路由urls.py

from django.urls import path, include

from app01.views import login

urlpatterns = [
    path('login/', login),
    path('', include('goods.urls')),
]

(2)goods/urls.py

from django.urls import path, re_path

from goods import views
app_name = 'goods'
urlpatterns = [
    # 展示商品数据、添加商品
    path('info/', views.GoodView.as_view(), name='info'),
    # 修改删除商品
    re_path('goods/(\d*)', views.UpdateDestoryGood.as_view()),
]

利用数据文件goods.sql插入商品数据,

INSERT INTO tb_goods (create_time, update_time, name, price, stock, sales) VALUES
('2019-09-11 17:28:21.804713', '2019-09-25 11:09:04.532866', 'Apple MacBook Pro 13.3英寸笔记本 银色', 11388, 5, 5),
('2019-09-12 06:53:54.575306', '2019-09-23 11:44:03.825103', 'Apple MacBook Pro 13.3英寸笔记本 深灰色', 11398, 0, 1),
('2019-09-14 02:14:04.599169', '2019-09-20 02:28:13.579856', 'Apple iPhone 11 Pro 256GB 香芋紫', 6499, 6, 4),
('2019-09-14 02:20:33.355996', '2019-09-14 17:27:12.736139', 'Apple iPhone 11 Plus 256GB 金色', 7988, 8, 2),
('2019-09-14 02:45:23.341909', '2019-09-14 17:27:17.181609', 'Apple iPhone 11 Plus 64GB 深空灰色', 6688, 10, 0),
('2019-09-14 02:49:40.912682', '2019-09-25 11:09:35.936530', 'Apple iPhone 11 Plus 256GB 深空灰色', 7988, 0, 5),
('2019-09-14 02:55:11.172604', '2019-09-14 17:27:28.772353', 'Apple iPhone 11 Plus 64GB 银色', 6688, 3, 0),
('2019-09-14 02:56:17.331169', '2019-09-14 17:27:34.536772', 'Apple iPhone 11 Plus 256GB 银色', 7988, 9, 1),
('2019-09-14 03:09:00.909709', '2019-09-14 17:27:40.624770', '华为 HUAWEI Pro 30 6GB+64GB 钻雕金', 3388, 4, 0),
( '2019-09-14 03:13:40.226704', '2019-09-25 11:06:55.087206', '华为 HUAWEI Pro 30 6GB+128GB 钻雕金', 3788, 3, 0),
( '2019-09-14 03:16:27.620102', '2019-09-25 10:56:51.267674', '华为 HUAWEI Pro 30 6GB+128GB 钻雕蓝', 3788, 5, 0),
( '2019-09-14 03:17:25.671905', '2019-09-14 17:28:06.649098', '华为 HUAWEI Pro 30 6GB+64GB 钻雕蓝', 3388, 5, 0),
( '2019-09-14 03:18:04.588296', '2019-09-14 17:28:23.886231', '华为 HUAWEI Pro 30 6GB+64GB 玫瑰金', 3388, 5, 0),
( '2019-09-14 03:19:03.691772', '2019-09-25 11:10:51.316291', '华为 HUAWEI Pro 30 6GB+128GB 玫瑰金', 3788, 0, 4),
( '2019-09-20 02:27:04.955931', '2019-09-20 02:27:04.956931', 'Apple iPhone 11 Pro 256GB 香芋紫', 6499, 6, 3);

7.2.2 使用表单类

1、在goods应用中创建forms.py,在其中定义表单类,代码如下:

from django import forms
from django.forms import ModelForm
from django.forms import formset_factory
from . import models
from .models import Goods
​
​
class GoodForm(ModelForm):
    class Meta:
        model = Goods
        fields = ['name', 'price', 'sales', 'stock']

2、goods.html修改为

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>商品列表</title>
</head>
<body>
<div>
    <table id="myTable" cellpadding="1" cellspacing="0" border="1"
           style="width:100%;max-width: 100%;margin-bottom: 20px ">
        <caption align="top" style="font-size: 26px">商品列表</caption>
        <thead>
        <tr>
            <th>序号</th>
            <th>名字</th>
            <th>价格</th>
            <th>库存</th>
            <th>销量</th>
            <th>管理</th>
        </tr>
        </thead>
        <tbody>
        {% for row in goods %}
            <tr align="center">
                <td>{{ forloop.counter }}</td>
                <td>{{ row.name }}</td>
                <td>{{ row.price }}</td>
                <td>{{ row.stock }}</td>
                <td>{{ row.sales }}</td>
                <td>
                    <a href="goods/{{ row.id }}">删除</a>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
</div>
<div>
    {#  表单一:添加  #}
    <form method="post" action="/info/" cellpadding="1" cellspacing="0"
          border="1">
        {% csrf_token %}
        <input type="submit" value="添加">
        {#        商品:<input type="text" name="good_name">#}
        {#        价格:<input type="text" name="good_price">#}
        {#        库存:<input type="text" name="good_stock">#}
        {#        销量:<input type="text" name="good_sales">#}
​
        {{ form }}
        {#        {{ form.as_table }}#}
    </form>
</div>
<div>
    {#                            表单二:修改                              #}
    <form method="post" action="/goods/" cellpadding="1" cellspacing="0"
          border="1">
        {% csrf_token %}
        <input type="submit" value="修改">
        {#        序号:<input type="text" name="good_num">#}
        {#        商品:<input type="text" name="good_name">#}
        {#        价格:<input type="text" name="good_price">#}
        {#        库存:<input type="text" name="good_stock">#}
        {#        销量:<input type="text" name="good_sales">#}
        序号: <input type="text" name="good_num">
        {{ form }}
        {#        {{ form.as_table }}#}
    </form>
</div>
</body>
</html>

goods应用下视图文件修改

from django.shortcuts import render, redirect, reverse
from django.views import View
from django import http
​
from app01.forms import GoodForm
from .models import Goods
​
​
class GoodView(View):
    """商品视图类"""
​
    def get(self, request):
        """展示商品"""
        # goods = Goods.objects.all()
        # context = {
        #     'goods': goods,
        # }
        # return render(request, 'goods.html', context)
        # 使用表单
        goods = Goods.objects.all()
        form = GoodForm()
        context = {
            'goods': goods,
            'form': form,
        }
        return render(request, 'goods.html', context)
    def post(self, request):
        """添加商品"""
        # good = Goods()
        # try:
        #     good.name = request.POST.get('good_name')
        #     good.price = request.POST.get('good_price')
        #     good.stock = request.POST.get('good_stock')
        #     good.sales = request.POST.get('good_sales')
        #     good.save()
        #     # return redirect('goods/info/')  # 快捷方式
        #     return redirect(reverse('goods:info'))
        # except Exception as e:
        #     print(e)
        #     return http.HttpResponseForbidden('数据错误')
        
        # 使用表单
        good = Goods()
        # 使用已提交的数据实例化NameForm
        form = GoodForm(request.POST)
        # 判断表单是否已验证,获取已验证的数据
        if form.is_valid():
            good_data = form.cleaned_data
            good.name = good_data['name']
            good.price = good_data['price']
            good.stock = good_data['stock']
            good.sales = good_data['sales']
            try:
                good.save()
            except:
                return http.HttpResponseForbidden('数据错误')
        return redirect(reverse('goods:info'))
​
class UpdateDestoryGood(View):
    """编辑或删除商品"""
​
    def get(self, request, gid):
        """删除商品数据"""
        try:
            good = Goods.objects.get(id=gid)
            good.delete()
        except Exception as e:
            print(e)
            return http.HttpResponseForbidden('删除失败')
        return redirect(reverse('goods:info'))
​
    def post(self, request, gid=0):
        """编辑商品"""
        # num = request.POST.get('good_num')
        # print(type(num))
        # one_goods = Goods.objects.all()[int(num) - 1]
        # print(one_goods)
        # one_goods.name = request.POST.get('good_name')
        # one_goods.price = request.POST.get('good_price')
        # one_goods.stock = request.POST.get('good_stock')
        # one_goods.sales = request.POST.get('good_sales')
        # # one_goods.save()
        # Goods.objects.filter(id=one_goods.id).update(price=one_goods.price, stock=one_goods.stock,
        #                                              sales=one_goods.sales, name=one_goods.name)
        # return redirect(reverse('goods:info'))
        # 使用表单
        goods = Goods.objects.all()
        count = goods.count()
        form = GoodForm(request.POST)
        good_num = request.POST.get('good_num')
        if form.is_valid():
            good_data = form.cleaned_data
            for i in range(1, count + 1):
                if i == int(good_num):
                    good = goods[i - 1]
                    good.name = good_data['name']
                    good.price = good_data['price']
                    good.stock = good_data['stock']
                    good.sales = good_data['sales']
                    try:
                        good.save()
                        break
                    except Exception as e:
                        return http.HttpResponseForbidden('编辑失败')
        return redirect(reverse('goods:info'))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值