Integrating typeahead.js with Django apps - javascript

I'm fairly new to Django and am trying to integrate typeahead.js to my Django app. I want to be able to search through the field 'name' in my local sql2lite DB which has around 15,000 entry. The table name is called 'institution'.
My html is able to find typeahead.js and have the following script to run it:
<script type="text/javascript" src="{% static 'js/typeahead/typeahead.jquery.js' %}">
$(document).ready(function() {
$("#InstitutionsSearch").typeahead({
name: 'Institutions',
remote: 'profile/account_names_autocomplete/?q=%QUERY'
What do I need to do with remote to set the search on a field in my DB? I read other threads but it isn't clear to me what remote actually do. Do I have to engage Bloodhound to make this work?
The query is reach my View printing hello0 but no more.
My view:
class UserAccountsUpdate(UpdateView):
context_object_name = 'variable_used_in `add_user_accounts.html`'
form_class = AddUserAccountsForm
template_name = 'add_user_accounts.html'
success_url = 'summary.html'
print "hello0"
def account_name_autocomplete(request):
print "hello1"
query = request.GET.get('q','')
if query:
print "hello2"
results = Insitutions.objects.filter(name__istartswith=query)
result_list = []
for item in results:
result_list.append(item.short)
else:
result_list = []
response_text = json.dumps(result_list, separators=(',',':'))
return HttpResponse(response_text, content_type="application/json")
#get object
def get_object(self, queryset=None):
return self.request.user
Thanks

Related

How to manage JSON data in javascript pass form django model?

I need to dynamically display my audio on my website. The audio is a file path stored in the Django model.
Djanog Model:
class audio(models.Model):
instrumentId = models.OneToOneField(instrument, on_delete=models.CASCADE, primary_key=True)
location = models.FileField()
I pass the data through view.py into json data so my script can read the data.
view.py, PostJsonListView fetch data form the model and generate json data, testView connect to the html displaying audios
class PostJsonListView(View):
def get(self, *args, **kwargs):
print(kwargs)
#upper is to get the number from the js file to set a upper boundry
upper = kwargs.get('num_aduios') #intial state be 3
lower = upper - 3
#pass in the audio in to the list [lower:upper] use to set boundry
audios = list(audio.objects.values()[lower:upper])
#comfirmation of no more audi to load
audio_size = len(audio.objects.values())
size = True if upper >= audio_size else False
return JsonResponse({'data':audios, 'max': size}, safe=False)
class testView(TemplateView):
template_name = 'frontend/testView.html'
JSON data in browser
Javascript that hand the data, after a button click, it would display three more data
console.log('HELLO')
const aduiosBox = document.getElementById('audio-box') //get the div audio-box
const nextBtn = document.getElementById('next-btn')
let visible = 3
const handleGetData = () =>{
$.ajax({
type: 'GET',
url: `/json/${visible}/`,
success: function(response)
{
max_size = response.max
//getting all the data and display in the console
const data = response.data
data.map(post=>{
console.log(post)
aduiosBox.innerHTML +=
//how to get the location right?
`
<div class="card p-3 mt-3 mb-3">
<audio controls>
<source src= ${post.location} type="audio/wav">
</audio>
</div>
`
})
//check if the display size reach maxium
if(max_size){
console.log('done')
}
},
error:function(error){
console.log(error)
}
})
}
handleGetData()
//event listenrs
nextBtn.addEventListener('click', ()=>{
visible += 3
handleGetData()
})
Console on the browser
Here, the audio path was from home/sound1.wav. From my another exmaple, where I also path audio object, has the path of /sounds/sounds1.wav
view.py for the working example
def survey(request):
if request.method == 'POST': #if something is post to the server, reference to HTML form method == post
form = rateForm(request.POST)
if form.is_valid():
form.save()
form = rateForm()
wavFile = audio.objects.all()
return render(request, "frontend/audio.html",{
'wavFile': wavFile,
'form': form,
})
Working example
File path of my Django app
In conclusion, I belive the website cannot get to the file path correctly. home/sound1.wav VS sounds/sound1.wav. How can I manage it so the Javascript code can get to the correct path to get the audio to display in the website?
I solved it by correcting the directory of my audio file. For anyone that is wondering the something, you should look at what have done to your setting.py for the directory of storing data you wanted to access

Create a FlaskForm dropdown based on the query string value

class DownloadForm(FlaskForm):
products = service.get_products()
choices = [(product, product.replace('-', ' '))
for product in products]
application = SelectField(
'Application',
[DataRequired()],
choices=choices
submit = SubmitField('Submit')
#home.route('/downloads/<application_name>', methods=['GET', 'POST'])
def downloads():
download_form = DownloadForm()
My route will be downloads/application_name.
Can I send this routevalue "application_name" to the form to filter out the choices in the Download Form?
I'm new to entire flask and python.
You can use a factory function to use the parameter from the URL to do your database query. Based on this query, a form is then created that can be used within the route.
def download_form_factory(name):
products = [
'Archiver',
'Editor-1',
'Editor-2',
'Music-Player',
'Video-Player'
]
class DownloadForm(FlaskForm):
app = SelectField(
'Application',
choices= [
(product, product.replace('-', ' ')) \
for product in filter(lambda p: name.lower() in p.lower(), products)
]
)
submit = SubmitField('Download')
return DownloadForm
The following example uses an input field of type QuerySelectField from WTForms-SQLAlchemy to facilitate database queries. As you can see above, the functionality is also possible with a normal SelectField.
A number of products are added to the database which, in addition to their name, have an additional property build.
If the user selects a name on the index page, all products that have the selected name are available for selection. He can then choose between the offered versions.
The form is created inside a function. The name to be searched for is passed to this function as a parameter. This can then be used to create the database query.
def download_form_factory(name):
# Create a class of the form.
class DownloadForm(FlaskForm):
# Create the select field
app = QuerySelectField(
# with a label
'Application',
# and the database entries containing the given name as options
query_factory=lambda: Product.query.filter(Product.name.ilike(f'%{name}%')).all(),
# and a label for each of these options.
get_label=lambda p: '%s (Build %s)' % (p.name, p.build),
# An option must be selected by the user.
validators=[InputRequired()]
)
# Create the Submit button.
submit = SubmitField('Download')
# Return the created form class.
return DownloadForm
Within the endpoint, the function mentioned is used and an instance of the form is created, which can be used in the usual way.
#app.route('/download/<string:name>', methods=['GET', 'POST'])
def download(name):
# Create the form and an instance of it.
form = download_form_factory(name)(request.form)
if form.validate_on_submit():
# If the POST request is sent with valid information,
# the form data can be requested.
# The result is the selected database object.
print(form.app.data)
return render_template('download.html', **locals())
Here is the complete example.
Flask (app.py)
from flask import (
Flask,
render_template,
request,
)
from flask_wtf import FlaskForm
from flask_sqlalchemy import SQLAlchemy
from wtforms import SubmitField
from wtforms_sqlalchemy.fields import QuerySelectField
from wtforms.validators import InputRequired
app = Flask(__name__)
app.secret_key = b'your secret here'
db = SQLAlchemy(app)
class Product(db.Model):
__table_args__ = (db.UniqueConstraint('name', 'build'),)
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
build = db.Column(db.String, nullable=False)
# Create a class of the form.
def download_form_factory(name):
class DownloadForm(FlaskForm):
app = QuerySelectField(
'Application',
get_label=lambda p: f'{p.name} (Build {p.build})',
query_factory=lambda: Product.query.filter(Product.name.ilike(f'%{name}%')).all(),
validators=[InputRequired()]
)
submit = SubmitField('Download')
return DownloadForm
# Fill the database with sample data.
with app.app_context():
db.drop_all()
db.create_all()
products = [Product(name=f'Product-{str(i).zfill(2)}', build=f'{j}') \
for i in range(1, 21) for j in range(1,i+1)]
db.session.add_all(products)
db.session.commit()
#app.route('/')
def index():
products = Product.query.group_by(Product.name).order_by(Product.name).all()
return render_template('index.html', **locals())
#app.route('/download/<string:name>', methods=['GET', 'POST'])
def download(name):
# Create the final object of the form.
form = download_form_factory(name)(request.form)
if form.validate_on_submit():
# Inquire about the selected product.
print(form.app.data)
return render_template('download.html', **locals())
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Index</title>
</head>
<body>
<ul>
{% for prod in products -%}
<li>{{prod.name}}</li>
{% endfor -%}
</ul>
</body>
</html>
HTML (templates/download.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Download</title>
</head>
<body>
<form method="post">
{{ form.csrf_token }}
<div>
{{ form.app.label }}
{{ form.app() }}
</div>
{{ form.submit() }}
</form>
</body>
</html>

Why does return jsonify() in flask goes to the API page instead of changing the page?

I am trying to make an upvote/downvote system on my Flask website, and I am trying to implement it using AJAX so the page won't reload every time there is an upvote or a downvote.
My flask application for project is:
#main.route('/project', methods=['GET', 'POST'])
def project():
...
return render_template('project.html', projects = all_projects, popular = liked_projects, recent = recent_projects,
users = all_users, comments = all_comments, followed = followed_projects, joined = joined_projects, my = my_projects, projectMember = projectMember)
My flask application for the upvote button is:
#main.route('/projects/upvote/<int:id>')
def projectupvote(id):
post = projectPosts.query.get_or_404(id)
post.likes += 1
db.session.commit()
return jsonify({"likes":post.likes})
My HTML is:
Up vote
Down vote
<h1 style="margin-bottom:5%; display: inline-block;" id = 'likes'> {{project.likes}}</h1>
And my JS application is:
$(document).ready(function() {
$('a').on('click', function(event) {
$.ajax({
data : {
likes : $('#likes').val(),
},
type : 'GET',
url : '/project'
})
.done(function(data) {
$('#likes').text(data.likes).show();
});
event.preventDefault();
});
});
When running the code, instead of updating the likes while staying on the page, it leads me to this:
It gives the correct data, but moves to another page displaying the raw JSON data of the likes.
Why does it happen and how to go about the situation? I have been researching for hours but couldn't get to the bottom of it.

Django 3. Having trouble passing dropdown menu selection from .html to forms

I'm still new to Django (2 weeks or so). I've been struggling the past few days with passing a string from an html file to forms. My project lets the user choose a state from a dropdown menu (Michigan and Ohio for now, I'll add the rest later). When the state is selected, it will take that string and pull a list of counties of that state from a spreadsheet. This is where the problem lies. I've searched far and wide and I just can't seem to find a solution. The major holdback to many of these solutions is I don't want to "submit" with a button. I want the user to "select" a state, then select a county without a page refresh. I've also included a screenshot of the webpage. So far the dependent dropdowns work perfectly thanks to a youtube tutorial. The "submit" button in the picture is cosmetic for now.
Thanks in advance for helping out. Let me know if you have any questions regarding models or anything else regarding the code.
views.py
def StateForm_Page(request):
context = {}
stateChoice = 'Michigan' //hardcode a state so if the post fails, the function can still find an excel sheet
if request.method == 'POST':
State_Form = StateForm(request.POST)
stateChoice = State_Form.cleaned_data['stateChoice'] //I think this is where my code is failing
else:
State_Form = StateForm()
context['State_Form'] = State_Form
dataArray = pd.read_excel(r'C:\filename.xls', sheet_name= stateChoice)
county_strings = dataArray['County '].values.tolist()
json_county_strings = json.dumps(county_strings)
context['json_county_strings'] = json_county_strings
return render(request, 'StateForm_page.html', context)
StateForm_page.html
<body>
<form action="" method="POST" name="stateChoice">
{% csrf_token %}
{{ State_Form.as_p }}
</form>
<script>
var state;
var county;
$(document).ready(function(){
$('#id_county').empty(); //empties county before state is chosen
$("#id_state").on('change', function(){ //when #id_state is changed...
state = $("#id_state").val(); //assign state with the selection
var countyStrings = JSON.parse('{{ json_county_strings | escapejs }}'); //grabs counties from respective state
var length = countyStrings.length;
var i;
for(i=0; i < length; i++){
county = countyStrings[i]; //update county options with spreadsheet values
$('#id_county').append(
`
<option value ="${county}">
${county}
</option>
`
);
}
});
})
}
</script>
</body>
What the webpage looks like so far:
Next day changes
Hey, after putting a few more hours into it, I'm still not having every luck. Per your suggestions, below is what I've added
views.py
def retrieveState(request):
statePick = request.GET.get('state')
return JsonResponse(statePick, safe = False)
def StateForm_Page(request):
context = {}
stateChoice = []
if request.method == 'POST':
#stateChoice = State_Form.cleaned_data['stateChoice']
State_Form = StateForm(request.POST)
stateChoice = retrieveState(request)
else:
stateChoice = 'Michigan'
State_Form = StateForm()
StateForm_Page.html
$.ajax({
type: 'POST',
url: 'ajax/retrieveState/',
data: state,
dataType: 'json',
});
Good news is something is being triggered on the ajax url I added, but I don't think the function in views is retrieving the ajax data. Any suggestions? Thanks for your help!

Display intro video first visit only Django

I have a Django app that needs to display a video that gives an into to the website. I only want it to do this on the initial visit as opposed to every time the user refreshes. I feel like sessions would have something to do with this but I’m not sure. Thanks!
I think its best to put this flag directly in your database. You can put a field in your user model(if you are using custom user) or in a model which has OneToOne relation with User. For example:
class Profile(models.Model):
user = models.OneToOneField(User)
has_seen_intro = models.BooleanField(default=False)
And send this information to Template from view like this, for example:
class HomeView(TemplateView):
template_name = 'home.html'
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
profile = self.request.user.profile
if not profile.has_seen_intro:
context['show_intro'] = True
profile.has_seen_intro = False
profile.save()
# or use user.has_seen_intro if you have custom model
return context
And update the template like this
{% if show_intro %}
// intro video codes
{% endif %}
Update
for anonymous user, please try like this:
class HomeView(TemplateView):
template_name = 'home.html'
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
if self.request.user.is_authenticated:
profile = self.request.user.profile
if not profile.has_seen_intro:
context['show_intro'] = True
profile.has_seen_intro = False
profile.save()
else:
if not self.request.session.get('has_seen_intro', True):
self.request.session['has_seen_intro'] = False
context['show_intro'] = True
return context

Categories