Django ORM,如何使用values()并仍然可以使用choicefield?

时间:2017-08-05 07:10:58

标签: python django django-queryset django-orm choicefield

我正在使用django v1.10.2

我正在尝试创建动态报告,我将字段和条件以及主要的ORM模型信息存储到数据库中。

我生成动态报告的代码是

main_model_name

所以main_model可以是任何东西 这项工作很有效,但有时choicefield的关联模型有main_model

因此,其中一个报告PalletPallet PalletMovement有很多serial_number 我的显示列为:created_atpallet_movement__locationPallet

前两列是属于PalletMovement模型的字段。 最后一个来自PalletMovement

class PalletMovement(models.Model): pallet = models.ForeignKey(Pallet, related_name='pallet_movements', verbose_name=_('Pallet')) WAREHOUSE_CHOICES = ( ('AB', 'AB-Delaware'), ('CD', 'CD-Delaware'), ) location = models.CharField(choices=WAREHOUSE_CHOICES, max_length=2, default='AB', verbose_name=_('Warehouse Location')) 模型看起来像这样:

choicefield

由于查询集会返回原始值,如何使用PalletMovement模型中的pallet_movement__location来确保AB-Delaware显示CD-Delaware }或main_model

请记住,// assumes this.viewer contains your viewer, your code might be different ... // make sure viewer has been created if (this.viewer) { // I added this to handle some specific cases if(this.viewer.impl.selector) { this.viewer.tearDown() this.viewer.finish() this.viewer = null } } 可以是任何内容,具体取决于我在数据库中存储的内容。

据推测,我可以在数据库中存储更多信息,以帮助我更好地过滤和呈现数据。

4 个答案:

答案 0 :(得分:4)

values()方法返回表示字段名称和相应值的键值对字典。

例如:

型号:

class MyModel(models.Model):
    name = models.CharField()
    surname = models.CharField()
    age = models.IntegerField()
    ...

查询:

result = MyModel.objects.filter(surname='moutafis').values('name', 'surname')

结果:

< Queryset [{'name': 'moutafis', 'surname': 'john'}] >

您现在可以像处理普通词典一样操纵此结果:

if main_model_name is 'PalletMovement':
    # Make life easier
    choices = dict(PalletMovement.WAREHOUSE_CHOICES)

    for item in result:
        item.update({ 
            pallet_movement__location: verbal_choice.get(
                pallet_movement__location, pallet_movement__location)
        })

您甚至可以将其转换为更好的可重用性功能:

def verbalize_choices(choices_dict, queryset, search_key):
    result = queryset        

    for item in result:
        item.update({ search_key: choices_dict.get(search_key, search_key) })

    return result

verbal_result = verbalize_choices(
                    dict(PalletMovement.WAREHOUSE_CHOICES),
                    result,
                    'pallet_movement__location'
                )

我建议使用update()get()方法,因为它们可以避免潜在的错误,例如:

  • search_key中不存在choice_dict,然后get()会返回search_key
  • 的值
  • update()会尝试更新给定的键值对(如果存在),否则会将其添加到字典中。

如果上述内容的使用位于数据的模板表示中,则可以改为创建custom template filter

@register.filter(name='verbalize_choice')
def choice_to_verbal(choice):
    return dict(PalletMovement.WAREHOUSE_CHOICES)[choice]

请在此处进行额外查看:Django: How to access the display value of a ChoiceField in template given the actual value and the choices?

答案 1 :(得分:1)

您可以使用{{ obj.get_location_display }}

在你的模板中:

{{ obj.pallet_movement.get_location_display }}

values()

[编辑:]正如评论中所指出的,这在调用{{1}}

时无效

答案 2 :(得分:1)

创建模板标签的替代方法是:

{{form.choicefield.1}}

这显示了外键字段的初始数据的值,而不是id。

答案 3 :(得分:1)

任何main_model_name的通用解决方案都是由Django Model _meta API内省: class_object._meta.get_field(field_name).choices
那就是:

choice_dicts = {}
for field_name in display_columns:
    choice_dicts[field_name] = {
        k: v for k, v in class_object._meta.get_field(field_name).choices
    }
out = []
for row in results:
    out.append({name: choice_dicts[name].get(value, value)
                for name, value in row.items()
                })

其余的是一个琐碎的例子,大​​多是从问题

复制的代码
>>> pallet = app.models.Pallet.objects.create()
>>> palletm = app.models.PalletMovement.objects.create(pallet=pallet, location='AB')
>>>
>>> main_model_name = 'PalletMovement'
>>> conditions_dict = {}
>>> display_columns = ['pallet_id', 'location']
>>> sort_columns = []
>>>
>>> class_object = class_for_name("app.models", main_model_name)
>>> results = (class_object.objects.filter(**conditions_dict)
...                                .values(*display_columns)
...                                .order_by(*sort_columns)
...            )[:50]
>>>
>>> # *** INSERT HERE ALL CODE THAT WAS ABOVE ***
>>>
>>> print(out)
[{'location': 'AB-Delaware', 'pallet_id': 1}]

它与&#39; pallet_id&#39;同等作用。或者使用托盘&#39;在display_columns。即使那样&#34; _meta&#34;从下划线开始,它是一个记录的API。