簡體   English   中英

Model.objects.all()返回ForeignKeys和Choice字段的整數-如何強制其返回名稱?

[英]Model.objects.all() returns integers for ForeignKeys and choice fields - how to force it to return names instead?

我正在嘗試使用djqscsv導出.csv文件。 我知道模塊支持外鍵 ,但是我模型的一半是選擇外鍵 ,我真的不想像鏈接中所示那樣對其進行硬編碼。

它只是按原樣從數據庫中獲取表。 有沒有一種創建動態查詢的理想方法,該查詢可以檢查字段類型並返回適當的實際數據,而不僅僅是ID?

編輯,因為顯然這太難以可視化了:

class Bonus(models.Model):
    name = models.CharField(max_length=30, unique=True)

    def __unicode__(self):
        return self.name

class Contact(models.Model):
    url = models.URLField()
    email = models.EmailField()
    person = models.CharField(max_length=128)
    bonus_field = models.ForeignKey(Bonus)
    status = models.IntegerField(choices=STATUS_CHOICES, default=1)

choices.py

STATUS_CHOICES = (
    (1, ("Sent")),
    (2, ("Requested")),
    (3, ("In progress")),
)    

Contact.objects.all()返回Bonus中的 url,電子郵件,個人和row ID 我希望它返回相應的名稱,但是我不想寫

Contact.objects.values('url', 'email', 'person', 'bonus_field__name')

因為完整的模型太大了,我不想硬編碼。

我假設您要遍歷各個字段,並選擇ForeignKeys來專門處理:

from django.db import models

# Get field_name, is_foreign_key pairs from model meta
fields_foreign = [(
   field.name, 
   isinstance(field, models.ForeignKey)
) for field in Contact._meta.fields]

# Assume every related model has a 'name' field,
# if you want to get 'name' fields of these models, 
# construct the list of field names to pass to values():
# something like ['url', 'email', 'person', 'bonus_field__name']
value_fields = [
    f[0] if not f[1] else "{}__name".format(f[0])
    for f in fields_foreign
]

# Now get the values
Contact.objects.values(*value_fields)

如果是“實際數據”,則表示__str__返回的字符串:

contacts = Contact.objects.all()
for contact in contacts:
    values = []
    for f in fields_foreign:
        value = getattr(contact, f[0])
        if f[1]: # Foreignkey, call str() on the model object
           value = str(value) # this calls __str__ in model
        values.append(value)
    print values

如果要獲得更好的性能,則在查詢所有Contact對象時,最好對相關模型使用select_related()。

關於選擇,Django為每個帶有選擇項的字段提供了一個便捷的方法get_field_display()。 要在值列表中使用此選項,首先必須知道哪些字段已設置選項:

# Now we have tuples (field_name, is_field_foreign, field_has_choices)
fields_foreign_choices = [(
   field.name, 
   isinstance(field, models.ForeignKey),
   bool(field.choices)
) for field in Contact._meta.fields]

# We can use the magic get_field_display() method
contacts = Contact.objects.all()
for contact in contacts:
    values = []
    for f in fields_foreign_choices:
        value = getattr(contact, f[0])
        if f[1]: # Foreignkey, call str() on the model object
           value = str(value) # this calls __str__ in model
        elif f[2]: # The field has choices
           display_method = getattr(contact, "get_{}_display".format(f[0])
           value = display_method()
        values.append(value)
    print values

對於其他字段(例如Datetime字段),您可以執行以下操作:提取元數據,然后進行相應的轉換。

這是我解決問題的方法:

@NeoWang的最后一段代碼的確起作用(在稍作修改后以相同的Model.objects.values()形式返回字典列表),但是在我的特定情況下它沒有用,因為djqscsv模塊需要查詢集。 相反,我要做的是將代碼的第一位用於ForeignKey字段,並且在編寫CSV之前就進行選擇,我只是將選擇字段整數值替換為選擇元組的對應名稱。 硬編碼部分僅用於三個字段,因此我猜想加上一個適當的注釋並繼續進行。

所以這是這樣的:

models.py中的自定義管理器

class ContactManager(models.Manager):

    def get_values(self):

        fields_foreign = [(
           field.name, 
           isinstance(field, models.ForeignKey)
        ) for field in Contact._meta.fields]

        value_fields = [
            f[0] if not f[1] else "{}__name".format(f[0])
            for f in fields_foreign
        ]

        return Contact.objects.values(*value_fields)

djqscsv.py中的修改(很遺憾,我們必須合並修改,因此我們將不得不在項目中使用修改后的版本):

在djqscsv.py中

## import your choices.py!
## add this method (hardcoded, so modify accordingly) 
def replace_choice(record):

    for key in record:
        if key == 'status':
## very readable line incoming (might remove unicode call if you don't need it)
            record[key] = unicode([v[1] for i, v in enumerate(STATUS_CHOICES) if v[0] == record[key]][0], 'utf-8')           
    return record

## modify this forloop
for record in values_qs:
    fixed_record = replace_choice(record)
    record = _sanitize_unicode_record(field_serializer_map, fixed_record)
    writer.writerow(record)

replace_choice()方法已針對我的模型進行了硬編碼,但是您明白了。 在上面和@NeoWang答案中提供的代碼段上構建動態解決方案非常容易。

您可以為Contact創建一個自定義管理器,覆蓋values()函數,並使其根據需要處理ForeignKey字段。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM