我对python(3.5)/ django(1.10)相当新,我遇到了以下问题:
我正在使用Django的通用CreateView来创建模型和相应的子模型。
我的目标是保存购买信息。购买由一个账单和一个或多个收据组成。为此,我创建了一个自定义表单(BillForm
),其中包含一个自定义字段,用户可以输入将用于创建收据的逗号分隔值。
这就是我所拥有的:
models.py
class Bill(models.Model):
""" A given bill whenever an item is purchased."""
number = models.CharField(_('Number'), max_length=20)
purchase_date = models.DateTimeField(_('Purchase Date'))
company = models.ForeignKey(Company, verbose_name=_('Company'),
on_delete=models.DO_NOTHING)
...
def _get_receipts(self):
''' returns all receipts that related to a bill '''
return Receipt.objects.filter(bill = self)
receipts = property(_get_receipts)
class Receipt(models.Model):
""" A receipt confirming a product is in our posession """
number = models.CharField(_('Number'), max_length=20)
bill = models.ForeignKey(Bill, verbose_name=_('Bill'),
on_delete=models.DO_NOTHING)
urls.py:
url(_(r'^create_purchase/$'), views.ObjectCreateView.as_view(
model=Bill,
form_class=BillForm
),
name="create_purchase"),
forms.py:
class MultipleReceiptsField(forms.Field):
''' A custom field to store a list of coma separated receipts '''
def to_python(self, value):
''' Normalize data to a set of receipts numbers '''
if not value:
return set()
return set(v.strip() for v in value.split(',') if v.strip())
def validate(self, value):
''' check if the values passed are less than 20 char long (limit for
model). '''
super(MultipleReceiptsField, self).validate(value)
# had made the following a tuple, then updated to list and worked
invalid_receipts = [r for r in value if len(r) > 20]
if invalid_receipts:
# EXCEPTION THROWN HERE BUT NOT PROPAGATED
raise ValidationError(
[ValidationError(_("Length of receipt %(r) is too large (max 20 characters)"),
code=INVALID_PARAMS, params={'r':int(r)}) # it was params={r:r} should have used 'r'
for r in invalid_receipts]
)
class BillForm(forms.ModelForm):
''' A form used to create a Purchase Bill. '''
receipts = MultipleReceiptsField(label=_("Receipts"), widget=forms.Textarea)
def __init__(self, *args, **kwargs):
''' constructor used to filter the companies. '''
# executes
super(BillForm, self).__init__(*args, **kwargs)
self.fields['company'].queryset =\ Company.objects.filter(is_provider=True).filter(is_active=True)
def save(self, commit=True):
''' createe receipts when saving a bll '''
# save logic | NEVER EXECUTES...
# for each elementt in receipts, create a receipt object and
# set its bill value to the bill that we just created
bill = super(BillForm, self).save(commit=False)
receipts_cd = self.cleaned_data["receipts"]
...
return bill
class Meta:
model = Bill
fields = ('company', "number", "currency", "price", "receipts")
view.py:
class ObjectCreateView(IsInPurchaseGroup, CreateView):
model = None
form_class = None
#fields = "__all__"
template_name = "purchases/object_form.html"
def get_context_data(self, **kwargs):
context = super(ObjectCreateView, self).get_context_data(**kwargs)
context["title"] = str(ACTIONS[CREATE_ACTION]) + " " +\
str(self.model._meta.verbose_name)
context["button"] = ACTIONS[CREATE_ACTION]
return context
def get_success_url(self):
next_url, kwargs = get_next_url(self.request)
if not next_url:
# works because the pluralization of both models end with s
next_url =\
"purchases:{}s".format((str(self.model).split(".")[-1])[:-2])
# if i am creating a bill, then i must navigate to
# create_purchased_products in the warehouse department.
if self.model == Bill:
next_url = "warehouse:create_purchased_products"
kwargs = {"receipts" : self.object.receipts}
return reverse_lazy(next_url, kwargs=kwargs)
object_form.html
{% extends "purchases/base.html" %}
{% load i18n %}
{% block body %}
<h3>{{ title }}</h3>
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
<form action="" method="post">{% csrf_token %}
<table>{{ form.as_table }}</table>
<div class="buttons">
<input type="Submit" value="{{ button }}"/>
</div>
</form>
{% endblock %}
每当在网址上提供form_class时,以下功能都不会被执行:
如果我省略url上的form_class并设置变量fields = "__all__"
(只是创建我的Bill模型的对象),则调用方法ObjectCreateView.get_success_url()
。
为什么BillForm.save()
和ObjectCreateView.get_success_url()
没有被执行?我知道BillForm
有问题,但我似乎无法理解......
非常感谢任何帮助。
MultipleReceiptsField.validate()
中抛出了一些例外,但它们没有被传播(当我提交表单时,我没有获得异常,只是保留在发布时)。invalid_receipts
变量从元组更新为列表并开始工作我是否错过了元组和列表之间的一些细微差别?
forms.py - 无效:
class MultipleReceiptsField(forms.Field):
''' A custom field to store a list of coma separated receipts '''
def to_python(self, value):
''' Normalize data to a set of receipts numbers '''
if not value:
return set()
return set(v.strip() for v in value.split(',') if v.strip())
def validate(self, value):
''' check if the values passed are less than 20 char long (limit for
model). '''
super(MultipleReceiptsField, self).validate(value)
invalid_receipts = (r for r in value if len(r) > 20)
if invalid_receipts:
raise ValidationError(
[ValidationError(_("Length of recipt %(r) is too large (max 20 characters)"),
code=INVALID_PARAMS, params={'r':int(r)})
for r in invalid_receipts]
)
forms.py - working:
lass MultipleReceiptsField(forms.Field):
''' A custom field to store a list of coma separated receipts '''
def to_python(self, value):
''' Normalize data to a set of receipts numbers '''
if not value:
return set()
return set(v.strip() for v in value.split(',') if v.strip())
def validate(self, value):
''' check if the values passed are less than 20 char long (limit for
model). '''
super(MultipleReceiptsField, self).validate(value)
invalid_receipts = [r for r in value if len(r) > 20]
if invalid_receipts:
raise ValidationError(
[ValidationError(_("Length of receipt %(r) is too large (max 20 characters)"),
code=INVALID_PARAMS, params={'r':int(r)})
for r in invalid_receipts]
)
答案 0 :(得分:0)
我认为方法中的问题保存。方法保存返回对象的实例。如果不能保存则返回None。你的方法一直都没有返回。调用其他方法后,创建表单保存视图检查结果。如果没有看到poccess中止。你需要返回一些实例或者像这样调用super.save:
def save(self, commit=True):
inst = super(BillForm, self).save(commit=False)
#addition logic, all what you need.
return inst
或者您需要在视图类上覆盖有效方法,而不需要调用super()。valid()并覆盖表单中的save方法。
抱歉,我的英语非常糟糕。