Exemple #1
0
def has_action_checkbox(cl):
    for i, field_name in enumerate(cl.list_display):
        text, attr = label_for_field(field_name,
                                     cl.model,
                                     model_admin=cl.model_admin,
                                     return_attr=True)
        if attr:
            field_name = _coerce_field_name(field_name, i)
            # Potentially not sortable

            # if the field is the action checkbox: no sorting and special class
            if field_name == "action_checkbox":
                return True
def semantic_items_for_result(cl, result, form):
    """
    Generate the actual list of data.
    """
    def link_in_col(is_first, field_name, cl):
        if cl.list_display_links is None:
            return False
        if is_first and not cl.list_display_links:
            return True
        return field_name in cl.list_display_links

    first = True
    pk = cl.lookup_opts.pk.attname
    for field_index, field_name in enumerate(cl.list_display):
        empty_value_display = cl.model_admin.get_empty_value_display()
        row_classes = [
            "field-%s" % _coerce_field_name(field_name, field_index)
        ]
        try:
            f, attr, value = lookup_field(field_name, result, cl.model_admin)
        except ObjectDoesNotExist:
            result_repr = empty_value_display
        else:
            empty_value_display = getattr(attr, "empty_value_display",
                                          empty_value_display)
            if f is None or f.auto_created:
                if field_name == "action_checkbox":
                    row_classes = ["action-checkbox"]
                boolean = getattr(attr, "boolean", False)
                # BEGIN CUSTOMIZATION
                result_repr = semantic_display_for_value(
                    value, empty_value_display, boolean)
                # END CUSTOMIZATION
                if isinstance(value, (datetime.date, datetime.time)):
                    row_classes.append("nowrap")
            else:
                if isinstance(f.remote_field, models.ManyToOneRel):
                    field_val = getattr(result, f.name)
                    if field_val is None:
                        result_repr = empty_value_display
                    else:
                        result_repr = field_val
                else:
                    # BEGIN CUSTOMIZATION
                    result_repr = semantic_display_for_field(
                        value, f, empty_value_display)
                    # END CUSTOMIZATION
                if isinstance(
                        f,
                    (models.DateField, models.TimeField, models.ForeignKey)):
                    row_classes.append("nowrap")
        row_class = mark_safe(' class="%s"' % " ".join(row_classes))
        # If list_display_links not defined, add the link tag to the first field
        if link_in_col(first, field_name, cl):

            # BEGIN CUSTOMIZATION
            table_tag = "td"
            # END CUSTOMIZATION

            first = False

            # Display link to the result's change_view if the url exists, else
            # display just the result's representation.
            try:
                url = cl.url_for_result(result)
            except NoReverseMatch:
                link_or_text = result_repr
            else:
                url = add_preserved_filters(
                    {
                        "preserved_filters": cl.preserved_filters,
                        "opts": cl.opts
                    }, url)
                # Convert the pk to something that can be used in Javascript.
                # Problem cases are non-ASCII strings.
                if cl.to_field:
                    attr = str(cl.to_field)
                else:
                    attr = pk
                value = result.serializable_value(attr)
                link_or_text = format_html(
                    '<a href="{}"{}>{}</a>',
                    url,
                    format_html(' data-popup-opener="{}"', value)
                    if cl.is_popup else "",
                    result_repr,
                )

            yield format_html("<{}{}>{}</{}>", table_tag, row_class,
                              link_or_text, table_tag)
        else:
            # By default the fields come from ModelAdmin.list_editable, but if we pull
            # the fields out of the form instead of list_editable custom admins
            # can provide fields on a per request basis
            if (form and field_name in form.fields
                    and not (field_name == cl.model._meta.pk.name
                             and form[cl.model._meta.pk.name].is_hidden)):

                # BEGIN CUSTOMIZATION
                field = form.fields[field_name]
                bf = form[field_name]
                if isinstance(field.widget, RelatedFieldWidgetWrapper):
                    bf_repr = str(bf.errors) + "&nbsp;" + str(bf)
                else:
                    bf_repr = str(bf.errors) + str(bf)
                result_repr = mark_safe(bf_repr)
                # END CUSTOMIZATION

            yield format_html("<td{}>{}</td>", row_class, result_repr)
    if form and not form[cl.model._meta.pk.name].is_hidden:
        yield format_html("<td>{}</td>", form[cl.model._meta.pk.name])
