Django - Extracting data from Choice Field Formset - javascript

I was exploring the mechanism of formsets in Django. Here is a gist of what I did:
Created a sample choicefield form
forms.py
from django import forms
MONTH_CHOICES = (("JANUARY", "January"),
("FEBRUARY", "February"),
("MARCH", "March"),
("DECEMBER", "December"),)
class NameForm(forms.Form):
your_name = forms.ChoiceField(label="Your Name",choices=MONTH_CHOICES)
Added Views Code with a formset instance for the NameForm and data handling.
views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect,HttpResponse
from django.forms.formsets import formset_factory
from .forms import NameForm
def index(request):
lfs = formset_factory(NameForm)
if request.method == 'POST':
postedformset = lfs(request.POST)
if postedformset.is_valid():
for formz in postedformset:
print formz.cleaned_data['your_name']
return HttpResponseRedirect('/polls/thanks/')
else:
form = NameForm()
return render(request,'name.html',{'form':lfs})
def thanks(request):
return HttpResponse('Form filled. Thanks!')
3.A HTML for implementing the formset with a bit of javascript for adding and deleting forms
name.html
<html>
<head>
<title>DJANGO - First Forms</title>
</head>
<body>
<form action="/polls/" method="POST">
{{ form.management_form }}
<div class="link-formset">
{{ form }}
</div>
<input type="Submit"/>
</form>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.formset/1.2.2/jquery.formset.min.js"></script>
<script>
$('.link-formset').formset({
addText: 'add link',
deleteText: 'remove'
});
</script>
Implementation was done using this using this reference
Question
I was able to add multiple choicefields and save the form without any issues. However, only the choice of the first form was printed when
print formz.cleaned_data['your_name')
was executed. Querydict from request.POST has choices from all forms in formset (refer Update)
Please share your thoughts on this.
PS : I did check on questions like this and this, but still not able to trace the root cause.
Update
For 2 forms in my formset, when I tried to print request.POST, below QueryDict was obtained which has information from both forms..
<QueryDict: {u'form-1-form-TOTAL_FORMS': [u''], u'form-1-form-MIN_NUM_FORMS': [u''], u'form-1-form-MAX_NUM_FORMS': [u''], u'form-1-form-INITIAL_FORMS': [u''], u'form-MAX_NUM_FORMS': [u'1000', u'1000'], u'form-1-your_name': [u'FEBRUARY'], u'form-0-your_name': [u'FEBRUARY'], u'form-MIN_NUM_FORMS': [u'0', u'0'], u'form-INITIAL_FORMS': [u'0', u'0'], u'form-TOTAL_FORMS': [u'2', u'1']}>

Related

linking JavaScript code to Django database upon clicking on a button

