【问题标题】:Joining multiple models in order to get an orm query in Django?加入多个模型以便在 Django 中获取 orm 查询?
【发布时间】:2021-06-10 23:34:34
【问题描述】:

我必须返回特定时间内最畅销曲目的平均长度,使用 3 个模型我设法形成一个看起来像这样的 sql 查询

select  AVG(t.Milliseconds) as lengthTrack
from invoice_items as il
    join invoices as i on i.invoiceid = il.invoiceid
    join tracks as t on t.TrackId = il.TrackId 
where i.InvoiceDate between '2012-01-01' and '2013-12-31'
order by il.Quantity DESC LIMIT 10

我设法想出了这个,因为我真的很困惑如何加入这两个表以获得 10 个最畅销的表的平均长度跟踪:

start_date = datetime.date(2012, 01, 01)
end_date=datetime.date(2013, 12, 31)

InvoiceItem .objects.filter(ino_date__range=(start_date, end_date),)

模型.py

class Invoice(models.Model):
    id                = models.AutoField(primary_key=True, db_column='InvoiceId')
    customerid        = models.ForeignKey(Customer, db_column='CustomerId', on_delete=models.CASCADE)
    invoicedate       = models.DateTimeField(db_column='InvoiceDate')
    billingaddress    = models.TextField(max_length=70, db_column='BillingAddress', blank=True, null=True)
    billingcity       = models.TextField(max_length=40, db_column='BillingCity', blank=True, null=True)
    billingstate      = models.TextField(max_length=40, db_column='BillingState', blank=True, null=True)
    billingcountry    = models.TextField(max_length=40, db_column='BillingCountry', blank=True, null=True)
    billingpostalcode = models.TextField(max_length=10, db_column='BillingPostalCode', blank=True, null=True)
    total             = models.TextField(db_column='Total')

class Track(models.Model):
    id           = models.AutoField(primary_key=True, db_column='TrackId')
    playlist     = models.ManyToManyField(Playlist, through='PlaylistTrack')
    name         = models.TextField(db_column='Name', max_length=200)
    albumid      = models.ForeignKey(Album, db_column='AlbumId', blank=True, null=True, on_delete=models.CASCADE)
    mediatypeid  = models.ForeignKey(MediaType, db_column='MediaTypeId', on_delete=models.CASCADE)
    genreid      = models.ForeignKey(Genre, db_column='GenreId', blank=True, null=True, on_delete=models.CASCADE)
    composer     = models.TextField(db_column='Composer', blank=True, null=True, max_length=220)
    milliseconds = models.IntegerField(db_column='Milliseconds')
    bytes        = models.IntegerField(db_column='Bytes', blank=True, null=True)
    unitprice    = models.DecimalField(db_column='UnitPrice', max_digits=5, decimal_places=2)

class InvoiceItem(models.Model):
    id        = models.AutoField(primary_key=True, db_column='InvoiceLineId')
    invoiceid = models.ForeignKey(Invoice, db_column='InvoiceId', on_delete=models.CASCADE)
    trackid   = models.ForeignKey(Track, db_column='TrackId', on_delete=models.CASCADE)
    unitprice = models.DecimalField(db_column='UnitPrice', max_digits=5, decimal_places=2)
    quantity  = models.IntegerField(db_column='Quantity')

serialerzs.py

class InvoiceSerialer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Invoice
        fields = ('id', 'total')


class InvoiceItemSerialer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = InvoiceItem
        fields = '__all__'


class TrackSerialer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Track
        fields = '__all__'

在视图中我是否需要在 erializer_class 中添加 3 个序列化程序?我也想问一下我的查询是否正确?

【问题讨论】:

  • 需要更多代码来回答这个问题。在您的 SQL 查询中,您引用不在查询中的表 m。在没有底层模型的情况下,很难帮助您构建 Django 查询。此外,您的问题不涉及视图或序列化程序,所以这是一个红鲱鱼。查询应该仅可使用模型和管理器写入。因此,您可以在 Django shell 中对其进行测试,而无需视图或序列化程序。发布您的模型代码,我们可以帮助您生成查询。
  • 我已经编辑了我的问题并添加了模型和 serialerzs 文件

标签: python django django-queryset django-orm


【解决方案1】:

在两个日期之间获得最多的销量将是一个注释轨道在这些日期之间售出多少次的问题。

from django.db.models import Count, Q
top_ten_selling_tracks = Track.objects.annotate(
   sales_count=Count( 
      'invoice_item', # count the number of invoices that point to this track
      filter=Q(invoiceid__invoicedate__range=(start_date, end_date)) # only count them if the associated invoice falls in the appropriate range
   )).order_by(
      '-sales_count' # order them by sales descending, to get the top 10
   )[:10] # take the top ten tracks

平均值可以在 python 中完成(Django 可以轻松地聚​​合查询集,但由于您的限制约束,它可能更容易只是

return avg(t.milliseconds for t in top_ten_selling_tracks)

【讨论】:

  • 我是否需要在 serializer_class 中添加 3 个模型才能使此查询起作用?如果是这样,如何同时添加 3 个模型,因为当我查看文档时它说不可能?
  • 您的问题是如何获取查询。无论序列化程序如何,此查询都将起作用。也许您正试图在 REST API 的 DRF 序列化程序中返回它?但目前尚不清楚哪个序列化程序将包含此信息 - 您的序列化程序都不会返回多个对象的聚合 - 它不是轨道、发票或发票项目的属性,具有“前 10 个销售轨道的平均长度”。您可能只想编写一个简单的 API View 函数来返回此值,但如果不了解您的用例,这很难说。
  • 我需要从这些表中返回 2012 年至 2013 年间最畅销的 10 首曲目的平均长度,但是当我尝试你的函数时,我在返回时遇到了问题,它说它弄乱了“)”我不知道注释函数应该在哪里关闭?
  • 我修复了括号 - 我错过了过滤器末尾的那个。对不起!至于“我需要返回平均长度......” - 我明白了,但是在哪里和给谁?如果您将它放在序列化程序上,您将把它作为序列化对象的属性返回。什么对象?如果只是返回该值所需的 API 端点,请编写一个简短的 API 视图 django-rest-framework.org/api-guide/views/#api_view
  • 它是一个休息 api,我需要稍后在前面使用
猜你喜欢
  • 1970-01-01
  • 2015-10-26
  • 2019-04-22
  • 2017-11-25
  • 1970-01-01
  • 1970-01-01
  • 2014-05-27
  • 2018-02-09
  • 2018-12-22
相关资源
最近更新 更多