def items_for_result(cl, result, form,
                     user):  # added parameter 'owner' to function
    """
    Generate the actual list of data. 
    Added custom link logic on list - returns false if the user is not the owner and not superuser.
    """
    def link_in_col(is_first, field_name, cl,
                    owner):  # added parameter 'owner' to function
        if cl.list_display_links is None or not owner:  # added - row not link if administrator not owner of user row
            return False
        if is_first and not cl.list_display_links:
            return True
        return field_name in cl.list_display_links

    # added owner of user row
    owner = False
    if user.is_superuser or result.user_created == user:
        owner = True

    first = True
    pk = cl.lookup_opts.pk.attname
    for field_index, field_name in enumerate(cl.list_display):
        empty_value_display = cl.model_admin.get_empty_value_display()
        row_classes = [
            'field-%s' % _coerce_field_name(field_name, field_index)
        ]
        try:
            f, attr, value = lookup_field(field_name, result, cl.model_admin)
        except ObjectDoesNotExist:
            result_repr = empty_value_display
        else:
            empty_value_display = getattr(attr, 'empty_value_display',
                                          empty_value_display)
            if f is None or f.auto_created:
                if field_name == 'action_checkbox':
                    row_classes = ['action-checkbox']
                boolean = getattr(attr, 'boolean', False)
                result_repr = display_for_value(value, empty_value_display,
                                                boolean)
                if isinstance(value, (datetime.date, datetime.time)):
                    row_classes.append('nowrap')
            else:
                if isinstance(f.remote_field, models.ManyToOneRel):
                    field_val = getattr(result, f.name)
                    if field_val is None:
                        result_repr = empty_value_display
                    else:
                        result_repr = field_val
                else:
                    result_repr = display_for_field(value, f,
                                                    empty_value_display)
                if isinstance(
                        f,
                    (models.DateField, models.TimeField, models.ForeignKey)):
                    row_classes.append('nowrap')
        if str(result_repr) == '':
            result_repr = mark_safe('&nbsp;')
        row_class = mark_safe(' class="%s"' % ' '.join(row_classes))
        # If list_display_links not defined, add the link tag to the first field
        if link_in_col(first, field_name, cl, owner):
            table_tag = 'th' if first else 'td'
            first = False

            # Display link to the result's change_view if the url exists, else
            # display just the result's representation.
            try:
                url = cl.url_for_result(result)
            except NoReverseMatch:
                link_or_text = result_repr
            else:
                url = add_preserved_filters(
                    {
                        'preserved_filters': cl.preserved_filters,
                        'opts': cl.opts
                    }, url)
                # Convert the pk to something that can be used in Javascript.
                # Problem cases are non-ASCII strings.
                if cl.to_field:
                    attr = str(cl.to_field)
                else:
                    attr = pk
                value = result.serializable_value(attr)
                link_or_text = format_html(
                    '<a href="{}"{}>{}</a>', url,
                    format_html(' data-popup-opener="{}"', value)
                    if cl.is_popup else '', result_repr)

            yield format_html('<{}{}>{}</{}>', table_tag, row_class,
                              link_or_text, table_tag)
        else:
            # By default the fields come from ModelAdmin.list_editable, but if we pull
            # the fields out of the form instead of list_editable custom admins
            # can provide fields on a per request basis
            if (form and field_name in form.fields
                    and not (field_name == cl.model._meta.pk.name
                             and form[cl.model._meta.pk.name].is_hidden)):
                bf = form[field_name]
                result_repr = mark_safe(str(bf.errors) + str(bf))
            yield format_html('<td{}>{}</td>', row_class, result_repr)
    if form and not form[cl.model._meta.pk.name].is_hidden:
        yield format_html('<td>{}</td>', form[cl.model._meta.pk.name])