I'm asked to work on a networking website that is like Twitter. I work with HTML,CSS, Javascript for the client-side and Django for the server-side. I'm trying to link between Javascript and Django using JSON and fetch as I want to create a button in each of the users' profile that upon being clicked by the registered user, it makes the registered follow the profile as it is saved in django database as a model containing the follower(follower) and the user followed(following) but upon clicking on follow button (in user.html) it doesn't save any data in the database
in models.py:
class follow(models.Model):
follower = models.ForeignKey("User",on_delete=models.CASCADE, related_name="follower")
following = models.ForeignKey("User",on_delete=models.CASCADE, related_name="following")
in user.html(contains the script):
<html>
<head>
<script>
document.addEventListener('DOMContentLoaded',function(){
document.querySelectorAll('input').forEach(input =>{
input.addEventListener('click', function(){
console.log(input.id);
let follow_username = input.id
fetch('/follow/'+ follow_id, {
method:'PUT',
body: JSON.stringify({
follow: true
})
})
})
}
)
});
</script>
</head>
<body>
<h2>{{x.username}}</h2>
<form>
{% csrf_token %}
<input type="submit" value="follow" name ="follow" id={{x.username}}>
</form>
</body>
</html>
in urls.py:
from django.urls import path
from . import views
urlpatterns = [
path("follow/<str:name>", views.Users, name="follow")
]
in views.py:
def Users(request, name):
x = User.objects.get(username = name)
if request.method == 'PUT':
data = json.loads(request.body)
if data.get('follow') is not None:
user = request.user
anotherr = User.objects.filter(username = name)
another = User.objects.get(username = anotherr).id
follow.objects.create(follower = user, following = another)
return render (request, "network/user.html",{"x":x})
upon clicking on the follow button that present in user.html, no data is created in the database. so what is the problem?
I'll throw my best guesses on what's happening.. Just some improper syntax and undefined variables
View
another / anotherr no, just use x you're already fetching the user at the top of the view
get_or_create will not allow you to have duplicates / follow someone twice (generally a good idea)
Prints are just debugging, remove after you know it's working
def Users(request, name):
x = User.objects.get(username=name)
if request.method == 'PUT':
print('we\'ve hit put')
data = json.loads(request.body)
if data.get('follow') is not None:
print('in follow')
# Note: [User Obj Itself]
# follower = request.user (is: <User Obj>)
# following = x (is: <User Obj>)
followObj, createdBool = follow.objects.get_or_create(follower=request.user, following=x)
print('followObj', followObj)
print('created?', createdBool)
print('past follow')
print('about to render')
return render (request, "network/user.html",{"x":x})
Template
Idk what follow_id is, just use input.id
<html>
<head>
<script>
document.addEventListener('DOMContentLoaded',function(){
document.querySelectorAll('input').forEach(input =>{
input.addEventListener('click', function(){
// this should be true
console.log(input.id == '{{x.username}}');
console.log('Fetch Url:\t' + '/follow/'+ input.id);
fetch('/follow/'+ input.id, {
method:'PUT',
body: JSON.stringify({
follow: true
})
})
})
}
)
});
</script>
</head>
<body>
<h2>{{x.username}}</h2>
<form>
{% csrf_token %}
<input type="submit" value="follow" name ="follow" id={{x.username}}>
</form>
</body>
</html>
If these don't work, tell me what print or console.log got hit or didn't get hit- that'll really help narrow down the issue even more
Edit
Supposedly this, putting a token in a header, will work if you don't want to put a #csrf_exempt decorator (which might be a good idea tbh)
fetch('/follow/'+ input.id, {
method:'PUT',
headers: { 'X-CSRFToken': $('[name=csrfmiddlewaretoken]').val() },
body: JSON.stringify({
follow: true
})
})

Save JavaScript GeoLocation data to Django admin page [duplicate]

