How to Connect JQuery-UI Autocomplete Widget to Django-Dajax? - django

I have a Django app for which I am trying to build an autocomplete UI for making selections. As the user types into a text box and the the app should make search suggestions based on values retrieved from the database. I want to use Dajax/Dajaxice to handle the ajax and the jquery-ui autocomplete widget for the UI template. Can someone please explain how to get the jquery-ui autocomplete widget to call my dajax function via the autocomplete source attribute (or any other better way)?
My code is a combination of this dajax example and this jquery-ui autocomplete example.
my_app/ajax.py:
from my_app.models import MyModel
from dajax.core import Dajax
from dajaxice.decorators import dajaxice_register
from django.utils import simplejson
#dajaxice_register
def auto_filter_selections(request, symbol):
dajax = Dajax()
result = MyModel.objects.filter(symbol__startswith = symbol)
dajax.assign('#id_symbol', 'innerHTML', str(result))
return dajax.json()
template: my_app_ui.html
<head>
....
<script type="text/javascript" src="{{STATIC_URL}}jquery/jquery-1.7.2.js"></script>
<script type="text/javascript" src="{{STATIC_URL}}dajax/jquery.dajax.core.js"></script>
<script type="text/javascript" src="{{STATIC_URL}}/jquery/jquery-ui-1.10.4.custom/js/jquery-ui-1.10.4.custom.js"></script>
....
<script>
$(function() {
$("#id_symbol").autocomplete({
source: "Dajaxice.ui.auto_filter_symbols(Dajax.process,'symbol':$('#id_symbol').serialize(true)});",
minLength: 1 //We want to search for even one character
});
});
</script>
....
</head>
<body>
....
<div class="ui-widget">
<label for="id_symbol">Symbol: </label>
<input id="id_symbol">
</div>
....
</body>
If you notice above, I am using jquery-1.7.2 and jquery-ui-1.10.4. This is because the dajax documentation says it is compatible with jquery-1.7.2. Not sure if I can use a newer jquery version.
I am not sure how to get the template's javascript to call my dajax function. the jquery-ui documentation for .autocomplete says to use its source attribute but does not give a very good example. Can anyone tell me if the above is correct?
Once the dajax view function retrieves suggestions from the DB, how do I populate the .autocomplete text box with it?
I've done quite a bit of research over the past few days but there are few examples of Django-Dajax-JQueryUI applications out there.

After considerably more research and piecing various clues together I finally found the key to getting the JQuery-UI autocomplete widget to work with Dajax/Dajaxice and Django.
Synopsis:
Initialize JQuery-UI .autocomplete's source option with a separate javascript (JQuery) setter function
Connect .autocomplete widget's source option to server-side function with a Dajaxice command via a third javascript function.
Explanation:
Firstly, it is important to remember that Dajaxice provides the ajax communication channel by which your client-side javascript and the server side code transact, whereas Dajax provides a convenient way of generating the javascript (JSON) code that will perform the desired function in the client browser without having to write any javascript.
Since JQuery-UI provides us with the javascript widget (in the form of jquery) to perform our desired function (.autocomplete), we do not need Dajax and will not, according to my findings, have any success with it in this application. We ONLY need Dajaxice in order to connect the client side javascript (.autocomplete) to our server side function that does the searching and returns results to suggest to the user.
Below is my revised code that I have gotten working. Note that I have only tested it on a development platform thus far.
my_autocomplete_search_template.html with extraneous code removed:
<head>
....
<script type="text/javascript" src="{{STATIC_URL}}jquery/jquery-1.7.2.js"></script>
<script type="text/javascript" src="{{STATIC_URL}}dajax/jquery.dajax.core.js"></script>
<script type="text/javascript" src="{{STATIC_URL}}/jquery/jquery-ui-1.10.4.custom/js/jquery-ui-1.10.4.custom.js"></script>
....
<script>
//Initialize the source option of .autocomplete widget during page load
//See: http://api.jqueryui.com/autocomplete/#method-option setter example code
var local_source = ["Abc",] //Dummy string for initialization only; temporary value
$("#search_box").autocomplete("option", "source", local_source)
</script>
<script>
//.autocomplete widget is Dajaxice callback function
// *data* comes from server-side function
function search_result(data) {
$("#search_box").autocomplete({
source: data,
});
}
</script>
<script>
//This function called by user <input> tag and calls the server-side function via Dajaxice command
function dajax_filter_search_term() {
Dajaxice.my_app.auto_filter_search_term(search_result,'search_term':$('#search_box').val()});
// | | | ----------------------
// | | | |
// server-side .autcomplete serverside user-typed
// function callback func. func. argument value to search
}
</script>
....
</head>
<body>
....
<div class="ui-widget">
<label for="search_box">Search Term: </label>
<input type="text" name="search" id="search_box" onkeyup="dajax_filter_search_term()" />
</div>
....
</body>
my_app/ajax.py
from dajaxice.decorators import dajaxice_register
from django.utils import simplejson
from my_app.models import MyModel
#dajaxice_register
def auto_filter_search_term(request, search_term):
# Query DB for suggestions to present to user
q = MyModel.objects.filter(myfield__istartswith=search_term)
data = []
for item in q:
# Format returned queryset data, if needed
data_item = item.field1 + ', ' + item.field2 + ', ' + item.field3
data.append(data_item)
# Return data to callback function *search_result*
return simplejson.dumps(data)
That is it! The key is to initialize the .autocomplete source option first and to only use Dajaxice to communicate with the server-side function.
It is possible to optimize the client-side code further by getting rid of the javascript function dajax_filter_search_term() and including the Dajaxice call in the #search_box input tag like so:
<input type="text" name="search" id="search_box" onkeyup="Dajaxice.ui.auto_filter_search_term(search_result, {'search_term':$('#search_box').val()})" />
References
JQuery-UI API docs: http://api.jqueryui.com/autocomplete/#method-option:
Additional clues here:
Django, JQuery, and autocomplete