def mptt_items_for_result(cl, result, form):
    """
    Generates the actual list of data.
    """

    def link_in_col(is_first, field_name, cl):
        if cl.list_display_links is None:
            return False
        if is_first and not cl.list_display_links:
            return True
        return field_name in cl.list_display_links

    first = True
    pk = cl.lookup_opts.pk.attname

    # #### MPTT ADDITION START
    # figure out which field to indent
    mptt_indent_field = getattr(cl.model_admin, 'mptt_indent_field', None)
    if not mptt_indent_field:
        for field_name in cl.list_display:
            try:
                f = cl.lookup_opts.get_field(field_name)
            except models.FieldDoesNotExist:
                if (mptt_indent_field is None and
                        field_name != 'action_checkbox'):
                    mptt_indent_field = field_name
            else:
                # first model field, use this one
                mptt_indent_field = field_name
                break

    # figure out how much to indent
    mptt_level_indent = getattr(cl.model_admin, 'mptt_level_indent', MPTT_ADMIN_LEVEL_INDENT)
    # #### MPTT ADDITION END

    for field_index, field_name in enumerate(cl.list_display):
        # #### MPTT SUBSTITUTION START
        empty_value_display = cl.model_admin.get_empty_value_display()
        # #### MPTT SUBSTITUTION END
        row_classes = ['field-%s' % _coerce_field_name(field_name, field_index)]
        try:
            f, attr, value = lookup_field(field_name, result, cl.model_admin)
        except ObjectDoesNotExist:
            result_repr = empty_value_display
        else:
            empty_value_display = getattr(attr, 'empty_value_display', empty_value_display)
            if f is None or f.auto_created:
                if field_name == 'action_checkbox':
                    row_classes = ['action-checkbox']
                allow_tags = getattr(attr, 'allow_tags', False)
                boolean = getattr(attr, 'boolean', False)
                # #### MPTT SUBSTITUTION START
                result_repr = display_for_value(value, empty_value_display, boolean)
                # #### MPTT SUBSTITUTION END
                if allow_tags:
                    warnings.warn(
                        "Deprecated allow_tags attribute used on field {}. "
                        "Use django.utils.safestring.format_html(), "
                        "format_html_join(), or mark_safe() instead.".format(field_name),
                        RemovedInDjango20Warning
                    )
                    result_repr = mark_safe(result_repr)
                if isinstance(value, (datetime.date, datetime.time)):
                    row_classes.append('nowrap')
            else:
                # #### MPTT SUBSTITUTION START
                is_many_to_one = isinstance(f.remote_field, models.ManyToOneRel)
                if is_many_to_one:
                    # #### MPTT SUBSTITUTION END
                    field_val = getattr(result, f.name)
                    if field_val is None:
                        result_repr = empty_value_display
                    else:
                        result_repr = field_val
                else:
                    # #### MPTT SUBSTITUTION START
                    result_repr = display_for_field(value, f, empty_value_display)
                    # #### MPTT SUBSTITUTION END
                if isinstance(f, (models.DateField, models.TimeField, models.ForeignKey)):
                    row_classes.append('nowrap')
        if force_text(result_repr) == '':
            result_repr = mark_safe('&nbsp;')
        row_class = mark_safe(' class="%s"' % ' '.join(row_classes))

        # #### MPTT ADDITION START
        if field_name == mptt_indent_field:
            level = getattr(result, result._mptt_meta.level_attr)
            padding_attr = mark_safe(' style="padding-%s:%spx"' % (
                'right' if get_language_bidi() else 'left',
                8 + mptt_level_indent * level))
        else:
            padding_attr = ''
        # #### MPTT ADDITION END

        # If list_display_links not defined, add the link tag to the first field
        if link_in_col(first, field_name, cl):
            table_tag = 'th' if first else 'td'
            first = False

            # Display link to the result's change_view if the url exists, else
            # display just the result's representation.
            try:
                url = cl.url_for_result(result)
            except NoReverseMatch:
                link_or_text = result_repr
            else:
                url = add_preserved_filters(
                    {'preserved_filters': cl.preserved_filters, 'opts': cl.opts}, url,
                )
                # Convert the pk to something that can be used in Javascript.
                # Problem cases are long ints (23L) and non-ASCII strings.
                if cl.to_field:
                    attr = str(cl.to_field)
                else:
                    attr = pk
                value = result.serializable_value(attr)
                if cl.is_popup:
                    opener = format_html(' data-popup-opener="{}"', value)
                else:
                    opener = ''
                link_or_text = format_html(
                    '<a href="{}"{}>{}</a>',
                    url,
                    opener,
                    result_repr)

            # #### MPTT SUBSTITUTION START
            yield format_html('<{}{}{}>{}</{}>',
                              table_tag,
                              row_class,
                              padding_attr,
                              link_or_text,
                              table_tag)
            # #### MPTT SUBSTITUTION END
        else:
            # By default the fields come from ModelAdmin.list_editable, but if we pull
            # the fields out of the form instead of list_editable custom admins
            # can provide fields on a per request basis
            if (form and field_name in form.fields and not (
                    field_name == cl.model._meta.pk.name and
                    form[cl.model._meta.pk.name].is_hidden)):
                bf = form[field_name]
                result_repr = mark_safe(force_text(bf.errors) + force_text(bf))
            # #### MPTT SUBSTITUTION START
            yield format_html('<td{}{}>{}</td>', row_class, padding_attr, result_repr)
            # #### MPTT SUBSTITUTION END
    if form and not form[cl.model._meta.pk.name].is_hidden:
        yield format_html('<td>{}</td>', force_text(form[cl.model._meta.pk.name]))
