How to construct a condition to choose appropriate function in template - python

I have two apps and want them to run one function in view.py and render in template. The only difference is that each app uses different models. For example, my first app uses function called like_post_fin:
post = get_object_or_404(Post_Fin, id=request.POST.get('id'))
and my second app uses function called like_post:
post = get_object_or_404(Post, id=request.POST.get('id'))
other part of code is same for each function.
In my first app template I will use to call function:
<form action="{% url 'like_post_fin' %}" method="post">
In my second app template I will use:
<form action="{% url 'like_post' %}" method="post">
other part of html code is same for both template.
When I run codes separately everything works perfect. But I want to have just one function and template for both apps which should use condition in view function or template.
I tried to use condition in app's template by using following code
{% if title == 'my app title' %}
<form action="{% url 'like_post_fin' %}" method="post">
{% else %}
<form action="{% url 'like_post' %}" method="post">
{% endif %}
But it did not work. Template titles are given using following code:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = 'my app title'
In my base html
{% if title %}
<title>web - {{ title }}</title>
{% else %}
<title> web </title>
{% endif %}
So, how to make condition in template or view file function

Related

Django How to pass username in a predefined template

I created a templates for header/footer and imports, if I want to acess the username in my header template I cant do that because it has no views. How can I pass the username to the header template?
header_template.py
from django import template
register = template.Library()
#register.inclusion_tag('home/partials/header.html')
def header(element):
return {'element': element, }
Import in Template
{% load header_template %}
{% header context %}
Usage in the template:
{% if user.is_authenticated %}
<a class="btn btn-primary display-4" href="{% url 'home:profil' %}">Profil</a>
{% else %}
<a class="btn btn-primary display-4" href="{% url 'home:login' %}">Login</a>
{% endif %}
Thanks for your help.
You can take context in your tag:
#register.inclusion_tag('home/partials/header.html', takes_context=True)
def header(context, element):
return context | {'element': element}
Read more here:
https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#inclusion-tags
My opinion, you are don't need this, The cause for every new tag in template - a wrong logic.

Implementing Search Form with Django

Hello Stackoverflow community,
I am having trouble with my form not rendering in Django.
Here's my attempt to render an empty form in views.py.
class SearchSite(forms.Form):
query = forms.CharField(label="New Item",
help_text="Search for any article located on the site.")
def search(request):
form = SearchSite()
context = {
"form": form,
"query_matches": query_matches
}
response = render(request, "encyclopedia/layout.html", context)
return response
Here's what my urls.py file looks like:
urlpatterns = [
path("", views.index, name="index"),
path("wiki/<str:page_title>", views.page, name="wiki"),
path("wiki/", views.search, name="site_search")
]
My layout.html file:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link href="{% static 'encyclopedia/styles.css' %}" rel="stylesheet">
</head>
<body>
<div class="row">
<div class="sidebar col-lg-2 col-md-3">
<h2>Wiki</h2>
<form action="{% url 'site_search' %}" method="get">
{% csrf_token %}
There should be something here
{{ form }}
<input type="submit">
</form>
<div>
Home
</div>
<div>
Create New Page
</div>
<div>
Random Page
</div>
{% block nav %}
{% endblock %}
</div>
<div class="main col-lg-10 col-md-9">
{% block body %}
{% endblock %}
</div>
</div>
</body>
</html>
I have noticed two particular problems in above screenshot. Firstly, my form does not render when inside my index.html webpage, which extends layout.html. Secondly, when I click the submit button, I get routed to a webpage that has my CSRF token in the url ... and then finally renders my form.
How can I fix this? Thanks everyone.
I have noticed two particular problems in above screenshot. Firstly,
my form does not render when inside my index.html webpage, which
extends layout.html.
Yes. You aren't passing form to index.html. Pass that in the view which renders the homepage. Even if it extends from layout.html, you need to pass it in the context for it to work.
def index(request):
# Your code.
return render(request, 'index.html', {'form': SearchSite()})
Secondly, when I click the submit button, I get routed to a webpage
that has my CSRF token in the url ... and then finally renders my
form.
That's because, in index.html, there is a blank form with a csrf_token, with an action set to /wiki, which calls search when the submit button is pressed. And search gives you layout.html, with the form, and as the form method is GET, it shows it in the url. I suggest changing it to POST if there is confidential data (and even otherwise. Why is there a csrf_token if it is not a POST request? Not needed. If you really want a GET request, then remove the csrf_token).
Here's my solution to the problem I had earlier for any future people visiting the post.
I wrote a form called SearchSite and defined a view called search in my views.py.
class SearchSite(forms.Form):
query = forms.CharField(
help_text="Search for any article located on the site.")
def search(request):
form = SearchSite()
is_substring_of_queries = []
if request.method == "GET":
form = SearchSite(request.GET)
if form.is_valid():
for entry in util.list_entries():
existsIdenticalResult = form.cleaned_data["query"].casefold() == entry.casefold()
existsResult = form.cleaned_data["query"].casefold() in entry.casefold()
if existsIdenticalResult:
return HttpResponseRedirect(reverse("wiki",
kwargs={"page_title": entry}))
elif existsResult:
is_substring_of_queries.append(entry)
context = {
"form": SearchSite(),
"is_substring_of_queries": is_substring_of_queries
}
response = render(request, "encyclopedia/search.html", context)
return response
When my view.search is requested, it will send the response of either an empty form (if accessed by index.html or if there are no results with a message saying there are no results) , an empty form and all the queries that are substrings of the markdown entries or route the client to an exact entry if the query matched.
Here's the routing down in my urls.py so far:
urlpatterns = [
path("", views.index, name="index"),
path("wiki/<str:page_title>", views.page, name="wiki"),
path("search/", views.search, name="site_search")
]
In my layout.html, I have the following form:
<form action="{% url 'site_search' %}" method="get">
{{ form }}
<input type="submit">
</form>
as well as in my search.html the queries that are substrings of the markdown entries:
{% if is_substring_of_queries %}
<h1>Search Results</h1>
{% for query in is_substring_of_queries%}
<li> {{ query }} </li>
{% endfor %}
{% else %}
<h1>No Results! Try again.</h1>
{% endif %}
If there are any mistakes, please let me know.

