How to get data from flask database using javascript? - flask

I want to display users in select box from flask database but the select is handled by javascript. How do I pass information to javascript?

You can do this using Jinja. The list of users from the database can be passed by rendering the template as follows. In the given example, I passed a list of keys that is obtained from a separate function. It was iterated over in index.html with the option tag using the Jinja syntax.
App.py
#app.route('/', methods=['POST','GET'])
def index():
return render_template('index.html', keyset = keys)
index.html
<body>
{% block body %}
<select name="example" id="names">
{% for key in keyset %}
<option value="{{key}}">{{key}}</option>
{% endfor %}
</select>
{% endfor %}
</body>
Let me know if this helps!

Related

Access a variable from template tag that takes arguments

I have a template tags that takes ID on template and returns a list, I want to check the list if the variable is available and make checkbox input checked.
`_checkbox.html`
{% load get_previous_response %}
{% user_response question.id %} {# this returns a list of ids #}
So I want to do something like this
<input type="checkbox" {% if option.id in user_response %}checked{% endif %}>
problem is the above won't work, I tried django templatetag `with template context`
My main goal is I want to access the list returned by {% user_response question.id %}.
EDIT
My custom templatetag.
get_previous_response.py
from django import template
from survey.models import Question
register = template.Library()
#register.simple_tag(takes_context=True)
def user_response(context, question_id):
question = Question.objects.filter(id=question_id).first()
user = context['request'].user
response = question.get_simple_answer(user)
return response
I think there are a couple of ways to achieve this.
From the django docs on simple tags:
It’s possible to store the tag results in a template variable rather than directly outputting it. This is done by using the as argument followed by the variable name. Doing so enables you to output the content yourself where you see fit
In your case, that would be something like this:
{% user_response question.id as user_responses %}
Another approach would be to add the list in the request context, and access it from there. The downside is that this will be available in all your templates(which I guess is not what you want).
See this SO answer on how to do that.
Implement a Templatetag class and set the context in the render method. Here is the Django doc for how to do that: https://docs.djangoproject.com/en/3.2/howto/custom-template-tags/#setting-a-variable-in-the-context
You can try:
{% if option.id in user_response %}
<input type="checkbox" checked>
{% else %}
<input type="checkbox">
{% endif %}

How to save a django "with" template tag value and reuse it in other templates?

I have a template tag that reads values from the URL. For example
the searched term is cancer. After searching, the next page that appears would have a with Searched terms: Cancer. And I would like the value cancer to appear in all of my webpages until the user does a new search.
Pages I have work this way:
Search.html > display.html > explore.html
Search.html is where the user enters what they want to search for.
I have a searchedterms.html which is included into all 3 templates and contains the Javascript code to read from the URL.
By using a JavaScript code, I managed to display searched terms: cancer in display.html but in explore.html the value is empty. I want to be able to save "cancer" to the tag and use it in other templates.
?conditions=cancer
in search.html:
<input required="" type="text" name="conditions">
in display.html:
{% with searched_terms='searchedterms.html' %}
{% include searched_terms %}
{% endwith %}
in explore.html:
{% with searched_terms='searchedterms.html' %}
{% include searched_terms %}
{% endwith %}
in searchedterms.html:
<div id="searched" class="container"></div>
<script type="text/javascript">
var urlParams = new URLSearchParams(window.location.search);
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.search);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
};
var condition = getUrlParameter('conditions');
document.getElementById("searched").innerHTML = "Searched Terms: " + condition;
</script>
Actual results: Cancer appears in display.html but not in explore.html. When display.html is refreshed "cancer" also disappears.
Desired Results: Cancer appears in display.html and explore.html until the user starts a new search.
I think Django Inclusion tag is what you are looking for.
Register your tag in templatetags as below:
#register.inclusion_tag('searchedterms.html')
def searched_terms(query):
return {
'query': query
}
and now in your searchedterms.html file:
<div>
your searched query is: {{ query }} {# display your query here #}
</div>
For Class Based View:
in your Search.html > display.html > explore.html files:
{% load tags %}
{% block content %}
{% searched_terms view.kwargs.conditions %} {# here you pass your kwargs from url #}
<div>some of your existing code. </div>
{% endblock %}
how view.kwargs.conditions work is explained here Access kwargs from a URL in a Django template
For Functional View:
If you want url kwargs in your template from functional views then you can get url kwargs in view and pass it as context data:
def search_view(request, **kwargs):
"""
your existing codes
"""
context = {'conditions': kwargs.get('conditions')}
return render(request, 'search.html', context)
Using request in the template to access from url:
If you want to access the data from url in template then you can also use request.GET or request.POST based on how you want to access the data as in your Search.html > display.html > explore.html files:
{% load tags %}
{% block content %}
{% searched_terms request.GET.conditions %} {# here you access data from url #}
<div>some of your existing code. </div>
{% endblock %}
you can look for django documentation HttpRequest objects for what you can have access with request.

Django select 2 multiple select slow load

I'm a beginner and I've been playing around with the multiple select option of select2.js. In a historical school database we have over 300k student_id's. I can get the select2 option to work, but it's extremely slow and takes forever to load. I've seen other pages with select 2 load massive amounts of data and work fine.
I'm using the following to javascript to load select2.
$(document).ready(function () {
$('.js-example-basic-multiple').select2();
});
In Django i'm loading the data in my template with:
<script src= "{% static '/search/user_select2.js' %}" type="text/javascript"></script>
<div class="col"><h4 style="margin-top: 0"><strong>Student ID List</strong></h4><select data-placeholder="Choose a list of 3-4 User ids..." class="js-example-basic-multiple" value = "{{ userid }}" style="width: 1110px" required>
{% for user in userid %}
<option value="{{ user }}"> {{ user }}</option>
{% endfor %}
</select>
userid is defined with the following arg in my view:
def multisearch(request):
userid = STudent.objects.filter(student_status_id = 1).values('studentid')
print(userid)
args = {'userid':userid}
return render(request, 'multisearch.html',args)
It takes a long time to load be cause you preload all options of your select2 input. I would suggest you to use select2 through django-autocomplete-light to avoid this issue. It will provide you tools to setup an autocomplete system and load matching options while typing text on your select2 input. Moreover, results paginated so that they are loaded as you scroll the select2 dropdown.
Basically you will have an autocomplete view:
from dal import autocomplete
from your_app.models import Student
class Status1StudentsAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
qs = Student.objects.filter(student_status_id=1)
if self.q: # self.q is the user-typed query
qs = qs.filter(name__istartswith=self.q)
return qs
That, of course, needs to be routed:
from your_app.views import Status1StudentsAutocomplete
urlpatterns = [
url(
r'^autocomplete/students/status-1/$',
Status1StudentsAutocomplete.as_view(),
name='students_status1_autocomplete',
),
]
Then use an autocomplete widget for your field:
from dal import autocomplete
from django import forms
class SomeForm(forms.Form):
student = forms.ModelChoiceField(
queryset=Student.objects.filter(student_status_id=1),
widget=autocomplete.ModelSelect2(url='student_status1_autocomplete')
)
Finally just display your form as you usually would and don't forget to include the custom css/js with {{ form.media }}.
{% extend "your_layout.html" %}
{% block extrahead %} {# assuming extrahead block is within the <head> element #}
{{ block.super }}
{{ form.media }}
{% endblock %}
{% block content %} {# assuming you have a content block within your <body> element #}
<form method="POST">
{% csrf_token %}
{{ form }}
<button type="submit">Go!</button>
</form>
{% endblock %}

Flask Admin Custom View

I am pretty new to Flask/Flask-Admin.
I have followed the tutorial on flask admin and managed to get the admin panel working but slightly lost on how to get the below things implemented.
https://github.com/flask-admin/flask-admin/tree/master/examples/auth
When logged in as a normal user I can only see "home" page.
How can I expose other views to "normal user" and restrict actions such as read only etc.
I have created a "baseview" which is not associated with any other models as below:
class SitesView(MyBaseView):
#expose('/')
def index(self):
return self.render('views/testviews.html')
admin.add_view(SitesView(name='Test views', endpoint='test views'))
and html as below:
{% extends 'admin/master.html' %}
{% block body %}
{{ super() }}
{% if current_user.has_role('view1') %}
Site1
{% endif %}
{% if current_user.has_role('view2') %}
<a>Site2</a>
{% endif %}
{% if current_user.has_role('view3') %}
<a>Site3</a>
{% endif %}
{% if current_user.has_role('view4') %}
<a>Site4</a>
{% endif %}
{% endblock %}
This gives me a new tab with different views with works as expected.
What I am trying to achieve here is when user click the Site1 link they go to Site1 page within flask-admin interface but I am not sure how to do that. I could create a new route for this but the problem is I can't(don't know how to) extend flask admin template.
For example this works but it redirect the page outside flask-admin template:
#app.route('/views/')
def views():
return render_template('views/views1.html')
and modified the templates>admin>index.html page with below:
<ul class="lead text-center list-group">
{% if current_user.has_role('view1') %}
<li class="list-group-item">View1</li>
{% endif %}
{% if current_user.has_role('view2') %}
<li class="list-group-item">View2</li>
{% endif %}
{% if current_user.has_role('view3') %}
<li class="list-group-item">View3</li>
{% endif %}
{% if current_user.has_role('view4') %}
<li class="list-group-item">View4</li>
{% endif %}
</ul
I want to build the whole web site using flask admin so that I can keep user experience consistence. Am I doing this the wrong way?
Thanks for your time.
Please do let me know if you want me to provide more information on this issue.
Kind Regards.
So after going through documentations and tutorials I have found the solution to my issue.
For my first question:
When logged in as a normal user I can only see "home" page. How can I
expose other views to "normal user" and restrict actions such as read
only etc.
We can do this by overwriting our view functions is_accessible method as below:
def is_accessible(self):
if not current_user.is_active or not current_user.is_authenticated:
return False
if current_user.has_role('superuser') or current_user.has_role('user') or current_user.has_role('view1'):
return True
return False
For my second question we just need to give the endpoint as for our BaseView as below:
class MyView(BaseView):
#expose('/')
def index(self):
return self.render('views.html')
admin.add_view(MyView(name='Custom Views', endpoint='customviews'))
And then in your jinja template you need to call it:
href="{{ url_for('customviews.index') }}
Just one thing to note, doing this:
current_user.has_role('superuser') or current_user.has_role('user') or current_user.has_role('view1')
could get quite messy if we have so many roles, not sure how we would approach this but hoping this will help someone.
Thanks all.
I know this is an old question, but for the following code
current_user.has_role('superuser') or current_user.has_role('user') or current_user.has_role('view1')
What I like to do is having a hybrid_property (available on both Peewee and SQLAlchemy) inside my User class that consolidates these properties. So it'd look something like this:
#hybrid_property
def user_has_administrative_rights(self):
return self.has_role('superuser') or self.has_role('user')

django-cms "summary view" aggregating content from multiple pages

Django==1.5.1
django-cms==2.4.1
I'd like to make something like a summary view from all the child pages of a selected page in django-cms, pulling out title, truncated content etc with a more... link for each listed child. I've managed to get titles and paths just fine, but im struggling to get content from the placeholders.
I have a templatetag like this:
from cms.models import Page
from cms.utils.page_resolver import get_page_from_path
from django import template
register = template.Library()
#register.inclusion_tag('news_summary_item.html')
def get_news_items():
news_root = get_page_from_path('news')
newsitems = news_root.children.filter(published=True)
return {'newsitems':newsitems}
and here is the template its using:
{% load cms_tags menu_tags %}
<ul>
{% for item in newsitems %}
<li>{{ item.get_title }}
{% for placeholder in item.placeholders.all %}
# {% show_placeholder placeholder.slot item current_language %} #
{% endfor %}
</li>
{% endfor %}
</ul>
Can anyone help with getting the placeholder content here? Ideally, id like to be able to pass it through truncatewords_html to just get a summary, but open to other ways to get the same effect.
Thanks for any tips/pointers!
I had to index CMS content in one project and I get the content of each placeholder, and the content of a placeholder is stored in the plugins attached to it
How te get the content of a CMSPlugin in a view?
from cms.models import CMSPlugin
plugin = CMSPlugin.objects.filter(plugin_type='TextPlugin')[0] # Get first text plugin
# This return the body/content of the plugin:
plugin_content = plugin.get_plugin_instance()[0].body
If you would like to manage other plugins like PicturePlugin you could get the "alt" text like:
plugin_picture_content = plugin.get_plugin_instance()[0].alt
How to get the content of CMSPlugin in a template?
# plugin_object containing a CMSPlugin
{{plugin_object.get_plugin_instance.0.body}}
I supose when you want to get the content, we are talking about TextPlugin, you have to be carefull here because only the plugin type TextPlugin has the attribute body, the PicturePlugin has the attribute alt and the LinkPlugin has the attribute href etc...
Solution adapted for your problem
You are doing a loop over placeholders, so you need to get all the plugins for each placeholder and get the content of each plugin, because the content of the placeholders as I mentioned before are stored in the plugins attached to it (TextPlugin, PicturePlugin, LinkPlugin...).
... ... ...
{% for placeholder in item.placeholders.all %} # Loop over placeholders
{% for plugin in placeholder.get_plugin_list %} # Get plugins for each placeholder
{{plugin.get_plugin_instance.0.body|striptags}}
{% endfor %}
{% endfor %}
... ... ...
And to ensure that you only show the content of TextPlugin and not from other plugins you could do:
... ... ...
{% for placeholder in item.placeholders.all %} # Loop over placeholders
{% for plugin in placeholder.get_plugin_list %} # Get plugins for each placeholder
{% if 'TextPlugin' in plugin.plugin_type %}
{{plugin.get_plugin_instance.0.body|striptags}}
{% endif %}
{% endfor %}
{% endfor %}
... ... ...