What is the best way to deal with NULL column values

Issue #59 new
Grizzle created an issue

In my application one of the columns is an attribute of a related model as seen below.

columns = ['location.room.site.code', 'row', 'code', 'name', 'owner']

In normal circumstances it works fine because most of the time the model I'm using for this datatable has a related location model.

The relation isn't required so when I first create the object without linking it to a location my datatable fails to render with the following error in the frontend.

DataTables warning: table id=datatable - Ajax error. For more information about this error, please see http://datatables.net/tn/7

and the following error on the Django end

django.db.models.fields.related_descriptors.RelatedObjectDoesNotExist: Rack has no location.

So I am thinking I need to override the get_columns() method and put in some way to handle this scenario. I'm fine with returning an empty/null value as there are cases where this will be a legitimate behaviour.

Am I correct in thinking this or is there a better way to do this?

Comments (2)

  1. Maciej Wisniowski repo owner

    I think you can override render_column method, something like below (code not tested):

    def render_column(self, row, column):
        if column == 'location.room.site.code':
            # do your stuff here, eg.
            try:
                 return row.location.room.site.code
             except Location.DoesNoteExists:  # assuming you have Location model
                 return '-'
        return super().render_column(row, column)
    
  2. Grizzle reporter

    What you suggested did work (a variation of anyway) but I found by putting the obj = getattr(obj, part) in a try/except block achieved the same thing and in theory should work for any other columns that have a similar issue.

        def render_column(self, row, column):
            """ Renders a column on a row. column can be given in a module notation eg. document.invoice.type
            """
            # try to find rightmost object
            obj = row
            parts = column.split('.')
            for part in parts[:-1]:
                if obj is None:
                    break
                try:
                    obj = getattr(obj, part)
                except:
                    return '-'
    
            # try using get_OBJECT_display for choice fields
            if hasattr(obj, 'get_%s_display' % parts[-1]):
                value = getattr(obj, 'get_%s_display' % parts[-1])()
            else:
                value = getattr(obj, parts[-1], None)
            if value is None:
                value = self.none_string
            if self.escape_values:
                value = escape(value)
            if value and hasattr(obj, 'get_absolute_url'):
                return '<a href="%s">%s</a>' % (obj.get_absolute_url(), value)
            return value
    

    I guess the other thing would be to return something appropriate to say that the column in empty.

  3. Log in to comment