Exemple #5
0
    def items_for_result(self):
        # 1. Removed "nowrap" CSS-class
        # 2. Removed <th> from table body
        # 3. Add "display_editable_field" function

        first = True
        pk = self.cl.lookup_opts.pk.attname
        for field_index, field_name in enumerate(self.cl.list_display):
            empty_value_display = self.cl.model_admin.get_empty_value_display()
            row_classes = [
                "field-%s" %
                admin_list._coerce_field_name(field_name, field_index)
            ]

            try:
                f, attr, value = lookup_field(field_name, self.obj,
                                              self.cl.model_admin)
            except ObjectDoesNotExist:
                result_repr = empty_value_display
            else:
                empty_value_display = getattr(attr, "empty_value_display",
                                              empty_value_display)
                if f is None or f.auto_created:
                    if field_name == "action_checkbox":
                        row_classes = ["action-checkbox"]
                    boolean = getattr(attr, "boolean", False)
                    result_repr = display_for_value(value, empty_value_display,
                                                    boolean)
                else:
                    if isinstance(f.remote_field, models.ManyToOneRel):
                        field_val = getattr(self.obj, f.name)
                        if field_val is None:
                            result_repr = empty_value_display
                        else:
                            result_repr = field_val
                    else:
                        result_repr = display_for_field(
                            value, f, empty_value_display)

            row_class = mark_safe(" class='%s'" % " ".join(row_classes))

            # If list_display_links not defined, add the link tag to the first field
            if self._link_in_col(first, field_name):
                first = False

                # Display link to the result's change_view if the url exists, else
                # display just the result's representation.
                try:
                    url = self.cl.url_for_result(self.obj)
                except NoReverseMatch:
                    link_or_text = result_repr
                else:
                    url = add_preserved_filters(
                        {
                            "preserved_filters": self.cl.preserved_filters,
                            "opts": self.cl.opts
                        }, url)

                    # Convert the pk to something that can be used in Javascript.
                    # Problem cases are non-ASCII strings.
                    if self.cl.to_field:
                        attr = str(self.cl.to_field)
                    else:
                        attr = pk

                    value = self.obj.serializable_value(attr)
                    link_or_text = format_html(
                        '<a href="{}"{}>{}</a>', url,
                        format_html(' data-popup-opener="{}"', value)
                        if self.cl.is_popup else '', result_repr)

                yield format_html("<td{}>{}</td>", row_class, link_or_text)
            else:
                # By default the fields come from ModelAdmin.list_editable, but if we pull
                # the fields out of the form instead of list_editable custom admins
                # can provide fields on a per request basis
                if (self.form and field_name in self.form.fields and not (
                        field_name == self.cl.model._meta.pk.name
                        and self.form[self.cl.model._meta.pk.name].is_hidden)):
                    result_repr = self.display_editable_field(field_name)
                yield format_html("<td{}>{}</td>", row_class, result_repr)

        if self.form and not self.form[self.cl.model._meta.pk.name].is_hidden:
            yield format_html("<td>{}</td>",
                              self.form[self.cl.model._meta.pk.name])