Related

How to use a javascript variable inside a Django {% url %} tag?

Im trying to dynamically change the link of a button based on which div a user has currently selected.
I tried to run a quick test with a JS variable in the HTML script tag, but Django isn't reading the variable like a num.
<script type="text/javascript">
const testing = 10
</script>
<a href="{% url 'battlefield:onevsone_trainer_selection' num_trainers=testing %}" class='description__button btn btn__large'>Next ></a>
URL looks like:
path('one-vs-one/trainers/<int:num_trainers>', views.oneVsOne, name='onevsone_trainer_selection')
Not sure exactly why it's not working. When I passed it a string of '10' it worked
Django templates are handled server side by django, which means by the time the client browser has received the HTML, the url function, i.e. {% url 'battlefield:onevsone_trainer_selection' num_trainers=testing %}, will have been processed. Javascript, of course, runs in the browser, and you can't pass a javascript variable to a django function after it has arrived at the client.
If you want to change this clientside (without communicating with the server via ajax or something) you might need to change the href attribute directly. You could do something like:
<a id='changeableUrl' href="{% url 'battlefield:onevsone_trainer_selection' num_trainers=1 %}" class='description__button btn btn__large'>Next ></a>
<script>
//figure out where the URL should be going
const testing = 10
//get the current URL
url = document.getElementById('changeableUrl').getAttribute("href")
///replace the end of the url href with our value
url.replace('/1/', '/'+testing+'/')
///write back to the link attribute
document.getElementById('changeableUrl').setAttribute("href", url)
</script>
What you should understand is that django template engine works server-side, whereas Javascript only does its job on client side.
What happens is that you are asking django to render the following template :
<script type="text/javascript">
const testing = 10
</script>
<a href="one-vs-one/trainers/testing" class='description__button btn btn__large'>Next ></a>
Here, testing is not a javascript variable, it's just plain html content. Moreover, it's not an integer at rendering time, so the regex used internally by django shall not be matched and a rendering error shall be raised.
If you really want to set the url paramater client-side, then I see two solutions :
The first is to build the url manually without using the django url function. :
<a href="" id="to-change" class='description__button btn btn__large'>Next ></a>
<script type="text/javascript">
document.getElementById("to-change").href = "one-vs-one/trainers/" + num_trainer;
</script>
The second solution is the one proposed by SamSparx.
Whatever the solution you choose, you should carefully keep in mind that neither of the two if fully safe. In the first case, you make the code a little bit less maintainable by giving more work if one day you change the url in your urls.py file. In the second one, you expose you to a url that is predefined. If JS is not enabled or if something wrong happens on the browser of your client, it may mean that your link shall be linked to what it should not.

How do I inject a template into another template in Flask [duplicate]

