用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()
...
共有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:41hi,又是我。我按照你的文档来操作的。目前我新增账单的时候,响应是302,我看了请求,发现除了csrfmiddlewaretoken之外,没有其他值传进去。新手一枚,能指点下我应该从哪里来修改问题么?十分感谢
zaman
2021年2月8日 19:21source code?
Bo
2021年1月25日 11:01@q 是的,需要import这个form文件,views里面新增的用到了新加的form class
q
2021年1月21日 16:04views.py 新加的函数是不是需要导包?form.py?