后台
我正在创建一个电子商务应用程序,它允许用户对任何活跃的物品列表提交出价-其中Bid
和Listing
是**models.py
(* below *)中不同的Django模型。
对于每个新的投标,通过模型表单设置投标金额**(Bid.amount
)。如果出价金额大于当前出价(Listing.current_bid
),则:
Bid
被认为是有效的,对象被保存。Listing.current_bid
被更新为等于新的Bid.amount
。
问题
目前,我的解决方案(* 见***views.py
***below *)达到了预期的结果-它成功地验证和更新了每个新的出价,使用条件连接调用is_valid()
:
if new_bid_form.is_valid() and new_bid_form.cleaned_data["current_bid"] > previous_bid:
然而,即使这种设计可以工作,它也让人感觉像是“* hackish *”,因为验证逻辑并没有发生在模型中。因此,在调用clean()
时不会隐式检查条件,我可以预见这会导致问题的发生。相反,我希望在模型中实现验证逻辑,以便用Django的内置验证调用它,并将引发ValidationError
。
问题
1.我说我目前的“验证”解决方案设计得很差,对吗?
1.如果是这样,我如何在Bid
模型中验证输入到表单中的Bid.amount
的值是否大于Listing.current_bid
?(* 请参见下面的解决方案尝试 *)
www.example.com models.py
Listing Model
**
class Listing(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="usernames")
title = models.CharField(max_length=80)
description = models.CharField(max_length=800)
starting_bid = models.DecimalField(max_digits=11, decimal_places=2,validators=[MinValueValidator(Decimal('0.00'))])
current_bid = models.DecimalField(default=0, max_digits=11, decimal_places=2,validators=[MinValueValidator(Decimal('0.00'))])
image = models.URLField(blank=True)
Bid Model
**
class Bid(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="owners")
listing = models.ForeignKey(Listing, on_delete=models.CASCADE, related_name="listings")
amount = models.DecimalField(max_digits=11, decimal_places=2,validators=[MinValueValidator(Decimal('0.00'))])
views. py
listing() Function
**:为每个列表定义一个视图并实现一个ModelForm
来提交出价。
def listing(request, listing_id):
class NewBidForm(ModelForm):
template_name = "auctions/form_template.html"
class Meta:
model = Bid
fields = ["amount"]
widgets = {
"amount":forms.NumberInput(attrs={"placeholder": "Submit an offer greater than the current listing price"})
}
labels = {
"amount":_("Submit an Offer:")
}
# Get the current bid for the current listing
listing = Listing.objects.get(pk=listing_id)
current_bid = listing.current_bid
# If the submitted form data is valid, update & save new bid
if request.method == "POST":
new_bid_form = NewBidForm(request.POST)
if new_bid_form.is_valid() and new_bid_form.cleaned_data["amount"] > current_bid:
new_bid_form.instance.amount = new_bid_form.cleaned_data["amount"]
new_bid_form.instance.owner = request.user
new_bid_form.instance.listing = listing
new_bid_form.save()
# Set the listing's current bid to the new bid amount
listing.current_bid = new_bid_form.instance.amount
listing.save()
return HttpResponseRedirect(reverse("listing", args=[listing_id]))
else:
return render(request, "auctions/listing.html", {
"listing": listing,
"form": new_bid_form,
"message": messages.add_message(request, messages.ERROR, "Bid must be greater than the current highest bid."),
})
解决尝试
到目前为止,我还没有找到一个类似的例子,它提供了任何可以迭代的解决方案的提示。从Django文档中,似乎覆盖clean()
方法可能 * 是实现这一目标的一种方法,但我还没有找到一种方法,当一个(* 未保存 *)模型示例依赖于另一个不同模型的示例时。
我尝试了一个解决方案,在我的Bid
模型中使用了下面的clean()
方法:
def clean(self):
super().clean()
if self.amount < self.listing.current_bid:
raise ValidationError("Bid must be greater than the previous current bid")
但是,这返回了一个错误,我认为这是因为新的Bid
尚未保存,因此没有对.listing
的引用:
RelatedObjectDoesNotExist at /listing/1. Bid has no listing.
任何洞察力都将不胜感激!
1条答案
按热度按时间pobjuy321#
对于其他可能有类似问题的人,我能够找到一个解决方案(这是盯着我的脸),通过覆盖
clean()
方法,因为我已经猜到了。引发此错误的原因是,在调用重写的
clean()
方法时,Bid
对象尚未引用Listing
。因此,通过引用清单对象示例化
Bid
,我能够解决这个问题:作为参考,对
Bid
模型中的clean()
方法进行了轻微的修改: