Bob's Blog

Web开发、测试框架、自动化平台、APP开发、机器学习等

返回上页首页

用Django做一个简单的记账网站(八)提交表单



账单记录的控件都添加了,也加上了异步的类型数据交互,接下来就可以提交表单将数据提交到后端保存。

在前面的文章中已经定义了数据model,我们可以根据账单的model来添加form的定义,这里可以直接用到ModelForm,会简单一些,先新建一个forms.py:

from django import forms
from .models import HistoryRecord

class HistoryRecordForm(forms.ModelForm):
    class Meta:
        model = HistoryRecord
        exclude = ['created_date', 'updated_date']

然后更新一下html页面的元素,将账单的控件都放在<form></form>中,添加对应的name属性,并指定到后端的方法来处理数据:

<form action="{% url 'record_income_expense' %}" method="post" class="history-record-form">
    {% csrf_token %}
    <div class="form-row">
        <div class="col-md-3 mb-3">
            <select class="custom-select" id="account-list" name="account">
                {% for a in accounts %}
                <option value="{{ a.id }}">{{ a.name }}</option>
                {% endfor %}
            </select>
        </div>
        <div class="col-md-3 mb-3">
            <select class="custom-select" id="ie-type-list">
                {% for ie in ie_types %}
                <option value="{{ ie.1 }}">{{ ie.0 }}</option>
                {% endfor %}
            </select>
        </div>
        <div class="col-md-3 mb-3">
            <select class="custom-select" id="category-list" name="category">
            </select>
        </div>
        <div class="col-md-3 mb-3">
            <select class="custom-select" id="sub-category-list" name="sub_category">
            </select>
        </div>
    </div>
    <div class="form-row">
        <div class="col-md-5 mb-3">
            <div class="input-group">
                <div class="input-group-prepend">
                    <select class="custom-select" id="currency-list" name="currency">
                    {% for c in currencies %}
                    <option value="{{ c.id }}">{{ c.name }}</option>
                    {% endfor %}
                    </select>
                </div>
                <input type="text" name="amount" aria-label="Money Amount" placeholder="金额" class="form-control" required="">
            </div>
        </div>
        <div class="col-md-7 mb-3">
            <input type="text" name="comment" aria-label="Comment" placeholder="备注" class="form-control">
        </div>
    </div>
    <div class="form-row">
        <div class="col-md-4 mb-3">
            <input id="time-occurrence" name="time_of_occurrence" type="text" class="form-control">
        </div>
        <div class="col-md-8 mb-3">
            <button type="submit" class="btn btn-info btn-block">记录账单</button>
        </div>
    </div>
</form>

form指向了url 'record_income_expense',于是在views.py中添加处理数据的代码,用来获取post过来的数据,判断form是否合法等。因为子类别允许不提交数据,于是多可以加个判断:

def record_income_expense(request):
    sub_category = request.POST.get('sub_category')
    time_now = timezone.now()
    if sub_category == "select value":
        try:
            account = request.POST.get('account')
            category = request.POST.get('category')
            currency = request.POST.get('currency')
            amount = request.POST.get('amount')
            comment = request.POST.get('comment')
            time_occur = request.POST.get('time_of_occurrence')
            history_record = HistoryRecord(account_id=account,
                                           category_id=category,
                                           currency_id=currency,
                                           amount=amount,
                                           comment=comment,
                                           time_of_occurrence=time_occur,
                                           created_date=time_now,
                                           updated_date=time_now
                                           )
            history_record.save()
        except Exception as e:
            print("not valid in request with error: %s" % str(e))
    else:
        form = HistoryRecordForm(request.POST)
        if form.is_valid():
            account = form.cleaned_data['account']
            category = form.cleaned_data['category']
            sub_category = form.cleaned_data['sub_category']
            currency = form.cleaned_data['currency']
            amount = form.cleaned_data['amount']
            comment = form.cleaned_data['comment']
            time_occur = form.cleaned_data['time_of_occurrence']
            history_record = HistoryRecord(account=account,
                                           category=category,
                                           sub_category=sub_category,
                                           currency=currency,
                                           amount=amount,
                                           comment=comment,
                                           time_of_occurrence=time_occur,
                                           created_date=time_now,
                                           updated_date=time_now
                                           )
            history_record.save()
        else:
            print("not valid in form")
    return redirect(index)

接着更新一下urls.py:

urlpatterns = [
    ...
    path('record_income_expense/', views.record_income_expense, name='record_income_expense'),
    ...
]

此时运行python manage.py runserver后,在页面选择类别填入数目文字便可提交到后端并保存进数据库了。

在记录了账单后,应该把对应的账户的余额做修改,所以别忘了更新account的值,比如当form是valid时,可以在上面的record_income_expense的后面加上如下片段,不过如果是取request.POST的值那么下面的需要改一点:

...
current_ie_type = category.category_type
if current_ie_type.lower() == "expense":
    account.amount -= decimal.Decimal(amount)
elif current_ie_type.lower() == "income":
    account.amount += decimal.Decimal(amount)
account.save()
...

 

下一篇:  用Django做一个简单的记账网站(九)自定义模板过滤器
上一篇:  用Django做一个简单的记账网站(七)添加日期时间选择器

共有12条评论

添加评论

HP
2023年4月12日 14:03
显示not valid in form
HP
2023年4月12日 13:43
代码一样,但是提交了但是没有写进数据库中
Yako
2021年3月2日 18:24
@Bo, 好的,十分感谢。
Bo
2021年3月2日 17:37
@Yako "select value"是html里下拉框的默认值,判断是否选值,这个看自己怎么定义就行
Yako
2021年3月2日 17:35
我想问一下视图函数里if sub_category == "select value":这个判断是做什么用的,是判断分类的下拉选项不能空吗,那"select value"值又是怎么来的?
Bo
2021年2月26日 17:35
@tracy 你看看log里是不是有提示表单数据not valid之类的字样,我想会不会是提交的数据校验不通过
tracy
2021年2月26日 16:54
我看了admin的history records里也没有数据。 我的请求数据没进去,怎么解决呢?
Bo
2021年2月26日 16:50
@tracy 302是没错的,提交表单后是redirect(index),这里没有动态添加记录在页面上,因为有比较多的情况,所以会重定向到首页展示最新的账单记录
tracy
2021年2月26日 16:41
hi,又是我。我按照你的文档来操作的。目前我新增账单的时候,响应是302,我看了请求,发现除了csrfmiddlewaretoken之外,没有其他值传进去。新手一枚,能指点下我应该从哪里来修改问题么?十分感谢
zaman
2021年2月8日 19:21
source code?
Bo
2021年1月25日 11:01
@q 是的,需要import这个form文件,views里面新增的用到了新加的form class
q
2021年1月21日 16:04
views.py 新加的函数是不是需要导包?form.py?