我正在django写一个会计应用程序,有Order
个,其中包含创建发票的日期和创建信用票据的可选日期。
class Order(models.Model):
date_invoice_created = models.DateTimeField(null=True, blank=True)
date_credit_note_created = models.DateTimeField(null=True, blank=True)
我目前正在为我们的会计师开发视图,并且她希望在管理面板中的不同行上同时包含发票和信用记录,并按其各自的创建日期排序。
所以基本上我想在不同的行中显示相同的模型两次,按不同的字段排序。在SQL中,这将是:
SELECT id, create_date FROM (
SELECT id, date_invoice_created AS create_date, 'invoice' AS type FROM order
UNION
SELECT id, date_credit_note_created AS create_date, 'creditnote' AS type FROM order
) ORDER BY create_date
不要介意我的SQL-fu不是最新的,但我想你明白我的意思。
所以我试图通过覆盖第二个查询集中的日期来让django为我这样做,因为django不支持两个extra
' d查询集的并集: / p>
invoices = Order.objects.filter(date_invoice_created__isnull=False)
credit_notes = Order.filter_valid_orders(qs
).filter(
date_credit_note_created__isnull=False
).extra(
select={'date_invoice_created': 'date_credit_note_created'}
)
return (invoices | credit_notes).order_by('date_invoice_created')
不幸的是,联合的逐位或操作总是确保ID是不同的,但我真的希望它们不是。如何实现具有重复行的联合?
答案 0 :(得分:0)
我现在使用SQL-View找到了解决问题的方法。
我创建了一个新的迁移(使用south),其中包含上述问题中提到的SQL查询作为视图,它返回所有行两次,每个行分别带有create_date
和type
信用票据和发票。
accounting/migrations/00xx_create_invoice_creditnote_view.py
:
class Migration(SchemaMigration):
def forwards(self, orm):
query = """
CREATE VIEW invoiceoverview_invoicecreditnoteunion AS
SELECT * FROM (
SELECT *,
date_invoice_created AS create_date,
'invoice' AS type
FROM accounting_order
WHERE date_invoice_created NOT NULL
UNION
SELECT *,
date_credit_note_created AS date,
'creditnote' AS type
FROM accounting_order
WHERE date_credit_note_created NOT NULL
);
"""
db.execute(query)
def backwards(self, orm):
query = """
DROP VIEW invoiceoverview_invoicecreditnoteunion;
"""
db.execute(query)
# ...
# the rest of the migration model
# ...
然后我为这个视图创建了一个新模型,它具有Meta
managed = False
,以便django使用模型而不关心它的创建。它与原始Order
模型具有相同的字段,但也包含SQL-View中的两个新字段:
invoiceoverview/models.py
:
class InvoiceCreditNoteUnion(models.Model):
""" This class is a SQL-view to Order, so that the credit note and
invoice can be displayed independently.
"""
class Meta:
managed = False # do not manage the model in the DB
# fields of the view
date = models.DateTimeField()
type = models.CharField(max_length=255)
# ...
# all the other fields of the original Order
# ...
现在,我可以将此模型用于contrib.admin.ModelAdmin
,并通过查看type
字段来显示appripriate内容。 e.g:
class InvoiceAdmin(admin.ModelAdmin):
list_display = ['some_special_case']
def some_special_case(self, obj):
if obj.type == 'creditnote':
return obj.credit_note_specific field
else:
return obj.invoice_specific_field
admin.site.register(InvoiceCreditNoteUnion, InvoiceAdmin)
这最终允许我使用管理员面板提供的所有其他功能,例如覆盖queryset
方法,排序等。