formatting table cell content in django-tables2 - django

Love django-tables... but something that I'm sure is trivial to solve is giving me fits. When the value I pass for a given row/column is like:
some<br/>random<br/>words<br/>returned
I want the browser to parse and render the content in that cell... to look like this:
somerandomwordsreturned
not escape the content I'm passing and display it like this:
some<br/>random<br/>words<br/>returned
Surely there's some flag or option that I've missed?

Use mark_safe as follows:
import django_tables2 as tables
from django.utils.safestring import mark_safe
class testTable(tables.Tables):
id = tables.Column()
html = tables.Column()
def render_html(self):
return mark_safe('some<br/>random<br/>words<br/>returned')
Same question was asked in this thread

If some of your data already contains HTML, the simplest solution is to use a TemplateColumn rather than a normal column and mark the value as safe:
class Table(tables.Table):
html_data = tables.TemplateColumn("{{ value|safe }}")
# ...

HA. Found it. It wasn't django-tables2 that was auto-escaping my content, it was the django templating system itself: https://code.djangoproject.com/wiki/AutoEscaping.
I had to change my template code to render the django-table2 like this:
{% autoescape off %}
{% load render_table from django_tables2 %}
{% render_table route_table %}
{% endautoescape %}

If you want to render as html your column value
import django_tables2 as tables
from django.utils.safestring import mark_safe
class testTable(tables.Tables):
# column 1
html = tables.Column()
# ....
def render_html(self, value):
return mark_safe(value)

Related

Make a change to a string in django template?

I have a queryset in Django that contains a string field. This is a filename, something like images/photo.jpg or images/photo.20.19.22.jpg. I need to rewrite them in one particular view so that ".thumbnail" is inserted before the extension. The previous names should become images/photo.thumbnail.jpg and images/photo.20.19.22.thumbnail.jpg.
What is the best way to do this? This is part of a queryset so it will look like:
{% for record in list %}
{{ record.image }}
{% endfor %}
Now of course I would love to do this outside of my template. However, I don't see a way in which I can do that. After all, this needs to be done for every record inside my queryset. To complicate things, this record does not come directly from a modal. This record is coming from a subquery, so I don't see a way for me to change the modal itself. Should I use templatetags for this? Any other recommendations?
FYI the subquery is something like this:
>>> from django.db.models import OuterRef, Subquery
>>> newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
>>> Post.objects.annotate(image=Subquery(newest.values('image')[:1]))
A simple custom template filter could do this.
#register.filter
def add_thumbnail(image):
return image.replace('.jpg', 'thumbnail.jpg')
And in the template:
{% for record in list %}
{{ record.image|add_thumbnail }}
{% endfor %}

How to fix 'Argument data to tableXXX is required' in django-tables2?

I'm setting up a webstore manager and I'm relying on django-tables2 package to show a list of products using the SimpleTableMixin. I want to add the filter/search capability to the view. As recommended by the django-tables2 package one can rely on django-filter package to provide filtering. However, it the case of a model with many fields it becomes almost impossible to query and develop forms for those efficiently. My goal is to use django-haystack to have a single input search form as a mean to query the model instances which should be displayed in a similar table/form.
I've tried to add the SimpleTableMixin to the django-haystack package generic SearchView. However I keep on getting the following error:
TypeError at /manager/front/products/
Argument data to ProductTable is required
So far my implementation goes as follow:
view:
# ############## Products ############## (previous implementation with django-filter)
# #method_decorator(staff_member_required, name='dispatch')
# class ProductList(SingleTableMixin, FilterView):
# model = Product
# table_class = tables.ProductTable
# filterset_class = filters.ProductFilter
# template_name = 'manager/front/products/product_list.html'
############## Products ##############
#method_decorator(staff_member_required, name='dispatch')
class ProductList(SingleTableMixin, SearchView):
model = Product
table_class = tables.ProductTable
template_name = 'manager/front/products/product_list.html'
tables:
import django_tables2 as tables
from front.models import Product
class ProductTable(tables.Table):
class Meta:
model = Product
template_name = 'django_tables2/bootstrap.html'
search_indexes.py:
from haystack import indexes
from front.models import Product
class ProductIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
def get_model(self):
return Product
urls:
path('front/products',views.ProductList.as_view(),name="manage_products"),
template:
{% extends 'base_site.html' %}
{% load render_table from django_tables2 %}
{% block content_title %}Manage Products{% endblock%}
{% block content %}
<form action="" method="get" class="form form-inline">
{{ form }}
<button class="btn btn-default" type="submit">Search</button>
</form>
{% render_table table %}
{% endblock %}
How can I remove that error and provide efficient search abilities to my list views?
Are you sure that you are using haystack.generic_views.SearchView and not haystack.views.SearchView? Please notice that on https://django-haystack.readthedocs.io/en/latest/views_and_forms.html it says:
As of version 2.4 the views in haystack.views.SearchView are deprecated in favor of the new generic views in haystack.generic_views.SearchView which use the standard Django class-based views which are available in every version of Django which is supported by Haystack.
Thus if you're using haystack.views.SearchView then the get_context_data of SingleTableMixin will never be called thus no table will be put in your context (i.e table will be empty). Actually because I dislike the behavior of {% render_table %} when its parameter is empty (it behaves different than the other Django tags/filters i.e it throws an exception while the django ones silently ignore that) I usually put it inside some {% if table %} checks.
UPDATE
It seems that for whatever reason the data is not passed to the table. I am not sure why, I can't test it right now but from a quick look at the source code your implementation should have been working (considering that SearchView has a get_queryset and TableMixin uses the get_queryset to retrieve its data). In any case you try overriding some methods of TableMixin to make sure that the table is properly returned (take a look at TableMixin here: https://django-tables2.readthedocs.io/en/latest/_modules/django_tables2/views.html).
I think the most definite solution would be to just bite the bullet and override get_table yourself. So, try adding something like this to your class:
def get_table(self, **kwargs):
table_class = self.get_table_class()
# I only change this line from the original to make sure that the self.get_queryset() is called to return the data
table = table_class(data=self.get_queryset(), **kwargs)
return RequestConfig(self.request, paginate=self.get_table_pagination(table)).configure(
table
)
One idea that just popped in my mind. Is there a possibility that the get_queryset() method of SearchView returns None due to bad configuration or whatever?

