ORM Django 多对多
Posted
技术标签:
【中文标题】ORM Django 多对多【英文标题】:ORM Django Many to Many 【发布时间】:2019-09-08 15:02:37 【问题描述】:我正在尝试检索用户购买的票的一个订单 ID。当我输入Order.objects.all()
时,它会显示数据库中的所有订单ID,但我试图只检索一个order ID
。当我改为查询时:Order.objects.filter(buyer=Ticket.objects.get(id='tic_id'))
----它给了我一个错误:
以 10 为基数的 int() 的无效文字:'tic_id'。
有人可以验证我的模型是否正确以及如何查询以获取仅一个order ID
而不是所有order ID
s?例如,它目前显示:
“您的订单号是 123456789101112131415”,我的目标是显示“订单号是 11”;谢谢,感谢您的耐心等待!
models.py
class User(models.Model):
first_name=models.CharField(max_length=100)
last_name=models.CharField(max_length=100)
email=models.CharField(max_length=100)
password=models.CharField(max_length=100)
created_at=models.DateTimeField(auto_now_add=True)
updated_at=models.DateTimeField(auto_now=True)
class Ticket(models.Model):
venue=models.CharField(max_length=100)
quantity=models.PositiveIntegerField()
price=models.DecimalField(default=25.00, max_digits=5, decimal_places=2, null=True, blank=True)
loop=models.CharField(max_length=100)
purchaser = models.ForeignKey(User, related_name="purchases", on_delete=models.PROTECT)
created_at=models.DateTimeField(auto_now_add=True)
updated_at=models.DateTimeField(auto_now=True)
class Order(models.Model):
full_name=models.CharField(max_length=100)
cc_number=models.PositiveIntegerField()
exp_date=models.PositiveIntegerField()
cvc=models.PositiveIntegerField()
buyers=models.ManyToManyField(Ticket, related_name="bought_tickets")
created_at=models.DateTimeField(auto_now_add=True)
updated_at=models.DateTimeField(auto_now=True)
views.py
def process(request):
Order.objects.create(full_name=request.POST['full_name'], cc_number=request.POST['cc_number'],exp_date=request.POST['exp_date'], cvc=request.POST['cvc'])
return redirect('/checkout')
def checkout(request):
context=
"user":User.objects.get(id=request.session['user_id']),
"tickets": Ticket.objects.filter(purchaser=User.objects.get(id=request.session['user_id'])).annotate(total=Sum(F('quantity') * F('price'), output_field=FloatField())).annotate(tax=ExpressionWrapper(F('quantity') * F('price')*0.0725, output_field=FloatField())).annotate(total_price=ExpressionWrapper(F('quantity') * F('price') + F('tax'), output_field=FloatField())),
"order":Order.objects.filter(buyer=Ticket.objects.get(id='tic_id'))
return render(request, 'first_app/checkout.html', context)
checkout.html
<p class="lead">Your order number is:<strong>% for o in order %o.id% endfor %</strong><p class="lead">with ticket number:</p><strong>% for ticket in tickets %ticket.id% endfor %</strong>
【问题讨论】:
您想如何确定要显示的订单? @DanielRoseman 已购买门票的订单号 ID 或门票号 ID。它显示了票证 ID 和订单 ID——但是当我执行 Order.objects.all() 时它给了我一个订单 ID 列表,我只是想为每张购买的票/票显示一个订单号(票证ID) 但是Order和Ticket的关系是多对多的。所以每张订单都有很多张票,每张票有很多张订单。给定一个订单,你怎么知道你想展示它的哪张票? 我认为您正在帮助我澄清这种关系:我猜用户可以请求 1-8 张门票(一对多),它会提供一个门票 ID。但是由于用户必须支付 Ticket ID——它带有一个订单 ID。您可能是正确的,这种关系可能没有意义;我应该将订单 ID 保留为与票证 ID 的一对一关系吗?你有什么建议?抱歉,我对此很陌生,但我感谢您的澄清。 除非您尝试设置骗局,否则每张票只能订购一次?因此,指向它所属订单的票证上的外键更有意义。如果您正在试图通过多次销售同一张票来设置骗局,因此需要 M2M,那么您最好根本没有数据库?证据和一切? 【参考方案1】:我觉得您的架构中的关系略有偏差。 就是现在:
应该是什么:
然后,您将获得带有 Order.objects.get(buyer=user_id).values_list('pk', flat = True)[0]
的订单 ID(错误:请参阅更新!),并且通过购买它的订单获得门票的所有者。
如果感觉不太对劲,最好拿起笔和纸开始画一些图表。
更新: 模型大致如下所示:
class Order:
# one order can only have one buyer, but Users may have many orders
buyer = ForeignKey(User, related_name = 'orders')
class Ticket:
# one ticket can only have one order, but many tickets may be ordered at once
order = ForeignKey(Order, related_name = 'tickets')
def get_owner(self):
# Returns the user that has ordered this ticket.
return self.order.buyer
另外,我刚刚意识到您仍然不会从Order.objects.get(buyer=user_id)
获得一个订单,因为用户可能有多个订单。
一种方法是重定向到包含已创建订单的 url 或将该订单存储在会话中。
或者只是:
def process(request):
order = # ... create order
context = 'order': order, # ... other stuff
return render(request, 'first_app/checkout.html', context)
【讨论】:
我认为你的模型更有意义。用户附加到票证 ID(1-多票证)(一对多关系) 那么我可以使用 Ticket 作为外键而不是 M2M 来进行 Order 关系吗?例如:```class Order(models.Model): full_name=models.CharField(max_length=100) cc_number=models.PositiveIntegerField() exp_date=models.PositiveIntegerField() cvc=models.PositiveIntegerField() Buyer=models.ForeignKey (Ticket, related_name="bought_tickets") created_at=models.DateTimeField(auto_now_add=True) updated_at=models.DateTimeField(auto_now=True) 不,反过来。我已经更新了我的答案。【参考方案2】:您正在将 str 传递给参数 id
Ticket.objects.get(id='tic_id')
。我假设tic_id
是一个变量,所以你需要使用它而不使用引号Ticket.objects.get(id=tic_id)
【讨论】:
它是一个变量。我可能在我的视图中的其他地方定义了它。我试图弄清楚如何显示一个订单 ID 而不是订单 ID 列表。我需要在 HTML 或视图中编辑 Jinja 吗? 删除引号,而不是id='tic_id'
使用 id=tic_id
。 id
期待 int
,但您传递的是 str
。以上是关于ORM Django 多对多的主要内容,如果未能解决你的问题,请参考以下文章