Exemple #6
0
def mptt_items_for_result(cl, result, form):
    """
    Generates the actual list of data.
    """
    def link_in_col(is_first, field_name, cl):
        if cl.list_display_links is None:
            return False
        if is_first and not cl.list_display_links:
            return True
        return field_name in cl.list_display_links

    first = True
    pk = cl.lookup_opts.pk.attname

    # #### MPTT ADDITION START
    # figure out which field to indent
    mptt_indent_field = getattr(cl.model_admin, 'mptt_indent_field', None)
    if not mptt_indent_field:
        for field_name in cl.list_display:
            try:
                f = cl.lookup_opts.get_field(field_name)
            except models.FieldDoesNotExist:
                if (mptt_indent_field is None
                        and field_name != 'action_checkbox'):
                    mptt_indent_field = field_name
            else:
                # first model field, use this one
                mptt_indent_field = field_name
                break

    # figure out how much to indent
    mptt_level_indent = getattr(cl.model_admin, 'mptt_level_indent',
                                MPTT_ADMIN_LEVEL_INDENT)
    # #### MPTT ADDITION END

    for field_index, field_name in enumerate(cl.list_display):
        # #### MPTT SUBSTITUTION START
        empty_value_display = cl.model_admin.get_empty_value_display()
        # #### MPTT SUBSTITUTION END
        row_classes = [
            'field-%s' % _coerce_field_name(field_name, field_index)
        ]
        try:
            f, attr, value = lookup_field(field_name, result, cl.model_admin)
        except ObjectDoesNotExist:
            result_repr = empty_value_display
        else:
            empty_value_display = getattr(attr, 'empty_value_display',
                                          empty_value_display)
            if f is None or f.auto_created:
                if field_name == 'action_checkbox':
                    row_classes = ['action-checkbox']
                allow_tags = getattr(attr, 'allow_tags', False)
                boolean = getattr(attr, 'boolean', False)
                # #### MPTT SUBSTITUTION START
                result_repr = display_for_value(value, empty_value_display,
                                                boolean)
                # #### MPTT SUBSTITUTION END
                if allow_tags:
                    warnings.warn(
                        "Deprecated allow_tags attribute used on field {}. "
                        "Use django.utils.safestring.format_html(), "
                        "format_html_join(), or mark_safe() instead.".format(
                            field_name), RemovedInDjango20Warning)
                    result_repr = mark_safe(result_repr)
                if isinstance(value, (datetime.date, datetime.time)):
                    row_classes.append('nowrap')
            else:
                # #### MPTT SUBSTITUTION START
                is_many_to_one = isinstance(f.remote_field,
                                            models.ManyToOneRel)
                if is_many_to_one:
                    # #### MPTT SUBSTITUTION END
                    field_val = getattr(result, f.name)
                    if field_val is None:
                        result_repr = empty_value_display
                    else:
                        result_repr = field_val
                else:
                    # #### MPTT SUBSTITUTION START
                    result_repr = display_for_field(value, f,
                                                    empty_value_display)
                    # #### MPTT SUBSTITUTION END
                if isinstance(
                        f,
                    (models.DateField, models.TimeField, models.ForeignKey)):
                    row_classes.append('nowrap')
        if force_text(result_repr) == '':
            result_repr = mark_safe('&nbsp;')
        row_class = mark_safe(' class="%s"' % ' '.join(row_classes))

        # #### MPTT ADDITION START
        if field_name == mptt_indent_field:
            level = getattr(result, result._mptt_meta.level_attr)
            padding_attr = mark_safe(
                ' style="padding-%s:%spx"' %
                ('right' if get_language_bidi() else 'left',
                 8 + mptt_level_indent * level))
        else:
            padding_attr = ''
        # #### MPTT ADDITION END

        # If list_display_links not defined, add the link tag to the first field
        if link_in_col(first, field_name, cl):
            table_tag = 'th' if first else 'td'
            first = False

            # Display link to the result's change_view if the url exists, else
            # display just the result's representation.
            try:
                url = cl.url_for_result(result)
            except NoReverseMatch:
                link_or_text = result_repr
            else:
                url = add_preserved_filters(
                    {
                        'preserved_filters': cl.preserved_filters,
                        'opts': cl.opts
                    },
                    url,
                )
                # Convert the pk to something that can be used in Javascript.
                # Problem cases are long ints (23L) and non-ASCII strings.
                if cl.to_field:
                    attr = str(cl.to_field)
                else:
                    attr = pk
                value = result.serializable_value(attr)
                if cl.is_popup:
                    opener = format_html(' data-popup-opener="{}"', value)
                else:
                    opener = ''
                link_or_text = format_html('<a href="{}"{}>{}</a>', url,
                                           opener, result_repr)

            # #### MPTT SUBSTITUTION START
            yield format_html('<{}{}{}>{}</{}>', table_tag, row_class,
                              padding_attr, link_or_text, table_tag)
            # #### MPTT SUBSTITUTION END
        else:
            # By default the fields come from ModelAdmin.list_editable, but if we pull
            # the fields out of the form instead of list_editable custom admins
            # can provide fields on a per request basis
            if (form and field_name in form.fields
                    and not (field_name == cl.model._meta.pk.name
                             and form[cl.model._meta.pk.name].is_hidden)):
                bf = form[field_name]
                result_repr = mark_safe(force_text(bf.errors) + force_text(bf))
            # #### MPTT SUBSTITUTION START
            yield format_html('<td{}{}>{}</td>', row_class, padding_attr,
                              result_repr)
            # #### MPTT SUBSTITUTION END
    if form and not form[cl.model._meta.pk.name].is_hidden:
        yield format_html('<td>{}</td>',
                          force_text(form[cl.model._meta.pk.name]))
