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) + " " + 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(' ') 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(' ') 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]))
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])
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(' ') 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]))
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(' ') 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]))