Django import-export choices field
Asked Answered
B

3

5

I have a model with choices list (models.py):

class Product(models.Model):
    ...
    UNITS_L = 1
    UNITS_SL = 2
    UNITS_XL = 3
    PRODUCT_SIZE_CHOICES = (
    (UNITS_L, _('L')),
    (UNITS_SL, _('SL')),
    (UNITS_XL), _('XL'),
    )
    product_size = models.IntegerField(choices=PRODUCT_SIZE_CHOICES)
    ...

Also I added a new class for exporting needed fields(admin.py):

from import_export import resources, fields
...
Class ProductReport(resources.ModelResource):
    product_size = fields.Field()

    class Meta:
        model = Product

    #I want to do a proper function to render a PRODUCT_SIZE_CHOICES(product_size)

    def dehydrate_size_units(self, product):
        return '%s' % (product.PRODUCT_SIZE_CHOICES[product_size]) 

    fields = ('product_name', 'product_size')

Class ProductAdmin(ExportMixin, admin.ModelAdmin):
    resource_class = ProductReport

But this is not working. How can I get a named value of PRODUCT_SIZE_CHOICES in export by Django import-export ?

Blearyeyed answered 24/9, 2016 at 9:49 Comment(1)
There was a similar question: link, but without answers too.Blearyeyed
C
21

You can use 'get_FOO_display' to achieve this in the Django Admin:

class ProductReportResource(resources.ModelResource):
    product_size = fields.Field(
        attribute='get_product_size_display',
        column_name=_(u'Product Size')
    )
Constantino answered 24/3, 2018 at 18:44 Comment(1)
Exact answer for exporting model choice fieldsWhom
I
2

In my case I was trying to get the display from a foreign key choice field, like: user__gender

After unsuccessfully trying the accepted answer and the other answer by Waket, I found this thread here: https://github.com/django-import-export/django-import-export/issues/525

From where I tried a couple of options, and the one that finally worked for me is this:

  1. Create the widget somewhere
from import_export.widgets import Widget

class ChoicesWidget(Widget):
    """
    Widget that uses choice display values in place of database values
    """
    def __init__(self, choices, *args, **kwargs):
        """
        Creates a self.choices dict with a key, display value, and value,
        db value, e.g. {'Chocolate': 'CHOC'}
        """
        self.choices = dict(choices)
        self.revert_choices = dict((v, k) for k, v in self.choices.items())

    def clean(self, value, row=None, *args, **kwargs):
        """Returns the db value given the display value"""
        return self.revert_choices.get(value, value) if value else None

    def render(self, value, obj=None):
        """Returns the display value given the db value"""
        return self.choices.get(value, '')
  1. In your model resource declare the field using the widget and passing the choices to it, like this:
    user__gender = Field(
        widget=ChoicesWidget(settings.GENDER_CHOICES),
        attribute='user__gender',
        column_name="Gènere",
    )
Impatiens answered 28/9, 2021 at 9:55 Comment(0)
R
0

Another solution:

class BaseModelResource(resources.ModelResource):

    def export_field(self, field, obj):
        field_name = self.get_field_name(field)
        func_name = 'get_{}_display'.format(field_name)
        if hasattr(obj, func_name):
            return getattr(obj, func_name)
        return super().export_field(field, obj)


class ProductReportResource(BaseModelResource):
    ...
Reopen answered 11/11, 2020 at 12:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.