Django models - html/render attribute? - python

I use the same models in many different templates and tables. I'm looking for a way to tell Django how to render those objects in templates so I don't have to write the same html again and again.
For example model Url - when I want to display it inside a template or table, I have to write (sometimes much more):
{{ url.site.name }}
which renders:
Stackoverflow.com
It would be better if I could just do something like:
{{ url }} # url is Url model object
I think that I can add methods like def render_object(self) like this:
def render_object(self):
return mark_safe("""{}""".format(self.url,self.site.name))
and in templates:
{{ url.render_object }}
but I'm curious if it is there some built in function. As far as I know __unicode__(self) would do the work but it would mess admin and shell display names.

Add custom template tag my_tags.py like render_url and then in your template load that template tag ({% load my_tags %}) and send url object to it: {% render_url url %}. You can use html template in your tag or just make result as a string and return it. Check the documentation for details.

Related

Nested Django view with .html inserted using include tag

I would like to know if anyone has any best practice recommendations for rendering a view within a view in Django, or something with a similar effect where both views can have their own context and methods.
I am currently rendering the dropdown using the built-in include tag. So the nested .html is using the same Django view as the rest of the page. And all the context is coming from the main view as shown below. I would like to give this dropdown its own Django view so that I only perform certain database queries and other calculations if the dropdown is opened.
<div class="container-fluid">
<div class="row">
<div class="col-6">
</div>
<div class="col-2 d-flex justify-content-center">
{% include nested.html %}
</div> ...
It would be nice if someone with experience in this could let me know what they think, and if it even makes sense to try and split this into 2 views.
In summary. I would like to know if I can somehow render a separate view using something similar to the include Django tag. So that I have control over where the view gets rendered.
Below I have outlined my implementation of the solution below, using custom inclusion tags as suggested in the comments to my question.
You can make a custom template tag file in project directory and then register these in the template library. e.g:
template_tags.py
from django import template
from users.models import Organisation
register = template.Library()
#register.inclusion_tag('nested.html', takes_context=True)
def nested_template(context, param=None): #param to pass variables from main view
context.update({
'data_list': get_data_list(param)
'organisation_id': param,
})
return context
def get_data_list(self,param):
data_list = ... #do all queries needed.
return data_list
In the template tag you point to your nested.html which does whatever you need it to do. For example:
nested.html
{% for data in data_list %}
<h4> {{data}} </h4>
{% endfor %}
Then to include the template, in your main view template:
{% load nested_template %} #at the top or anywhere before using it
{% nested_template param %} #where you want the template included
Hopefully clear enough and may assist someone

Trouble using a custom tag correctly with Django

Summary
I've been trying to get a custom tag working in Django, but seemingly it wont register correctly.
The index file looks to load correctly, it just complains about the tag not being registered correctly.
What I've done right now is just to put the .py file where I register the tag inside an app that is in the django installed apps part.
Should I be doing something else to ensure the tag registers properly?
Further info
The error I get:
Invalid block tag on line 1: 'show_loans'. Did you forget to register
or load this tag?
The view where I call the tag
index.html
{% show_loans %}
The python file where i try to register the tag
loansTable.py
from .models import Loan
from datetime import datetime
from django import template
register = template.Library()
#register.simple_tag('loansTable.html')
def show_loans():
l1 = Loan()
l2 = Loan()
l1.loanedDate_date = datetime.now
l2.handinDate_date = datetime.now
l2.loanedDate_date = datetime.now
l2.handinDate_date = datetime.now
loans2 = { l1, l2 }
return {'loans': loans2}
loansTable.html
<ul>
{% for loan in loans %}
<li> {{ loan }} </li>
{% endfor %}
</ul>
Folder structure:
-app
--templates
---customTemplates
----index.html
----loansTable.html
--loansTable.py
Thanks for your help.
You don't need to register your tag to a template. You just need to load it from there. Which you are already doing.
Therefore just replace:
#register.simple_tag('loansTable.html')
With this:
#register.simple_tag
You also need to put your custom tags in a templatetags directory. From the docs:
In your index.html you must load template tags by file name where you have registered your template tags.
i.e. if you registered tag inside custom_tags.py file
{% load custom_tags %}
The app should contain a templatetags directory, at the same level as models.py, views.py, etc. If this doesn’t already exist, create it - don’t forget the init.py file to ensure the directory is treated as a Python package.
The error tells you exactly what is wrong: you did not load the tag in the template where you are using it, ie index.html.
{% load loansTable %}
{% show_loans %}
Also, you are confusing your tag types. The tag that renders another template is called an inclusion tag, so you should use that when you register it:
#register.inclusion_tag('loansTable.html')
def show_loans():
...

How to display my python code in a table on Django webpage?