I Want to develop a flask navigation bar like Google Contacts.
I Want to Render a particular HTML page inside the red box (as in the picture) when I click each of the navigation buttons (the green box as in picture) without refreshing the page.
I have already tried using
{% extends "layout.html" %}
As #Klaus D. mentioned in the comments section, what you want to achieve can be done using Javascript only. Maybe your question were
How can I send a request to my server-side (to get or fetch some information) and receive back a response on the client-side without having to refresh the page unlike the POST method usually does?
I will try to address the aforementioned question because that's probably your case.
A potential solution
Use Ajax for this. Build a function that sends a payload with certain information to the server and once you receive back the response you use that data to dynamically modify the part of the web-page you desire to modify.
Let's first build the right context for the problem. Let's assume you want to filter some projects by their category and you let the user decide. That's the idea of AJAX, the user can send and retrieve data from a server asynchronously.
HTML (div to be modified)
<div class="row" id="construction-projects"></div>
Javascript (Client-side)
$.post('/search_pill', {
category: category, // <---- This is the info payload you send to the server.
}).done(function(data){ // <!--- This is a callback that is being called after the server finished with the request.
// Here you dynamically change parts of your content, in this case we modify the construction-projects container.
$('#construction-projects').html(data.result.map(item => `
<div class="col-md-4">
<div class="card card-plain card-blog">
<div class="card-body">
<h6 class="card-category text-info">${category}</h6>
<h4 class="card-title">
${item.title_intro.substring(0, 40)}...
</h4>
<p class="card-description">
${item.description_intro.substring(0, 80)}... <br>
Read More
</p>
</div>
</div>
</div>
`))
}).fail(function(){
console.log('error') // <!---- This is the callback being called if there are Internal Server problems.
});
}
Build a function that will fetch the current page via ajax, but not the whole page, just the div in question from the server. The data will then (again via jQuery) be put inside the same div in question and replace old content with new one.
Flask (Server-side)
''' Ajax path for filtering between project Categories. '''
#bp.route('/search_pill', methods=['POST'])
def search_pill():
category = request.form['category']
current_page = int(request.form['current_page'])
## Search in your database and send back the serialized object.
return jsonify(result = [p.serialize() for p in project_list])
Thank you #CaffeinatedCod3r,#Klaus D and #newbie99 for your answers.
I Figured it out. instead of using Flask we can use Angular JS Routing for navigation.
Here is the example that i referred:
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-route.js"></script>
<head>
<base href="/">
</head>
<body ng-app="myApp">
<p>Main</p>
Banana
Tomato
<p>Click on the links to change the content.</p>
<p>Use the "otherwise" method to define what to display when none of the links are clicked.</p>
<div ng-view></div>
<script>
var app = angular.module("myApp", ["ngRoute"]);
app.config(function($routeProvider, $locationProvider) {
$routeProvider
.when("/banana", {
template : "<h1>Banana</h1><p>Bananas contain around 75% water.</p>"
})
.when("/tomato", {
template : "<h1>Tomato</h1><p>Tomatoes contain around 95% water.</p>"
})
.otherwise({
template : "<h1>Nothing</h1><p>Nothing has been selected</p>"
});
$locationProvider.html5Mode(true);
});
</script>
</body>
</html>
By Using $locationProvider.html5Mode(true) i was able to remove the # from the URL.

Stylized HTML fields in Django admin

I Have TextField to store HTML text. I want to colorize HTML tags. I use TinyMCE but didn't need an HTML editor like WordPress just simple to colorize like IDE, Search a lot but didn't find anything useful, So if you can help I appreciate it.
My field:
I want output like this but changeable:
Using a code editor in Django admin Textarea
The following is implemented with CodeMirror but you can use any other library (Monaco, etc).
Final result:
For all the libraries, we need to add some library specific javascript and stylesheet plus some custom code for integration.
Django has pretty flexible templating to enable this. We can override the entire template or specific blocks. Detailed documentation can be fond here.
To integration CodeMirror, we can override the admin/base.html 's extrahead block. We will include the required js/css, one extra css for theming and some js to find and apply CodeMirror.
Here, I have create a admin/base.html inside my project's configured template directory. This will apply to all the apps and models. There are ways to target an app or model individually - check the office docs.
This works for JSONField data. You will have to tweak a bit to format
html or any other language.
Inspect the page and find id of the textarea you want to target
<!-- tested with Django 3.2.9 -->
{% extends "admin/base.html" %}
{% block extrahead %}
{{ block.super }}
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/codemirror.min.js" crossorigin="anonymous"
referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/codemirror.min.css"
crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/theme/oceanic-next.min.css"
crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/mode/javascript/javascript.min.js"
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
window.addEventListener('load', (event) => {
const target = document.getElementById("id_data");
target.value = JSON.stringify(JSON.parse(target.value), null, ' ');
const config = {
mode: 'javascript',
theme: 'oceanic-next',
lineNumbers: true,
lineWrapping: true
}
const jsonCodeMirror = CodeMirror.fromTextArea(target, config);
jsonCodeMirror.setSize("100%", 600);
});
</script>
{% endblock %}
Multiple textarea inputs can be targeted as well with get element with classname and then looping over the result set and applying the same logic.
For html formatting,
you can use this https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/mode/htmlmixed/htmlmixed.min.js instead of javascript. Delete the json stringify statement. Change mode to htmlmixed.
Don't need to override any template
solved by integrating django-ace field and in this we have support for CSS, python, HTML etc also.
Simply use this in django forms and provide the form in django model admin class
admin file
from appname import forms
#admin.register(models.Table)
class TableModelAdmin(admin.ModelAdmin):
form = forms.TableModelForm
form file
from django import forms
from django_ace import AceWidget
class TableModelForm(forms.ModelForm):
class Meta:
model = models.Table
fields = '__all__'
widgets = {
'columns': AceWidget(
mode='json',
theme='None',
width='1200px',
height='500px',
fontsize='18px',
showprintmargin=False,
),
}