Exemple #7
0
def result_headers(cl):
    """
    Generate the list column headers.
    """
    ordering_field_columns = cl.get_ordering_field_columns()
    for i, field_name in enumerate(cl.list_display):
        text, attr = label_for_field(field_name,
                                     cl.model,
                                     model_admin=cl.model_admin,
                                     return_attr=True)
        if attr:
            field_name = _coerce_field_name(field_name, i)
            # Potentially not sortable

            # if the field is the action checkbox: no sorting and special class
            if field_name == "action_checkbox":
                yield {
                    "text": mark_safe(text),
                    "class_attrib": mark_safe("action-checkbox-column"),
                    "sortable": False,
                }
                continue

            admin_order_field = getattr(attr, "admin_order_field", None)
            if not admin_order_field:
                # Not sortable
                yield {
                    "text": text,
                    "class_attrib": format_html("column-{}", field_name),
                    "sortable": False,
                }
                continue

        # OK, it is sortable if we got this far
        th_classes = ["sortable", "column-{}".format(field_name)]
        order_type = ""
        new_order_type = "asc"
        sort_priority = 0
        sorted = False
        # Is it currently being sorted on?
        if i in ordering_field_columns:
            sorted = True
            order_type = ordering_field_columns.get(i).lower()
            sort_priority = list(ordering_field_columns).index(i) + 1
            th_classes.append("sorted %sending" % order_type)
            new_order_type = {"asc": "desc", "desc": "asc"}[order_type]

        # build new ordering param
        o_list_primary = []  # URL for making this field the primary sort
        o_list_remove = []  # URL for removing this field from sort
        o_list_toggle = []  # URL for toggling order type for this field

        def make_qs_param(t, n):
            return ("-" if t == "desc" else "") + str(n)

        for j, ot in ordering_field_columns.items():
            if j == i:  # Same column
                param = make_qs_param(new_order_type, j)
                # We want clicking on this header to bring the ordering to the
                # front
                o_list_primary.insert(0, param)
                o_list_toggle.append(param)
                # o_list_remove - omit
            else:
                param = make_qs_param(ot, j)
                o_list_primary.append(param)
                o_list_toggle.append(param)
                o_list_remove.append(param)

        if i not in ordering_field_columns:
            o_list_primary.insert(0, make_qs_param(new_order_type, i))

        yield {
            "text":
            text,
            "sortable":
            True,
            "sorted":
            sorted,
            "ascending":
            order_type == "asc",
            "sort_priority":
            sort_priority,
            "url_primary":
            cl.get_query_string({ORDER_VAR: ".".join(o_list_primary)}),
            "url_remove":
            cl.get_query_string({ORDER_VAR: ".".join(o_list_remove)}),
            "url_toggle":
            cl.get_query_string({ORDER_VAR: ".".join(o_list_toggle)}),
            "class_attrib":
            format_html("{}", " ".join(th_classes)) if th_classes else "",
        }