Is it possible to save the javascript html5 geolocation latitude and longitude to the django admin when user uses the geolocation website. The web page goal is to save the user's longitude and latitude values so that the data can be accessed later on when user signs in again.
I found a similar question being asked in stackoverflow years ago but there hasn't been any answer. The link is : Save JavaScript GeoLocation data to Django admin page
It would be great if there this an answer based on this code link.
Another option I read about is to create a html form and set the form to be autopopulated by jQuery from data produced by the javascript html5 geolocation. Again this is quite complicated for a beginner like me.
I would appreciate any bit of help whether by code, tutorial, blog post, examples or links. I don't expect all the programming code to be provided (although I do learn better from examples) but it would help if there are some material/example I could go to, to implement my programming tasks. Thank you.
I am currently up to here with my progress but still am unable to post the latitude and longitude to the django admin page:
code is as following:
The structure of the django project is as follows:
-ajax
- __pycache__
- migrations
- __pycache__
0001_initial.py
__init__.py
- static
- css
- bootstrap.css
- fonts
- js
- script.js
- templates
- ajax
- base.html
- index.html
- __init__.py
- admin.py
- apps.py
- models.py
- tests.py
- urls.py
- views.py
-server
- __pycache__
- __init__.py
- settings.py
- urls.py
- views.py
- wsgi.py
-db.sqlite3
-manage.py
index.html
{% extends 'ajax/base.html' %}
{% block body %}
<p>Click the button to get your coordinates.</p>
<button onclick="getLocation()">Get Your Location</button>
<p id="demo"></p>
<button type="button" id="btn_submit" class="btn btn-primary form-control" disabled>Submit</button>
{% endblock %}
script.js
var pos;
var $demo;
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
$demo.text("Geolocation is not supported by this browser.");
}
}
function showPosition(position) {
pos = position;
var { latitude, longitude } = pos.coords;
$demo.html(`Latitude: ${latitude}<br>Longitude: ${longitude}`);
$('#btn_submit').attr("disabled", null);
}
$(document).ready(function() {
$demo = $("#demo");
$('#btn_submit').on('click', function() {
var data = pos.coords;
data.csrfmiddlewaretoken = $('input[name=csrfmiddlewaretoken]').val();
$.post("/ajax/", data, function() {
alert("Saved Data!");
});
});
});
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" name="viewport" content="width=device-width, initial-scale=1">
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'ajax/css/bootstrap.css' %}"/>
</head>
<body>
{% csrf_token %}
<nav class="navbar navbar-default">
<div class="container-fluid">
</div>
</nav>
<div class="col-md-3"></div>
<div class="col-md-6 well">
<h3 class="text-primary">Python - Django Simple Submit Form With Ajax</h3>
<hr style="border-top:1px dotted #000;"/>
{% block body %}
{% endblock %}
</div>
</body>
<script src = "{% static 'ajax/js/jquery-3.2.1.js' %}"></script>
<script src = "{% static 'ajax/js/script.js' %}"></script>
</html>
models.py
from django.db import models
# Create your models here.
class Member(models.Model):
latitude = models.DecimalField(max_digits=19, decimal_places=16)
longitude = models.DecimalField(max_digits=19, decimal_places=16)
views.py (ajax)
from django.shortcuts import render, redirect
from .models import Member
def index(request):
return render(request, 'ajax/index.html')
def insert(request):
member = Member(latitude=request.POST['latitude'], longitude=request.POST['longitude'])
member.save()
return redirect('/')
urls.py (ajax)
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name="index"),
url(r'^insert$', views.insert, name="insert")
]
views.py (server)
from django.shortcuts import redirect
def index_redirect(request):
return redirect('/ajax/')
urls.py (server)
from django.conf.urls import url, include
from django.contrib import admin
from . import views
urlpatterns = [
url(r'^$', views.index_redirect, name="index_redirect"),
url(r'^ajax/', include("ajax.urls")),
url(r'^admin/', admin.site.urls),
]
It "POST"s the data but it does not appear in the django admin. I trawled many websites searching for answers why but still haven't found any. Thank you again for your help.
I have used jQuery and Ajax to submit the longitude and latitude data to any model you want to store these data in.
in your model.py:
from django.contrib.auth import User
class UserGeoLocation(models.Model):
user = models.OneToOneField(User)
latitude = models.FloatField(blank=False, null=False)
longitude = models.FloatField(blank=False, null=False)
for your view.py
def save_user_geolocation(request):
if request.method == 'POST':
latitude = request.POST['lat']
longitude = request.POST['long']
UserGeoLocation.create(
user = request.user
latitude= latitude,
longitude = longitude,
)
return HttpResponse('')
now that we have the view we can setup a url endpoint to submit the post request
url('^abc/xyz/$', appname.views.save_user_geolocation)
and Finally for the actual form,
$(document).on('submit', '#id', function(e){
e.preventDefault();
$.ajax(
type='POST',
url = 'abc/xyz',
data : {
lat:position.coords.latitude,
long: position.coords.longitude
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
},
});
for the last step, lets say you used the js code from the example you linked, then you can assign these coordinates value to variables that will be submitted with the post request that gets triggered when the user clicks on the button, the id here is the id of the form you want to submit the data from, and the e.PreventDefault is to stop the page from reloading when you post the data. Finally, the csrf token is required by django to able to submit the form.

Passing array from Flask to Javascript to create options for drop down menu

I am new to Flask and Javascript. I am trying to upload a file and use one of its columns as options in the drop down menu. Please correct me where I am wrong.
Here are the codes:
Flask:
from flask import Flask, render_template, redirect, url_for, request, flash, send_from_directory
from werkzeug import secure_filename
import os
import pandas as pd
import numpy as np
import json
UPLOAD_FOLDER = 'uploads/'
ALLOWED_EXTENSIONS = set(['csv'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
#app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
file = request.files['data_file']
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
data = pd.read_csv(os.path.join(app.config['UPLOAD_FOLDER'], filename))
names = data['some_column']
return redirect(url_for('drop_down', names=names))
#return render_template('drop_down.html', names=names)
return render_template('file_upload.html')
#app.route('/meta')
def drop_down():
return render_template('drop_down.html')
Javascript:
function my_script(){
console.log('script called.');
//var cars = ["Volvo","Ferrari","Audi","BMW","Mercedes","Porche","Saab","Avanti"];
var cars = {{ names|safe }};
console.log('cars assigned.');
function make_drop_down(list_of_names, element_id){
select_elem = document.getElementById(element_id)
if(select_elem){
for(var i = 0; i < list_of_names.length; i++) {
var option = document.createElement('option');
option.innerHTML = list_of_names[i];
option.value = list_of_names[i];
select_elem.appendChild(option);
}
}
};
console.log("Making Drop Downs!!");
make_drop_down(cars, 'drop_down_1');
make_drop_down(cars, 'drop_down_2');
console.log("Made Drop Downs!!");
};
html:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="static/drop_down.js"></script>
<title>DROP DOWN</title>
</head>
<body onload="my_script()">
<select id="drop_down_1">
<option>Choose Option 1</option>
</select>
</br></br>
<select id="drop_down_2">
<option>Choose Option 2</option>
</select>
</body>
</html>
I get the following error on the console:
ReferenceError: my_script is not defined
There are two problems.
The first one is that you are not passing the list of cars in your view handeling /meta
#app.route('/meta')
def drop_down():
return render_template('drop_down.html')
This should probably look something like this:
#app.route('/meta')
def drop_down():
cars = ["Volvo","Ferrari","Audi","BMW","Mercedes","Porche","Saab","Avanti"]
return render_template('drop_down.html',
names=cars)
The second problem is that your javascript won't be able to access the list, unless you pass it in your call to the function.
html
<body onload="my_script({{ names }})">
javascript
function my_script(names){
console.log('script called.');
var cars = names;
...
Edit:
The function that handles the view is the function that needs to pass the data. You could also use the commented away part of your upload file, which calls render_template... with the necessary data, but this doesn't feel as a "nice" approach.
You need to make the data available to your drop_down() view, either by storing it in a database, reading the data from the file in this function or by storing it in the session. So that you can pass the data along with the template

Embedding multiple pieces of JavaScript via a Tornado UIModule

I'm working on a Python package that uses Tornado to send data to the browser for visualization. In order to do this, I want the users to be able to write multiple arbitrary modules for the server to render together on a single page -- including each module's own JavaScript.
However, by default, the Tornado's UIModule class's embedded_javascript() method only appends JavaScript to <script>...</script> once per module class. I'm hoping there is a simple way to embed multiple pieces of JS, one for every UIModule (or another way to get the same effect).
Here's a minimal example of what I'm talking about:
import tornado.ioloop
import tornado.web
import tornado.template
class Element(tornado.web.UIModule):
'''
Module to add some custom JavaScript to the page.
'''
def render(self, element):
self.js_code = element.js_code
return ""
def embedded_javascript(self):
return self.js_code
class InterfaceElement(object):
'''
Object to store some custom JavaScript code.
'''
def __init__(self, js_code):
'''
Args:
js_code: Some JavaScript code in string form to add to the page.
'''
self.js_code = js_code
class MainPageHandler(tornado.web.RequestHandler):
def get(self):
elements = self.application.modules
self.render("uitest_template.html", app_name="Testing", elements=elements)
class ThisApp(tornado.web.Application):
def __init__(self, modules):
self.modules = modules
main_handler = (r'/', MainPageHandler)
#settings = {"ui_modules": {"Element": Element}}
settings = {"ui_modules": {"Element": Element},
"template_path": "ui_templates"}
super().__init__([main_handler], **settings)
# Create two objects with some custom JavaScript to render
module_1 = InterfaceElement("var a = 1;")
module_2 = InterfaceElement("var b = 2;")
app = ThisApp([module_1, module_2])
app.listen(8888)
tornado.ioloop.IOLoop.instance().start()
And the template for uitest_template.html is just
<!DOCTYPE html>
<head>
<title> Hello World </title>
</head>
<body>
{% for element in elements %}
{%module Element(element) %}
{% end %}
</body>
The rendered page then includes a <script> tag in body that is:
<script type="text/javascript">
//<![CDATA[
var b = 2;
//]]>
</script>
And what I want is:
<script type="text/javascript">
//<![CDATA[
var a = 1;
var b = 2;
//]]>
</script>
Or something like it. Any ideas?
Added - my solution
Based on the answer below, here's how I ended up handling it:
import tornado.ioloop
import tornado.web
import tornado.template
class InterfaceElement(object):
include_js = [] # List of .js files to include
js_code = '' # JavaScript string to include
def __init__(self, include_js=[], js_code=''):
self.include_js = include_js
self.js_code = js_code
class MainPageHandler(tornado.web.RequestHandler):
def get(self):
self.render("modular_template.html",
includes=self.application.include_js,
scripts=self.application.js_code)
class ThisApp(tornado.web.Application):
def __init__(self, modules):
# Extract the relevant info from modules:
self.modules = modules
self.include_js = set()
self.js_code = []
for module in self.modules:
for include_file in module.include_js:
self.include_js.add(include_file)
if module.js_code != '':
self.js_code.append(module.js_code)
main_handler = (r'/', MainPageHandler)
settings = {"template_path": "ui_templates",
"static_path": "ui_templates"}
super().__init__([main_handler], **settings)
module_1 = InterfaceElement(js_code="var a = 1;")
module_2 = InterfaceElement(include_js=["test.js"], js_code="var b = 1;")
app = ThisApp([module_1, module_2])
app.listen(8888)
tornado.ioloop.IOLoop.instance().start()
Which goes with the following template:
<!DOCTYPE html>
<head>
<title> Hello world </title>
</head>
<body>
<!-- Script includes go here -->
{% for file_name in includes %}
<script src="/static/{{ file_name }}" type="text/javascript"></script>
{% end %}
<script type="text/javascript">
// Actual script snippets go here.
{% for script in scripts %}
{% raw script %}
{% end %}
</script>
</body>
embedded_javascript and related methods are (effectively) class-level methods; they must return the same value for any instance of the class. (They're intended to be a kind of dependency-management system, so you can load a piece of javascript only on pages that include a module that needs it)
The only thing that is allowed to vary per instance is the output of render(), so to embed multiple pieces of javascript you should include the script tag in the result of your render() method.

Django & jQuery - How to use the TagSelectMultiple widget

I am trying to use the jquery-tagselector widget from stackoverflow's user Julio César with Django, and I am quite lost...
My form is:
class CreationForm(forms.Form):
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all(),widget=TagSelectMultiple(attrs={ 'style': 'width:400px', 'id': 'tags' }))
The TagSelectMultiple widget has the following code:
from django import forms
from django.forms.util import flatatt
from django.utils.encoding import force_unicode
from django.utils.html import escape, conditional_escape
from django.utils.safestring import mark_safe
class TagSelectMultiple(forms.SelectMultiple):
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
final_attrs = self.build_attrs(attrs, name=name)
self.name = name
output = [u'<div class="tagSelector" multiple="multiple"%s>' % flatatt(final_attrs)]
options = self.render_options(choices, value)
if options:
output.append(options)
output.append('<input type=text>')
output.append('</div>')
return mark_safe(u'\n'.join(output))
def render_option(self, selected_choices, option_value, option_label):
if unicode(option_value) in selected_choices:
return u'<span class="tag">%s <a>x</a><input name="%s" type="hidden" value="%s"/></span>' % (
conditional_escape(force_unicode(option_label)), escape(self.name), escape(option_value))
return ''
And my Tag model is:
class Tag(models.Model):
word = models.CharField(max_length=30)
def __unicode__(self):
return u"%s" % self.word
In my template, I have included all the needed javascript files:
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/themes/base/jquery-ui.css" rel=stylesheet type="text/css">
<link href='{% static "jquery-tagselector.css" %}' rel=stylesheet>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<script type='text/javascript' src='{% static "jquery-tagselector.js" %}'></script>
And I print my field with {{form.tags}}.
Following Julio César instructions on his webpage about how to use his Django Form Widget, I only had to modify the widget attributes, to get a good input id name:
Before my modification:
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all(),
widget=TagSelectMultiple(attrs={ 'style': 'width:300px' }))
After my modification:
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all(),
widget=TagSelectMultiple(attrs={ 'style': 'width:400px', 'id': 'tags' }))
First question: I don't know if I need to add the following script because I already gave my list of tags in the queryset attributes form field?
$('#tags').tagSelector(tags, 'tags');
Second question: When typing in my autocomplete box, I get absolutely no choices despite of having plenty Tag objects. Is it because of my tag model? Julio César don't explain the architecture of his Tag model, and I have some difficulties to guess this one. Or maybe it is because there is no self.choices in the widget code?
Link:
javascript jquery-tagselector.js file

Categories

Resources