Show select field based on some other select option in flask - python-3.x

I am creating a flask form where I need to show a dropdown based on some other dropdown select field in Flask. I was able to do it with HTML, but finding it difficult to do the same in Flask form.
routes.py :
class RegistrationForm(FlaskForm):
category = SelectField('Category', choices = [('Clothes', 'Clothes'), ('Watch', 'Watch')])
subcategory = SelectField('Sub Category', choices = [('USPA', 'USPA'), ('LEE', 'LEE'), ('FOSSIL', 'FOSSIL'), ('TITAN', 'TITAN')])
submit = SubmitField('Register')
HTML :
<form action="" method="post">
{{ form.hidden_tag() }}
<p>
<p>
{{ form.category.label }}<br>
{{ form.category }}<br>
{% for error in form.category.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.subcategory.label }}<br>
{{ form.subcategory }}<br>
{% for error in form.subcategory.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>{{ form.submit() }}</p>
</form>
I want mapping link this :
Clothes : USPA, LEE
Watch : FOSSIL, TITAN
But in the form I am getting all the options. I need subcategory based on selected category.

Since this is dynamic functionality on the client side you will need to use Javascript.
Personally I think the easiest way to do this is pre configure your flask form statically:
class RegistrationForm(FlaskForm):
category = SelectField('Category', choices = [('Clothes', 'Clothes'), ('Watch', 'Watch')])
subcategory_clothes = SelectField('Sub Category', choices = [('USPA', 'USPA'), ('LEE', 'LEE')], validators=[Optional()])
subcategory_watches = SelectField('Sub Category', choices = [('Titan', 'Titan'), ('Fossil', 'Fossil')], validators=[Optional()])
submit = SubmitField('Register')
And then display either one or the other combo boxes dependent upon the value of the initial combo box, using Javascript if statement. You will need a javascript event hook to detect changes to category, or use a framework such as Vue.js.
An example of javascript hook is here https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onchange
You can add a javascript function, in HTML, to show either box depending on the value of the other checkbox:
<script>
function myFunction() {
let box_value = document.getElementById("category").value;
if (box_value === "Clothes") {
document.getElementById("subcategory_clothes").style.display = "initial"
document.getElementById("subcategory_watches").style.display = "none"
} else {
document.getElementById("subcategory_clothes").style.display = "none"
document.getElementById("subcategory_watches").style.display = "initial"
}
}
</script>
And you can add a render_keyword argument in Python so that it populates the event hook in HTML:
category = SelectField('Category', choices = [('Clothes', 'Clothes'), ('Watch', 'Watch')], render_kw={'onchange': "myFunction()"})

Related

How to check routes on template?

Does anyone know how to check if a template is being accessed through a url route with the django template language?
Here is my situation: There's this template article.html, that shows all posts of a blog when accessed through blog-home url route, and that also shows only posts of a given user through user-posts url route.
This template works like that because what defines which posts will be shown are the classes in views.py.
That being said, here is what I tried to do: (I know its wrong)
{% if url == 'user-posts' %}
"Some HTML h1 tag I want do be shown only when this template is accessed via 'user-posts' url"
{% endif %}
How would be the correct way, if there's any, to write this if statement?
When Django matches a url pattern a ResolverMatch object is created and made available on the request object at request.resolver_match. This ResolverMatch object can be queried in your template to acheive what you want, the url_name attribute is the name of the url pattern that was matched
{% if request.resolver_match.url_name == 'user-posts' %}
You should create a custom templatetag,
my_app/templatetags/utils.py
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def is_active_view(context, *view_names):
request = context.get('request')
for view_name in view_names:
if getattr(request.resolver_match, 'view_name', False) and request.resolver_match.view_name == view_name:
return True
return ''
And use it in your template this way, assuming blog-home is the url name you gave to your url :
blog-home.html
{% load utils %}
{% is_active_view 'blog-home' as display_blog_home_section %}
{% if display_blog_home_section %}
<!-- Your code -->
{% endif %}
NB : this template tag can check after multiple view names at once and support namespaced url :
{% is_active_view 'front:blog-home' 'front:blog-categories' as display %}
Here is a more optimized version of this if you are using boostrap and trying to make the menu options "active" when you are on that URL
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def is_active_tab(context, *view_names):
request = context.get('request')
for view_name in view_names:
if getattr(request.resolver_match, 'view_name', '') == view_name:
return 'active'
return ''
And you use it like
<li class="nav-item {% is_active_tab 'games:list' %}">
<a class="nav-link" href="{% url 'games:list' %}">
{% translate "My Quizzes" %}
</a>
</li>
<li class="nav-item {% is_active_tab 'games:create' %}">
<a class="nav-link" href="{% url 'games:create' %}">
{% translate "New Game" %}
</a>
</li>
It adds an extra active classname to the class of the element if any of the view_names match the current view name. Makes the template writing much cleaner

Translate data from API in in template with an an other API

im doing a package tracker with PHP / TWIG , and would like to translate results in an other language, so i have a google translate APi
in my twig file i have this :
{% for item in item.origin_info.trackinfo %}
<div class="status-{{item.checkpoint_status}}">
<p> {{item.StatusDescription}}. </p>
<hr/>
{% endfor %}
And i would like to translate each {{ item.StatusDescription }}. Could you tell me how to do ?
my function to translate is :
function translation($str){
$url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=fr&dt=t&q=" . $str;
$result = file_get_contents($url);
$data = json_decode($result);
$traduction = $data[0][0][0];
$lang = $data[2];
return $traduction;
}
You could register a custom filter into twig which allows you to call global functions.
$twig = new \Twig\Environment($loader);
$twig->addFilter(new \Twig\TwigFilter('translate', 'translation'));
First parameter translate is what the filter will be called in twig, the second is your global function translation. You now can use this filter in any template, e.g.
{% for item in item.origin_info.trackinfo %}
<div class="status-{{item.checkpoint_status}}">
<p> {{ item.StatusDescription | translate }}. </p>
<hr/>
</div>
{% endfor %}
If you need more than one extra function, filter, test, ... you are better off with creating an extension. See documentation for more information on this.

drupal 8 twig: Get the fields from a reference entity (content type) in a Paragraph field

I have a paragraph field that is a reference entity to the Customer Testimonial content type. A content editor can add the customer-testimonial paragraph and type the name of the testimonial. This will then display the text on the website.
I have made a paragraph--c15a-customer-testimonial.html.twig template file with the following code.
{% set c15a = { 'title': content.field_testimonial.entity.field_testimonial_titel } %}
<div class="component c15a">
<div>
<div>Testimonial title</div>
<h2>{{ c15a.title }}</h2>
</div>
</div>
Of course, this prints nothing. How can I get the fields from the content type I'm referencing in my paragraph?
Thx,
I'm not 100% certain, but can you try this:
{% set c15a = { 'title': {{ content.field_testimonial.entity.field_testimonial_titel }} } %}
Adding the double brackets around the variable passed in.

Simple Pyramid app: using query params for routing to edit page

I am trying to make a simple Pyramid app, and having a hell of a time figuring out what part of the syntax I'm missing. What's happening is I have an edit page for my model, and I can not figure out how to pass in the id of the entry I'm editing.
My view reads like this:
#view_config(route_name='action', match_param='action=edit', renderer='string')
def update(request):
this_id = request.matchdict.get('id', -1)
entry = Entry.by_id(this_id)
if not entry:
return HTTPNotFound()
form = EntryUpdateForm(request.POST, entry)
if request.method == 'POST' and form.validate():
form.populate_obj(entry)
return HTTPFound(location=request.route_url('blog', id=entry.id, slug=entry.slug))
return {'form': form, 'action': request.matchdict.get('action')}
I have created an edit template, it looks like this, and is working for the create page, which uses a different model:
{% extends "templates/layout.jinja2" %}
{% block body %}
<h2>Create a Journal Entry</h2>
<form action="" method="POST">
{% for field in form %}
{% if field.errors %}
<ul>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<p>{{ field.label }}: {{ field }}</p>
{% endfor %}
<p><input type="submit" name="submit" value="Submit" /></p>
</form>
{% endblock %}
And the link I have made to the template looks like:
Edit Entry
Which yields the url http://0.0.0.0:6543/journal/edit?id=1. This is new and weird to me, because I'm used to Rails, where the url would look like http://0.0.0.0:6543/journal/1/edit but poking around and reading the Pyramid blogr tutorial, this seems like how Pyramid likes to have routes. Unfortunately, it still gives me a 404. It seems like I am successful passing the id of the entry into a query string, but somehow I am not telling the edit page to be at that location.
Thanks for any help you can give.
I can't see where the problem is as this minimal example works, if you navigate your browser to localhost:8080/journal/edit?id=723
#!/usr/bin/env python
from pyramid.response import Response
from pyramid.view import view_config
from pyramid.config import Configurator
from waitress import serve
#view_config(route_name="root", renderer="string")
def root_view(request):
return "root_view", request.params
#view_config(route_name='action', match_param='action=edit', renderer="string")
def action_view(request):
return "action_view", request.params
if __name__ == '__main__':
config = Configurator()
config.add_route('root', '')
config.add_route('action', '/journal/{action}')
config.scan()
app = config.make_wsgi_app()
serve(app)
Maybe you have some other problem with your routes. Can you paste them here all? Are you sure you do not have another function named update in your view?
Aside from that, you are completely free to build your routes as you wish with Pyramid.
config.add_route('action2', '/different/edit/{id}')
config.add_route('action3', '/someother/{id}/edit')
I personally would rather use one of the schemes above than the match_param predicate...

Flashdata not render in view

im try print an alert report before a submit form.
The constroller check that entity was valid and inform the result:
$estado = Array();
if(count($errors) > 0){
$estado['alert'] = 'alert-error';
$estado['message'] = $errors->get(0);
}else{
$estado['alert'] = 'alert-success';
$estado['message'] = "Usuario creado correctamente";
}
$this->getRequest()->getSession()->getFlashBag()->add('status',$estado);
return $this->redirect($this->generateUrl('alta_usuario'));
So, in the view:
{% if app.session.flashbag.has('status') %}
<div class="alert {{ app.session.get('status').alert }}">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ app.session.get('status').message }}
</div>
{% endif %}
But Symfony fails with the next message:
Impossible to access an attribute ("alert") on a NULL variable ("")
In the profiler the Flashdata is:
status : [{"alert":"alert-error","message":{}}]
Two questions:
1) Why "message" is null ? the entity has an error and $errors->get(0) should be get the first error ?
2) Why can't access the $estado values from the view ?.
Any ideas ?.
This question is much similar as below link.
You can find the answer at
Am I using the Symfony flash variables the wrong way?

Resources