python - 避免来自同一用户的重复输入
问题描述
我正在尝试建立一个拍卖网站。我已经设置了我的 placebid 视图,我对它的功能非常满意,但问题是同一个用户能够多次对同一个列表出价。这没关系,但我希望更新初始出价或删除初始出价并创建新出价,而不是将其作为多个单独的出价存储在数据库中。
我确实尝试了 UniqueConstraint 并添加到我的 Bid 模型(字段:bidder 和 bid_input),但它没有任何区别,而且当我从我的 Bid 模型中删除它并且 makemigrations 没有检测到任何更改时,似乎数据库无论如何都在解雇它。
在将表单保存在我的 placebid 视图中之前,我尝试进行 .filter().exists() 检查,现在该表单允许我进行初始出价,但是当我进行第二次出价时,它返回一个 Page Not Found 错误:
Page not found (404)
Request Method: POST
Request URL: http://127.0.0.1:8000/listing/3/bid
Raised by: auctions.views.placebid
No Bid matches the given query.
这是我的功能views.py,没有表单验证检查:
def placebid(request, id):
listing_bid = get_object_or_404(Listing, id=id)
highest_bid = Bid.objects.filter(bid_item_id=id).aggregate(Max('bid_input'))['bid_input__max'] or Decimal('0')
currentHighest = Bid.objects.filter(bid_item_id=id).aggregate(Max('bid_input'))['bid_input__max']
listing = Listing.objects.get(pk=id)
if request.method == "POST":
bidform = BidForm(request.POST)
if bidform.is_valid() and highest_bid == 0:
bid_placed = bidform.cleaned_data['bid_input']
if bid_placed <= listing.start_price:
messages.error(request, 'Make sure your bid is greater than the start price')
return HttpResponseRedirect(reverse("listing", args=(id,)))
else:
newbid = bidform.save(commit=False)
newbid.bidder = request.user
newbid.bid_input = bidform.cleaned_data['bid_input']
newbid.bid_item = listing_bid
newbid.time = timezone.now()
newbid.save()
messages.success(request, 'Bid placed succesfully')
return HttpResponseRedirect(reverse("listing", args=(id,)))
if bidform.is_valid() and highest_bid > 0:
bid_placed = bidform.cleaned_data['bid_input']
if bid_placed <= highest_bid:
messages.error(request, 'Make sure your bid is greater than the current highest bid')
return HttpResponseRedirect(reverse("listing", args=(id,)))
else:
newbid = bidform.save(commit=False)
newbid.bidder = request.user
newbid.bid_input = bidform.cleaned_data['bid_input']
newbid.bid_item = listing_bid
newbid.time = timezone.now()
newbid.save()
messages.success(request, 'Bid placed succesfully')
return HttpResponseRedirect(reverse("listing", args=(id,)))
else:
bidform = BidForm()
return HttpResponseRedirect(reverse("listing", args=(id,)))
这是我添加的 .filter().exists() 检查:
bid = get_object_or_404(Bid, id=id)
if bid.bid_input.filter(bidder=request.user.id).exists():
bid.bid_input.remove(request.user)
newbid = bidform.save(commit=False)
newbid.bidder = request.user
newbid.bid_input = bidform.cleaned_data['bid_input']
newbid.bid_item = listing_bid
newbid.time = timezone.now()
newbid.save()
messages.success(request, 'Bid placed succesfully')
return HttpResponseRedirect(reverse("listing", args=(id,)))
else:
newbid = bidform.save(commit=False)
newbid.bidder = request.user
newbid.bid_input = bidform.cleaned_data['bid_input']
newbid.bid_item = listing_bid
newbid.time = timezone.now()
newbid.save()
messages.success(request, 'Bid placed succesfully')
return HttpResponseRedirect(reverse("listing", args=(id,)))
投标模型
class Bid(models.Model):
bidder = models.ForeignKey(User, on_delete=models.CASCADE, related_name="bidders")
bid_item = models.ForeignKey(Listing, on_delete=models.CASCADE, related_name="bid_items", default=None)
bid_input = models.DecimalField(max_digits=9, decimal_places=2, default=None)
time = models.DateTimeField(default=timezone.now)
def __str__(self):
return f"{self.bidder}, bid amount: {self.bid_input}"
编辑添加 BidForm:
class BidForm(forms.ModelForm):
class Meta:
model = Bid
fields = ["bid_input"]
labels = {"bid_input": ""}
widgets = {
"bid_input": forms.NumberInput(attrs={'placeholder': 'Enter bid (£)'})
}
解决方案
首先我不喜欢你的观点是你的表单验证分布在表单和视图之间。首先,您检查该表单is_valid
,然后添加其他验证。我会将此验证移至ModelForm
您需要提供以形成所有需要的数据,例如form_bidder
,hidhest_bid
bid_item
class BidForm(forms.ModelForm):
class Meta:
model = Bid
fields = ["bid_input"]
labels = {"bid_input": ""}
widgets = {
"bid_input": forms.NumberInput(attrs={'placeholder': 'Enter bid (£)'})
}
def __init__(self, *args, **kwargs):
self.form_bidder = kwargs.pop("form_bidder")
self.highest_bid = kwargs.pop("hidhest_bid")
self.bid_item = kwargs.pop("bid_item")
super().__init__(*args, **kwargs)
def clean_bid(self):
bid_input = self.cleaned_data.get("bid_input")
if bid_input and self.highest_bid == 0 and bid_input < self.bid_item.start_price:
self.add_errror("bid_input", "Make sure your bid is greater than the start price")
if bid_input and self.highest_bid > 0 and bid_input < self.highest_bid:
self.add_errror("bid_input", "Make sure your bid is greater than the current highest bid")
return bid_input
def save(self, *args, **kwargs):
self.instance.bidder = self.form_bidder
self.instance.bid_item = self.bid_item
self.instance.time = timezone.now()
return super().save(*args, **kwargs)
- 鉴于
placebid
您拥有listing
并且listing_bid
它们应该相同,为什么您需要它们?如果您想在找不到对象时抛出异常,则保留,listing
否则保留listing_bid
- 要更新用户之前输入的数据而不是创建新数据,您需要提供包含用户之前输入的数据的
instance
属性。modelform
def placebid(request, id):
highest_bid = Bid.objects.filter(bid_item_id=id).aggregate(Max('bid_input'))['bid_input__max'] or Decimal('0')
currentHighest = Bid.objects.filter(bid_item_id=id).aggregate(Max('bid_input'))['bid_input__max']
# listing_bid = get_object_or_404(Listing, id=id)
listing = Listing.objects.get(pk=id)
form_instance = Bid.objects.filter(bidder=request.user, bid_item=listing).first()
if request.method == "POST":
bidform = BidForm(
request.POST,
instance=form_instance,
form_bidder=request.user,
hidhest_bid=highest_bid,
bid_item = listing,
)
if bidform.is_valid():
newbid = bidform.save()
messages.success(request, 'Bid placed succesfully')
return HttpResponseRedirect(reverse("listing", args=(id,)))
else:
for error in bidform.errors:
messages.error(request, str(error))
return HttpResponseRedirect(reverse("listing", args=(id,)))
else:
bidform = BidForm(
instance=form_instance,
form_bidder=request.user,
hidhest_bid=highest_bid,
bid_item = listing,
)
return HttpResponseRedirect(reverse("listing", args=(id,)))
推荐阅读
- security - 零知识证明性能的安全性
- reactjs - 在 Map 函数中设置状态后,如何仅将状态作为道具传递一次
- javascript - 通过中间服务器从浏览器获取文件时,multer 无法正常工作
- sql-server - 如何在 SQL Server 中执行 PIVOT 对多列进行聚合
- r - 方法=“QDA”和值=“finalModel”的train()错误
- javascript - 如何从 js 中获取数据?
- java - 如何将 xml 文件和 java 链接到我的节点 js?
- angular - CRUD 演示项目
- c# - 我可以安装一个 HttpModule (IIS) 来激活特定的动词吗?
- python - 与 pandas 中的多个数据表进行比较(python)