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 IDs?例如,它目前显示:

“您的订单号是 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_idid 期待 int,但您传递的是 str

以上是关于ORM Django 多对多的主要内容,如果未能解决你的问题,请参考以下文章

Django ORM - 通过模型查询多对多?

ORM Django 多对多

Python学习第135天(Django的ORM多对多查询)

Django中ORM多对多表的操作

Django学习-9-ORM多对多操作

Django 补充ORM多对多正向查询