How to send object from detail view to another view in Django?

I have a detail view that uses a Quiz object to display data stored in that object, like title and author. I want to have a button that links to a new page that displays different data from the same object. I don't know how to pass this data/object.
I can render the view and pass it the context of a specific quiz using an id but I want the id to change to be the id of the object from the initial page.
#assessement view
def assessment(request):
context = {
'quiz':Quiz.objects.get(id=1),
}
return render(request, 'quiz_app/assessment.html', context)
#detailview template for quiz
{% extends "quiz_app/base.html" %}
{% block content %}
<article class="quiz-detail">
<h1>{{ object.title }}</h1>
<h2>{{ object.question_amount }} Questions</h2>
<a class="btn" href="{% url 'quiz-assessment' %}">Start Quiz</a>
</article>
{% endblock content %}
#assessment template
{% extends "quiz_app/base.html" %}
{% block content %}
<h2>Assessment</h2>
<h2>Title is {{ quiz.title }}</h2>
{% endblock content %}
Then you should make another view for url quiz-assessment and pass the quiz pk as you did above in your assessment view.
def quiz_assessment(request,pk):
quiz = Quiz.objects.get (pk=pk)
return render (request,'assessment_template', {'quiz':quiz}
And in your url,pass the quiz id like this:
path ('<int:pk>/quiz/assessment /',views.quiz_assessment,name='quiz_assessment')
And in your template you can give url like this:
< a class="btn" href="{% url 'quiz_assessment' object.pk %}>
As suggested in the comments by #Robin Zigmond, you can do like this.
#assessement view
def assessment(request, qid):
context = {
'quiz':Quiz.objects.get(id=qid),
}
return render(request, 'quiz_app/assessment.html', context)
In the HTML file
#detailview template for quiz
{% extends "quiz_app/base.html" %}
{% block content %}
<article class="quiz-detail">
<h1>{{ object.title }}</h1>
<h2>{{ object.question_amount }} Questions</h2>
<a class="btn" href="{% url 'quiz-assessment' qid=object.id %}">Start Quiz</a>
</article>
{% endblock content %}
and in your urls.py change as:
path('quiz_asswssment/?P<int:qid>/', views.assessment, name="quiz_assessment")
Besides, what SammyJ has suggested, You can use the django sessions library or the django cache framework. You can temporarily store the information you need for the next view and access it whenever you want to.
In what Sammy J had suggested, you will always to have make sure that the queryset is passed in the context, otherwise it will not be rendered.
def assesment(self, request, id):
q = Quiz.objects.get(pk=id)
request.session["someData"] = q.name
request.session["qAmount] = q.amount
In your template file
<p>The title is : {{request.session.title}} and the amount is {{request.session.qamount}}
Note: Django sessions do not allow you to set a queryset as a session record, for that, you can use Django Cache framework.
Example
from django.core.cache import cache
cache.set('quiz', q)
getting cache -> cache.get('quiz')
Sessions framework docs : https://docs.djangoproject.com/en/2.2/topics/http/sessions/
Cache framework docs: https://docs.djangoproject.com/en/2.2/topics/cache/

In Django, how to implement boilerplate HTML variables with Dynamic URLs used in templates and DB objects?

In Django, in my DB I've created string variables containing boilerplate HTML with dynamic URLs, and I can't quite get them to work in my templates.
I'm using render_as_template (https://github.com/danielrozenberg/django-render-as-template/blob/master/render_as_template/templatetags/render_as_template.py) so the dynamic URLs work. I tried custom template tags, but when I use those with render_as_template, it fails to load.
I then tried a custom context processor. I created two functions in the context processor, one for hyperlinks, and one for tooltips. I got the tooltips processor to work, but I can only reference them in the template via their number in the auto-generated dict from the queryset.
I did the same with the hyperlink processor, then tried modifying it to use string keys instead of integers, but it doesn't load all of the field. I must be missing something.
custom_tags.py
from django import template
register = template.Library()
#register.simple_tag
def rdo_hyper():
value = Boilerplate.objects.filter(name='RDO').values_list('hyperlink',flat=True)
return value[0]
# It's only going to return one field.
# Expected output: <a href="{% url 'guides:rdo' %}" target=”_blank” rel=”noopener noreferrer”>Foobar</a>
# tried a non-DB version, just in case
#register.simple_tag
def rdo_hyper2():
value = "<a href=\"{% url \'guides:rdo\' %}\" target=\”_blank\” rel=\”noopener noreferrer\”>Foobar</a>"
return value
# Expected output: <a href="{% url 'guides:rdo' %}" target=”_blank” rel=”noopener noreferrer”>Foobar</a>
custom_context.py
from myapp.apps.wizard.models import Boilerplate
def boilerplate_hyperlink_processor(request):
boilerplate_hyper = {
"foo": Boilerplate.objects.filter(name='Aftermarket').values_list('hyperlink',flat=True),
"bar": Boilerplate.objects.filter(name='Sights').values_list('hyperlink',flat=True)
}
return {'boilerplate_hyper': boilerplate_hyper}
# Expected output of boilerplate_hyper.foo:
#<a href="{% url 'guides:aftermarket' %}" target=”_blank” rel=”noopener noreferrer”>Aftermarket Support</a>
#
# Expected output of boilerplate_hyper.bar:
# <a href="{% url 'guides:sights' %}" target=”_blank” rel=”noopener noreferrer”>Sights</a>
def boilerplate_tooltip_processor(request):
boilerplate_tooltip = Boilerplate.objects.values_list('tooltip',flat=True)
return {'boilerplate_tooltip': boilerplate_tooltip}
# Expected output of boilerplate_tooltip.0:
#<sup></sup>
template.html
{% load static %}
{% load custom_tags %}
{% rdo_hyper as rdo_hyper %}
{% rdo_hyper2 as rdo_hyper2 %}
{% load render_as_template %}
...
<html>
{% autoescape off %}
1. {% rdo_hyper %}
2. {{ rdo_hyper }}
3. {% rdo_hyper2 %}
4. {{ rdo_hyper2 }}
5. {% render_as_template rdo_hyper %}
6. {{ boilerplate_hyper.foo }}
7. {% render_as_template boilerplate_hyper.foo %}
8. {% render_as_template boilerplate_tooltip.0 %}
{% endautoescape %}
{# The hyperlink value is:
<a href="{% url 'guides:aftermarket' %}" target=”_blank” rel=”noopener noreferrer”>
Aftermarket Support</a> #}
</html>
In template.html, the following occurs:
Renders, but the dynamic URL fails.
Doesn't render the variable at all. Otherwise page loads fine.
Renders, but the dynamic URL fails.
Doesn't render the variable at all. Otherwise page loads fine.
Doesn't render the variable at all. Otherwise page loads fine.
Only renders "Aftermarket Support']>" instead of the full hyperlink field from the DB.
Throws this error:
TemplateSyntaxError:
In template <unknown source>, error at line 1.
Could not parse the remainder: '\'guides:aftermarket\'' from '\'guides:aftermarket\''
1 <QuerySet ['<a href="{% url \'guides:aftermarket\' %}" target=”_blank” rel=”noopener noreferrer”>Aftermarket Support</a>']>
Works fine.
It's great that {% render_as_template boilerplate_tooltip.0 %} works, but I would much rather reference variables in templates through a string key. After all, the ethos of Django's templating language is that its templates can be read and written by non-programmers. Any ideas?
I went back to trying custom tags and this seems to work:
custom_tags.py
#register.simple_tag(takes_context=True)
def rdo_hyper2(context):
value = "<a href=\"{% url \'guides:rdo\' %}\" target=\”_blank\” rel=\”noopener noreferrer\”>Foobar</a>"
rendered = context.template.engine.from_string(value).render(context)
return rendered
template.html
{% load custom_tags %}
...
{% rdo_hyper2 %}
When including {% rdo_hyper2 %} or other custom tags inside a DB field, I also have to use {% load custom_tags %} at the top of that field every time or else it throws:
Invalid block tag on line 12: 'rdo_hyper2'. Did you forget to register or load this tag?
Hopefully that's not resource intensive!

How to move flask wtform from extending view to extended view and instantiate forms for all views?

To make my question clearer, here is a little application that takes a sentence input and outputs that sentence twice.
I have base.html:
<html>
<head>
<title> My site </title>
<body>
{% block content %}{% endblock %}
</body>
</html>
and index.html:
{% extends "base.html" %}
{% block content %}
{{ s }}
<form action="" method="post" name="blah">
{{ form.hidden_tag() }}
{{ form.sentence(size=80) }}
<input type="submit" value="Doubler"></p>
</form>
{% endblock %}
Here is part of views.py:
from forms import DoublerForm
#app.route('/index')
def index():
form = DoublerForm()
if form.validate_on_submit():
s = form.sentence.data
return render_template('index.html', form=form, s=str(s) + str(s))
return render_template('index.html', form=form, s="")
And here is forms.py, without all the imports:
class DoublerForm(Form):
sentence = StringField(u'Text')
This seems to work OK. But what I would like is to have my input form in the base.html template so that this shows up on all pages that extend it, not just the index page. How can I move the form to the base.html and instantiate the form for all views that extend base.html?
You can use the flask.g object and flask.before_request.
from flask import Flask, render_template, g
from flask_wtf import Form
from wtforms import StringField
#app.before_request
def get_default_context():
"""
helper function that returns a default context used by render_template
"""
g.doubler_form = DoublerForm()
g.example_string = "example =D"
#app.route('/', methods=["GET", "POST"])
def index():
form = g.get("doubler_form")
if form.validate_on_submit():
s = form.sentence.data
return render_template('index.html', form=form, s=str(s) + str(s))
return render_template('index.html', form=form, s="")
You can also explicitly define a context function
def get_default_context():
"""
helper function that returns a default context used by render_template
"""
context = {}
context["doubler_form"] = form = DoublerForm()
context["example_string"] = "example =D"
return context
and is used like this
#app.route('/faq/', methods=['GET'])
def faq_page():
"""
returns a static page that answers the most common questions found in limbo
"""
context = controllers.get_default_context()
return render_template('faq.html', **context)
Now, you'll have whatever objects you add to the context dictionary available in all templates that unpack the context dictionary.
index.html
{% extends "base.html" %}
{% block content %}
{{ s }}
{% endblock %}
base.html
<html>
<head>
<title> My site </title>
<body>
{% block content %}{% endblock %}
<form action="" method="post" name="blah">
{{ doubler_form.hidden_tag() }}
{{ doubler_form.sentence(size=80) }}
{{ example_string }}
<input type="submit" value="Doubler"></p>
</form>
</body>
</html>

Categories