def _items_for_result(cl, result, form, namespace='common'):
    """
    Generates the actual list of data.
    """
    def link_in_col(is_first, field_name, cl):
        if cl.list_display_links is None:
            return False
        if is_first and not cl.list_display_links:
            return True
        return field_name in cl.list_display_links

    first = True
    pk = cl.lookup_opts.pk.attname
    for field_index, field_name in enumerate(cl.list_display):
        empty_value_display = cl.model_admin.get_empty_value_display()
        row_classes = [
            'field-%s' % _coerce_field_name(field_name, field_index)
        ]
        try:
            f, attr, value = lookup_field(field_name, result, cl.model_admin)
        except ObjectDoesNotExist:
            result_repr = empty_value_display
        else:
            empty_value_display = getattr(attr, 'empty_value_display',
                                          empty_value_display)
            if f is None or f.auto_created:
                if field_name == 'action_checkbox':
                    row_classes = ['action-checkbox']
                if field_name == 'details_button':
                    row_classes = ['details-button']
                allow_tags = getattr(attr, 'allow_tags', False)
                boolean = getattr(attr, 'boolean', False)
                result_repr = display_for_value(value, empty_value_display,
                                                boolean)
                if allow_tags:
                    warnings.warn(
                        "Deprecated allow_tags attribute used on field {}. "
                        "Use django.utils.html.format_html(), format_html_join(), "
                        "or django.utils.safestring.mark_safe() instead.".
                        format(field_name), RemovedInDjango20Warning)
                    result_repr = mark_safe(result_repr)
                if isinstance(value, (datetime.date, datetime.time)):
                    row_classes.append('nowrap')
            else:
                if isinstance(f.remote_field, models.ManyToOneRel):
                    field_val = getattr(result, f.name)
                    if field_val is None:
                        result_repr = empty_value_display
                    else:
                        result_repr = field_val
                else:
                    result_repr = display_for_field(value, f,
                                                    empty_value_display)
                if isinstance(
                        f,
                    (models.DateField, models.TimeField, models.ForeignKey)):
                    row_classes.append('nowrap')
        if force_text(result_repr) == '':
            result_repr = mark_safe('&nbsp;')
        row_class = mark_safe(' class="%s"' % ' '.join(row_classes))
        # If list_display_links not defined, add the link tag to the first field
        if link_in_col(first, field_name, cl):
            table_tag = 'th' if first else 'td'
            first = False

            # Display link to the result's change_view if the url exists, else
            # display just the result's representation.
            try:
                url = cl.url_for_result(result)
            except NoReverseMatch:
                link_or_text = result_repr
            else:
                url = common_add_preserved_filters(
                    {
                        'preserved_filters': cl.preserved_filters,
                        'opts': cl.opts
                    }, url)
                # Convert the pk to something that can be used in Javascript.
                # Problem cases are long ints (23L) and non-ASCII strings.
                if cl.to_field:
                    attr = str(cl.to_field)
                else:
                    attr = pk
                value = result.serializable_value(attr)
                link_or_text = format_html(
                    '<a href="{}"{}>{}</a>', url,
                    format_html(' data-popup-opener="{}"', value)
                    if cl.is_popup else '', result_repr)

            yield format_html('<{}{}>{}</{}>', table_tag, row_class,
                              link_or_text, table_tag)
        else:
            # By default the fields come from ModelAdmin.list_editable, but if we pull
            # the fields out of the form instead of list_editable custom admins
            # can provide fields on a per request basis
            if (form and field_name in form.fields
                    and not (field_name == cl.model._meta.pk.name
                             and form[cl.model._meta.pk.name].is_hidden)):
                bf = form[field_name]
                result_repr = mark_safe(force_text(bf.errors) + force_text(bf))
            yield format_html('<td{}>{}</td>', row_class, result_repr)
    if form and not form[cl.model._meta.pk.name].is_hidden:
        yield format_html('<td>{}</td>',
                          force_text(form[cl.model._meta.pk.name]))