python - 模型字段值未在 Django 中更新
问题描述
正在建立这个投票平台,用户将不得不投票。他们将输入他们想要购买的票数,然后付款。支付成功后,他们刚刚购买的票数应该添加到他们在数据库中的旧票数中。
例如,假设用户以 10 美元的价格购买了 2 张选票,并且已经拥有 3 张选票,则应将 2 添加到 3 以使其成为 5。
我的问题是 10 美元被添加到用户投票中。
models.py
class Nomination(models.Model):
Fullname = models.CharField(max_length=120)
Nominee_ID = models.CharField(max_length=100)
Category = models.ForeignKey(Category, on_delete=models.CASCADE)
image = models.ImageField(upload_to='nominations_images')
slug = models.SlugField(max_length=150)
votes = models.IntegerField(default=0)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.Fullname
views.py
def nomination_payView(request, slug):
if request.method == 'GET':
model = get_object_or_404(Nomination, slug=slug)
template_name = 'Payment.html'
context = {
'nomination': model
}
return render(request, 'Payment.html', context)
elif request.method == 'POST':
amount = (str(int(request.POST['votes']) * float(request.POST['price'])) + '0').replace('.', '')
zeros = '0' * (12 - len(amount))
amount = zeros + amount
email = request.POST['email']
url = 'https://test.theteller.net/checkout/initiate'
transaction_id = random.randint(100000000000, 999999999999)
data = {
"merchant_id": "TTM-00000740",
"transaction_id": transaction_id,
"desc": "Payment Using Checkout Page",
"amount": amount,
"redirect_url": f"http://127.0.0.1:8000/process-payment/{slug}/{amount}",
"email": email,
"API_Key": "ZDQ2OGEyZDNjN2YzMDY5ZDVkY2MyM2U5YTRiMGI0N2Q=",
"apiuser": "halotech5d525bfd6ead3",
}
encoded = base64.b64encode(
b'halotech5d525bfd6ead3:ZDQ2OGEyZDNjN2YzMDY5ZDVkY2MyM2U5YTRiMGI0N2Q=')
headers = {
'Content-Type': 'application/json',
'Authorization': f'Basic {encoded.decode("utf-8")}',
'Cache-Control': 'no-cache'
}
res = requests.post(url, data=json.dumps(data),
headers=headers).json()
print(res['checkout_url'])
return redirect(res["checkout_url"])
def process_payment(request, slug, amount):
trans_id = request.GET.get('transaction_id')
status = request.GET.get('status')
reason = request.GET.get('reason')
transaction_id = request.GET.get('transaction_id')
if status == 'Approved':
transaction = SuccessfulTransactionHistory(
nominee_name=slug,
transaction_id=transaction_id,
amount=amount
)
transaction.save()
nomination = Nomination.objects.filter(slug=slug).values('votes')
Nomination.objects.filter(slug=slug).update(votes=int(nomination[0]['votes']) + int(amount[:-2]))
return redirect('/success')
else:
context = {
'error': reason
}
transaction = FailedTransactionHistory(
nominee_name=slug,
transaction_id=transaction_id,
amount=amount
)
transaction.save()
return render(request, 'payment_error.html', context=context)
解决方案
无需执行单独的查询来获取值(第一次)然后递增(第二次)。只需使用F 表达式访问同一模型中的字段并在单个操作中执行增量:
from django.db.models import F
Nomination.objects.filter(slug=slug).update(votes=F('votes') + amount)
无需强制Nomination.votes
转换,int
因为它已经是。但是 ifamount
是一个str
(如果您在 URL 中接受它作为int
避免这样的转换会更好):
Nomination.objects.filter(slug=slug).update(votes=F('votes') + int(amount[:-2])) # The slice [:-2] was used as performed in the question. Adjust accordingly depending on what the amount really contains.
在这里,所有Nomination
具有目标的对象slug
都将按votes
上述数量递增。
更新
既然我们需要 的计数votes
,我们不应该只接受amount
这里的,因为它已经是 的乘积votes * price
。我们可以做的是改变对这个 API 的调用,并votes
通过nomination_payView()
专门改变这一行来包含:
"redirect_url": f"http://127.0.0.1:8000/process-payment/{slug}/{amount}",
类似于:
"redirect_url": f"http://127.0.0.1:8000/process-payment/{slug}/{amount}?votes={request.POST['votes']}",
或者:
"redirect_url": f"http://127.0.0.1:8000/process-payment/{slug}/{amount}/{request.POST['votes']}",
- 您将选择什么取决于端点可能处理的内容,
https://test.theteller.net/checkout/initiate
因为它将执行重定向。
然后在这个process_payment
API 中,我们可以直接从查询参数中直接访问该计数:
Nomination.objects.filter(slug=slug).update(votes=F('votes') + int(request.GET['votes']))
或者,如果您从路径参数中选择了第二个选项
Nomination.objects.filter(slug=slug).update(votes=F('votes') + votes) # Assuming you defined the URL as something like <path("process-payment/{str:slug}/{int:amount}/{int:votes}", ...> and the view function as <def process_payment(request, slug, amount, votes):>
推荐阅读
- css - 带 CSS 的 SVG 半圆
- ssl - 自签名证书出现 500 错误
- tensorflow - 如何使用 TensorFlow Serving 进行预处理和后处理
- typescript - 如何通过 spfx vue js 上的 rest api 获取托管元数据类型(共享点)值
- python - 基于排序的字典值字典字典?
- windows - 无法在 Windows 上找到 OpenSSL 依赖项构建休息床
- html - 如何使水平滚动条响应地适合 div 宽度?
- javascript - Safari 不支持 indexedDB.databases()
- c# - 如何“在分组框可见性折叠后覆盖空白空间”
- magento - Magento 2 - 静态块安装程序的多行内容