SelectDateWidget - how get to each subfield separately?

In project there is used SelectDateWidget and to render it in template it only need to write form.date_of_sth, but it renders all widgets (selects) in one. I would like to render each one separately. Is there any way to do it?
In Django 1.11:
Import the widget that you want to modify. Your choices can be found here: https://docs.djangoproject.com/en/1.11/ref/forms/widgets/#built-in-widgets
Create a subclass and specify the template name.
# app/widgets.py
from django.forms.widgets import DefaultWidget
class CustomWidget(DefaultWidget):
template_name = 'app/widget.html'
Create your template. This is copied exactly from django/forms/widgets/multiwidget.html but you can put anything you want here. You can also reference other existing widget templates for inspiration. Your choice can be found here: https://github.com/django/django/tree/master/django/forms/templates/django/forms/widgets
# app/templates/app/widget.html
{% spaceless %}
{% for widget in widget.subwidgets %}
{% include widget.template_name %}
{% endfor %}
{% endspaceless %}
Import your CustomWidget and add it to a field in your form.
# app/forms.py
from django import forms
from .widgets import CustomWidget
class MyForm(forms.Form):
my_field = forms.ExampleField(widget=CustomWidget())
Finally, in your template, render the main field and it will reference app/templates/app/widget.html to render each subfield manually based on the template you created.

Get data from the database into the main django admin page

i want to put some data from the database into the admin index page, so i am trying to add some code to the index.html, but the commands such as Model_name.object.get() don't seem to work there
<ul>{% trans 'Last Update at ' %}
{% for entryupdate in Updatetime.objects.all %}
{{ entryupdate.updatetime }}
{% endfor %}
</ul>
so what shall i use instead? The problem is that there is no variable associated with the object i need. If that would have been any other page i could have added the variable in the views.py, but that's not the case. Thank you!
Those sorts of functions don't work in any template.
You should use a custom template tag to query the data and return it.
Thank to the tip of Daniel i created that tag:
import datetime
from django import template
from Myapp.models import Updatetime
register = template.Library()
def update_time():
ss = Updatetime.objects.get(pk=1)
str11 = ss.updatetime.strftime("%d-%m-%Y %H:%M:%S")
return str11
register.simple_tag(update_time)

field's verbose_name in templates

Suppose I have a model:
from django.db import models
class Test(models.Model):
name=models.CharField(max_length=255, verbose_name=u'custom name')
How do I get my model's field's verbose name in templates? The following doesn't work:
{{ test_instance.name.verbose_name }}
I would very much appreciate the solution, something on lines as we do when using forms, using label attribute in template:
{{ form_field.label }}
You can use following python code for this
Test._meta.get_field("name").verbose_name.title()
If you want to use this in template then it will be best to register template tag for this. Create a templatetags folder inside your app containing two files (__init__.py and verbose_names.py).Put following code in verbose_names.py:
from django import template
register = template.Library()
#register.simple_tag
def get_verbose_field_name(instance, field_name):
"""
Returns verbose_name for a field.
"""
return instance._meta.get_field(field_name).verbose_name.title()
Now you can use this template tag in your template after loading the library like this:
{% load verbose_names %}
{% get_verbose_field_name test_instance "name" %}
You can read about Custom template tags in official django documentation.
The method in the accepted answer is awesome!
And maybe you'll like this if you want to generate a field list.
Adding an iterable to the class Test makes it convenient to list fields' verbose name and value.
Model
class Test(models.Model):
...
def __iter__(self):
for field in self._meta.fields:
yield (field.verbose_name, field.value_to_string(self))
Template
{% for field, val in test_instance %}
<div>
<label>{{ field }}:</label>
<p>{{ val }}</p>
</div>
{% endfor %}
based on this answer https://stackoverflow.com/a/14498938 .in Django Model i added
class Meta:
app_name = 'myapp'
in listview i have
from django.core import serializers
context['data'] = serializers.serialize( "python", self.get_queryset() )
inside mylist.html i have
{% for field, value in data.0.fields.items %}
<th style="text-align:center;">{% get_verbose_field_name data.0.model field %}</th>
{% endfor %}
in filter:
from django import template
register = template.Library()
from .models import Mymodel
#register.simple_tag
def get_verbose_field_name(instance, field_name):
"""
Returns verbose_name for a field.
"""
myinstance = eval(instance.split('.')[1].title())
return myinstance._meta.get_field(field_name).verbose_name.title()
instance in the abbove filter for the specific example is myapp.mymodel i evalute instance into model object and the i return field verbose name
it works in django 1.9
It's probably too late for an answer but I had the same issue until I realised that I caused the problem by overriding the fields in the form.py (self.fields['fieldname'] = ..). If you do that you also need to set a label otherwise it uses a label derived from the fieldname.
Hope this quick reply makes sense.