I have written some code in Python that reads in two strings, removes the punctuation and then compares the words in them within a matrix table which it prints to the console.
How do I convert the code to be utilised within the Django framework. I want to display a similar matrix on the web. I've already imported it into views. Please may someone point me in the right direction? I've been using django project and lynda to learn as I go along,
Edit:
Merci for the help guys. Managed to get it to display on a webpage. But it is printing it all out as a single string. How do I style it a bit better?
Think of passing your data to a "Django webpage" as just passing a dictionary of your values to a Django template from your Django view.
What is a Django template?
A Django template is the 'T' in Django's 'MTV' design pattern. In the conventional MVC design pattern (Model-View-Controller), the View is where you display things. In Django, Templates are where you display things. Oddly enough, the 'View' in Django is actually the Controller. This took me a while to wrap my head around.
Why do we use a dictionary-like context?
By mapping keys to values we achieve super-fast [O(1)/constant] lookup in the Django templates.
With all of this in mind, I'd advocate using 'TemplateView' generic view, doing your work in a utils file, importing utils into views, and then passing your data to the template via the context dictionary. So it would look something like this:
local_utils.py
import string
import pandas as pd
pd.set_option('display.max_columns', None)
def generate_out_matrix():
with open('./arrayattempts/samp.txt', 'r') as file1:
sampInput=file1.read().replace('\n', '')
#print(sampInput)
with open('./arrayattempts/ref.txt', 'r') as file2:
refInput=file2.read().replace('\n', '')
#print(refInput)
sampArray = [word.strip(string.punctuation) for word in sampInput.split()]
refArray = [word.strip(string.punctuation) for word in refInput.split()]
out=pd.DataFrame(index=refArray,columns=sampArray)
for i in range(0, out.shape[0]):
for word in sampArray:
out.ix[i,str(word)] = out.index[i].count(str(word))
return out.as_matrix()
views.py
from appname.local_utils import generate_out_matrix
class Detail(TemplateView):
template_name = 'appname/yourhtml.html'
# Will render on each call to URL for 'Detail'
def get_context_data(self):
out = generate_out_matrix()
context['out'] = out
return context
appname/templates/yourhtml.html
{% if out %}
{% for row in out_matrix %}
{% for o in row %}
{{ o }}
{% endfor %}
<br>
{% endfor %}
{% endif %}
urls.py
path('/your_path', views.Detail.as_view()),
https://docs.djangoproject.com/en/2.0/ref/templates/api/#rendering-a-context
To send your data to your template you should add your variable to context at your views
from django.http import Http404
from django.shortcuts import render
from polls.models import Poll
def detail(request, poll_id):
... // your logic
out // your variable
return render(request, 'yourhtml.html', {'out': out})
In html will be like that
{{ out }}
{% for o in out %}
{{ o }}
{% endfor %}
https://docs.djangoproject.com/en/2.0/topics/http/views/
You can style your table with some CSS or using ny lib struct to handle tables
You can follow this guide
display django-pandas dataframe in a django template

Using Django template tag "with" with the result of another template tag

I have a comment_form.html template, which is used in multiple places in my app, and I'd like to be able to pass the endpoint's url into that template from a parent template. Normally I would do this using the with tag:
{% with endpoint='/comments' %}
{% include 'comment_form.html' %}
{% endwith %}
The problem is that I can't use a string literal '/comments' here, but instead I need a url tag, like so: {% url 'blog:comments:comments' username=post.user.username object_id=post.id %}. The with template tag seems to expects a literal or a context variable and doesn't seem to be able to comprehend "use the result of another template tag".
One solution would be to pass the strings 'blog:comments:comments', post.user.username, post.id all separately. But this is a problem because different uses of the comment form may require different arguments to uniquely define the endpoint.
How can I use with with the result of another template tag?
You can't, but you don't need to. The url tag has an alternative syntax that injects is result into the context:
{% url 'blog:comments:comments' username=post.user.username object_id=post.id as endpoint %}

Django template check for empty when I have an if inside a for

I have the following code in my template:
{% for req in user.requests_made_set.all %}
{% if not req.is_published %}
{{ req }}
{% endif %}
{% empty %}
No requests
{% endfor %}
If there are some requests but none has the is_published = True then how could I output a message (like "No requests") ?? I'd only like to use Django templates and not do it in my view!
Thanks
Even if this might be possible to achieve in the template, I (and probably many other people) would advise against it. To achieve this, you basically need to find out whether there are any objects in the database matching some criteria. That is certainly not something that belongs into a template.
Templates are intended to be used to define how stuff is displayed. The task you're solving is determining what stuff to display. This definitely belongs in a view and not a template.
If you want to avoid placing it in a view just because you want the information to appear on each page, regardless of the view, consider using a context processor which would add the required information to your template context automatically, or writing a template tag that would solve this for you.

Categories

Resources