Does vue contain blocks funcionality like in djagno

I'm working on new web project. Previously I was keeping everything in one project (django). This time I decided to split it on two separate projects - backend (django) and frontend vue. I haven't worked with raw vue project so here is my question - Can I use blocks in vue ? My goal is to create one main template with nav bar, footer and the middle div for other views, just like in django blocks. I could import these components in each view but it is not elegant and I bet there must be some other solution.
Depending on your implementation you could use nested routes and something similar to this if routing is handled on the front-end:
<html>
...
<body>
// code outside here
// vue component taken from route
<router-view></router-view>
// more code outside here
</body>
...
</html>
You can find more information about Vue router here
Alternatively, you could have a base component with slots for other parts of your project:
<template>
<div>
<header-component></header-component>
<div>
<nav-component>
<slot name="..."></slot>
</nav-component>
<main>
<slot name="..."></slot>
</main>
</div>
</div>
</template>

how to embed standalone bokeh graphs into django templates

I want to display graphs offered by the bokeh library in my web application via django framework but I don't want to use the bokeh-server executable because it's not the good way. so is that possible? if yes how to do that?
Using the Embedding Bokeh Plots documentation example as suggested by Fabio Pliger, one can do this in Django:
in the views.py file, we put:
from django.shortcuts import render
from bokeh.plotting import figure
from bokeh.resources import CDN
from bokeh.embed import components
def simple_chart(request):
plot = figure()
plot.circle([1,2], [3,4])
script, div = components(plot, CDN)
return render(request, "simple_chart.html", {"the_script": script, "the_div": div})
in the urls.py file we can put :
from myapp.views import simple_chart
...
...
...
url(r'^simple_chart/$', simple_chart, name="simple_chart"),
...
...
in the template file simple_chart.html we'll have :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Experiment with Bokeh</title>
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-0.8.1.min.js"></script>
<link rel="stylesheet" href="http://cdn.bokeh.org/bokeh/release/bokeh-0.8.1.min.css">
</head>
<body>
{{ the_div|safe }}
{{ the_script|safe }}
</body>
</html>
And it works.
You don't need to use bokeh-server to embed bokeh plots. It just means you'll not be using (and probably don't need) the extra features it provides.
In fact you can embed bokeh plots in many ways like generating standalone html, by generating bokeh standalone components that you can then embed in you django app when rendering templates or with the method we call "autoloading" which makes bokeh return a tag that will replace itself with a Bokeh plot. You'll find better details looking at the documentation.
Another good source of inspiration is the embed examples you can find in the repository.
It is also possible to have it work with AJAX requests. Let's say we have a page loaded and would like to show a plot on button click without reloading the whole page. From Django view we return Bokeh script and div in JSON:
from django.http import JsonResponse
from bokeh.plotting import figure
from bokeh.resources import CDN
from bokeh.embed import components
def simple_chart(request):
plot = figure()
plot.circle([1,2], [3,4])
script, div = components(plot, CDN)
return JsonResponse({"script": script, "div": div})
When we get AJAX response in JS (in this example Jquery is used) the div is first appended to the existing page and then the script is appended:
$("button").click(function(){
$.ajax({
url: "/simple_chart",
success: function(result){
var bokeh_data = JSON.parse(result);
$('#bokeh_graph').html(bokeh_data.div);
$("head").append(bokeh_data.script);
}});
});
It must put {{the_script|safe}} inside the head tag
Here's a flask app that uses jquery to interract with a bokeh plot. Check out the templates/ for javascript you can reuse. Also search for bokeh-demos on github.