Model.objects.all()返回foreignkey和choice字段的整数如何强制它返回名称?

2024-09-26 18:12:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试使用djqscv导出.csv文件。我知道the module supports foreign keys,但是我的模型有一半是选择和外键,我真的不想硬编码如链接所示。在

它只是按原样从数据库中获取表。有没有一种奇特的方法可以创建一个动态查询来检查字段类型并返回适当的、实际的数据,而不仅仅是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)

在py选择.py在

^{pr2}$

在联系人.objects.all()返回奖金中的url、email、person和行的ID。我希望它返回相应的名称,但我不想写

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

因为整个模型太大了,我不想硬编码。在


Tags: name模型selfurl编码modelmodelsemail
3条回答

我是如何解决这个问题的:

来自@NeoWang的最后一段代码确实可以工作(在对返回相同形式的字典列表稍作修改之后)模型.对象.值(是的),但是在我的特定情况下它没有任何用处,因为djqscv模块需要一个queryset。相反,我所做的是将代码的第一位用于ForeignKey字段,对于选项,在编写CSV之前,我只需将choice字段的整数值替换为choices元组中的相应名称。硬编码部分只针对三个字段,所以我将添加一个适当的注释,我想就这么做了。在

所以这看起来是这样的:

自定义管理器模型.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)

修改djqscv.py(遗憾的是,我们必须合并修改,因此我们必须在项目中使用我们的修改版本):

在djqscv.py在

^{pr2}$

replace_choice()方法是针对我的模型进行硬编码的,不过您应该明白这一点。在上面和@NeoWang answer中提供的代码块上构建动态解决方案相当容易。在

我假设您希望遍历字段,并选择要专门处理的外键:

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__返回的字符串:

^{pr2}$

如果希望获得更好的性能,在查询所有联系人对象时,最好对相关模型使用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字段这样的其他字段,您可以执行相同的操作:提取meta,并相应地进行转换。在

您可以为Contact创建一个自定义管理器,覆盖values()函数,并使其根据需要处理ForeignKey字段。在

相关问题 更多 >

    热门问题