Return two responses in Flask/JavaScript - javascript

I have a Flask/JavaScript application wherein I take a form's inputs and pass them to a Flask app to retrieve distance information from the GoogleMaps API and subsequently return the resulting JSON to JavaScript.This works fine for a single instance of an origin/destination.
I want to receive two origin/destination inputs and return both to my JavaScript but cannot figure out how to do that. I'm still learning, but am under the impression I can't simply return two values in a single function so I'm hoping someone can take a look at what I have and tell me what the best approach would be to get the JSON for both back to JavaScript.
#app.route("/", methods=['GET', 'POST'])
def home():
if request.method == 'POST':
# form inputs
origin = request.form.get('origin')
destination = request.form.get('destination')
current_home = request.form.get('current_home')
future_home = request.form.get('future_home')
# current traffic conditions set to now
departure = int(time.time())
# params we pass to the url
current_params = {
'origins': origin,
'destinations': destination,
'mode':'driving',
'units':'imperial',
'departure_time' : departure,
'traffic_model':'best_guess',
'avoid':'tolls'
}
future_params = {
'origins': future_home,
'destinations': destination,
'mode':'driving',
'units':'imperial',
'departure_time' : departure,
'traffic_model':'best_guess',
'avoid':'tolls'
}
# api call
current_url = 'https://maps.googleapis.com/maps/api/distancematrix/json?'+ urllib.urlencode(current_params)
future_url = 'https://maps.googleapis.com/maps/api/distancematrix/json?'+ urllib.urlencode(future_params)
current_response = requests.get(current_url)
future_response = requests.get(future_url)
# return json
return jsonify(current_response.json())
return jsonify(future_response.json())
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True)

You need to wrap both values in a dict and then return the dict.
payload = {
"current_response": current_response,
"future_response": future_response
}
return jsonify(payload)

Related

How to solve add key and value in cookies in the developer tools using django?

This is a Social network website. It's built-in python Django. I need to add the user login section to the values stored in the local storage section.
in this website have 2 login method one is end-user and another is companies
the main setting is needed user is login that time the key and value is needed to store the local storage
this is needed for cross-site login for users for example Facebook users have joined in through Instagram.
please help me with the solution? I need to fix the set cookies in the session also
I added the codes below section models.py
# Custom user
class CustomUser(AbstractUser):
""" Custom user model"""
email = models.EmailField(unique=True, validators=[EmailValidator])
is_company = models.BooleanField(default=False)
is_employee = models.BooleanField(default=False)
is_enduser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
slug = AutoSlugField(populate_from='username')
objects = CustomUserManager()
def __str__(self):
return f"{self.username}"
#property
def group_name(self):
"""
Returns a group name based on the user's id to be used by Django Channels.
Example usage:
user = User.objects.get(pk=1)
group_name = user.group_name
"""
return "user_%s" % self.id
*urls.py
app_name = 'account'
urlpatterns = [
path('login/company/', views.u_login, name='c_login'),
path('login/employee/', views.c_login, name='u_login'),
path('logout/', views.user_logout, name='logout'),
path('user-signup/', user_signup_view, name="user_signup"),
path('switch/<int:id>/', switch_user, name="user_switch"),
path('activate/<slug:uidb64>/<slug:token>/',views.activate_account, name='activate'),
path('change-pwd/<int:id>/', views.set_password, name='set_pwd'),
]
#employee copy login
def c_login(request):
print("runned")
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
print("cd",cd)
user = authenticate(request,
username=cd['username'],
password=cd['password'],
remember_me=cd['remember_me'])
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect(reverse('feed:user_feed', args=[request.user.profile.slug]))
else:
return HttpResponse('Disabled account')
else:
messages.error(request, 'Invalid username or password')
return render(request, 'account/u_login.html', {'form': form})
else:
form = LoginForm
return render(request, 'account/u_login.html', {'form': form})
Login session check through cookies and set encrypted token with (Unique ID, Name, E-mail) According to the given flow.
Set details in Cookies with Encrypted Token
With
(ID,Name,Email )
Probably django-allauth is what you need. Most thing you need have been implemented.
https://django-allauth.readthedocs.io/en/latest/index.html
first install these packages and the settings include session also.
https://docs.djangoproject.com/en/3.2/topics/http/sessions/
install this package and session need to added also
pip install djangorestframework-simplejwt
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
SESSION_COOKIE_SECURE = False
ENCRYPTED_COOKIE_SERIALIZER = 'json'
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SAMESITE = 'None'
SESSION_COOKIE_SAMESITE = 'None'
COMPRESS_ENCRYPTED_COOKIE = True
ENCRYPTED_COOKIE_COMPRESSION_LEVEL = 1

DFR simple jwt get authToken from a user instance instead of username/password

I have a simple chat app, authentication in it works exaclty as whatsapp
Get phone number => if doesn't exist create one else skip => send validation code and set it as "phone_code" field in User model => finally remove the "phone_code" if validated
The app is built in React Native with Rest framework as the API, I'm new to this and I'm struggling to get the authentication token without the password. i use djangorestframework-simplejwt
my register view:
#api_view(('POST',))
def register(request):
if request.method == 'POST':
serializer = UserSerializer(data=request.data)
if not serializer.is_valid():
if 'is not valid' in serializer.errors['phone_number'][0]:
return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)
phone_number = serializer.initial_data['phone_number'].replace(' ', '')
try:
user = User.objects.get(phone_number=phone_number)
except User.DoesNotExist:
user = User.objects.create_user(
phone_number=phone_number, username=phone_number)
user.phone_code = randint(99999, 999999)
user.save()
TokenObtainPairView()
return Response(serializer.data, status.HTTP_200_OK)
# todo send validation code, I will handle later
my Login view (Chich validates for the validation code)
#api_view(['POST',])
def loginuser(request):
if request.method == 'POST':
phone_number = request.data.get('phone_number')
try:
user = User.objects.get(phone_number=phone_number)
if int(request.data.get('phone_code')) == user.phone_code and user.phone_code:
user.phone_code = None
user.save()
#!!!!!!!!!!!!!!!!!!!NOW HOW CAN I GET THE JWT AUTHENTICATION TOKEN AND SEND IT TO MY REACT NATIVE APP?!
return JsonResponse({'phone_number': phone_number}, status=200)
else:
return JsonResponse({'error': "Invalid code"}, status=400)
except Exception as error:
return JsonResponse({'error': error}, status=500)
when the user validates his phonenumber, how can I send the jwt format auth token with the Response?
urls.py:
path('api/token/', users_views.ObtainToken.as_view(), name='token_obtain_pair'),
my Custom obtainToken view:
class ObtainToken(TokenObtainPairView):
permission_classes = (AllowAny,)
serializer_class = MyTokenObtainPairSerializer
Also I found out that when I was using Postman if I send an empty password the system will give a the authentication token. I would appreciate any help, thanks
You should base your code on the existing views and serialiazer from rest_framework_simplejwt : using TokenObtainPairView is a good start, keep that.
Then in your seriliazer_class, MyTokenObtainPairSerializer, you should use TokenObtainSerializer
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
self.user = User.objects.get(phone_number=phone_number)
# Do the verification with the phone_code here, if error, return a response with an error status code
refresh = self.get_token(self.user)
data['refresh'] = text_type(refresh)
data['access'] = text_type(refresh.access_token)
return data

Submitting form and getting response without refreshing page

I was making this simple BMR calculator app the problem is when I submit I don't want to go to any other page I want to show the results in the same page instead of having to go to another page.
In my views.py
def bmrvalue(age, height, weight, gender):
if gender == 'm':
BMR = (10 * weight) + (6.25 * height) - (5 * age) + 5
else:
BMR = (10 * weight) + (6.25 * height) - (5 * age) - 161
return BMR
def MyBmr(request):
if request.method == "POST":
form = BmrForm(request.POST)
if form.is_valid():
age = form.cleaned_data['age']
height = form.cleaned_data['height']
weight = form.cleaned_data['weight']
gender = form.cleaned_data['gender']
mybmr = bmrvalue(age,height,weight,gender)
return render (request, 'resultes.html', {'bmr':mybmr })
else:
form = BmrForm()
return render (request, 'home.html', {'form': form})
Any ideas on how I can achieve that?
The front end code required for this (place in your HTML) notice that I said required pretty much other than web sockets this is the way to do this:
<script>
function calculateResultsAndPost(){
const gender = document.getElementById('gender')
const weight = document.getElementById('weight')
const height = document.getElementById('height')
const age = document.getElementById('age')
const BMR = (10 * weight ) + (6.25 * height) - (5 * age ) + gender.isChecked ? 5 : - 161
// if you really need this on the server
fetch('/my-python-api-endpoint/bmr', {
method: 'POST',
body: {body:
{
BMR: BMR,
otherData: otherData,
weight: weight,
gender: gender.isChecked,
age: age
}
})
}
</script>
The logic in this for needs to move to JavaScript including all the math there seems to be no reason for serverside interaction here at all, but in case you need it those requests need to happen not using the
The only way to get data to the backend without making the page fully refresh is through JavaScript (whether new WebSocket(), XMLHttpRequest()/fetch()). If you submit a form with an action and method it will refresh the page there are no if ands or buts about this (well you can be really hacky and place that in an iFrame and have the iFrame refresh).
The backend Django code required:
In urls.py
from django.urls import path
from . import views
app_name = 'bmr'
urlpatterns = [
path('/bmr', views.IndexView.as_view(), name='index'),
]
In views.py. All this is a vague approximation
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, JsonResponse
from django.urls import reverse
from django.views import generic
from .models import User
class IndexView(generic.ListView):
def post(self, request, *args, **kwargs):
"""Accepts XMLHttpRequests"""
user = User.create(processRequest(request.body))
return JsonResponse(user.toJSON())
# or more simply:
def post(self, request, *args, **kwargs):
user = User.create(processRequest(request.body))
return JsonResponse(user.toJSON())
From the Django docs:
HttpRequest.body¶ The raw HTTP request body as a byte string. This is
useful for processing data in different ways than conventional HTML
forms: binary images, XML payload etc. For processing conventional
form data, use HttpRequest.POST.
You can also read from an HttpRequest using a file-like interface. See
HttpRequest.read().

Dynamic EventSource with flask and javascript

I am currently building a tool using flask that does various actions using ssh. One of those actions is using DD to copy from X to Y.
I currently have the following javascript set up on my page
<script>
var source == new EventSource("/dd");
source.onmessage = function(event){
$('.determinate'.css('width', event.data+'%')
if(event.data == 100){
source.close()
}
}
Which calls the following flask generator which parse's the stdout of DD to return a % value for the current progress.
#app.route('/dd')
def progress():
def generate():
ssh.SSHClient('127.0.0.1', username, password)
chan = ssh.get_transport().open_session()
chan.settimeout(10800)
try:
ssh.do('dd if=/dev/sda of=/test.img')
while data:
data = chan.recv_stderr(1024)
try:
yield "data: " + str(data) + "\n\n\"
return Response(generate(), mimetype='text/event-stream')
The above is pseudo code, but the things i want to be able to change are the DD command (dd if=/dev/sda of=/test/img) from variables i get from the form that triggers this page, as well as the hostname from the ssh.connect function with request.remote_addr.
When i try to replace '127.0.0.1' with request.remote_addr i get an out of context error.
Is there anyway to pass flask/jinja2 variables such as {{ image.path }} to my generator view?. The pseudo code i want would be this, where hostname, and dd is dynamic ( changes are in curly brackets )
#app.route('/dd')
def progress():
def generate():
ssh.SSHClient({{ request.remote_addr }}, username, password)
chan = ssh.get_transport().open_session()
chan.settimeout(10800)
try:
ssh.do('dd if={{ device }} of={{ image.path }}')
while data:
data = chan.recv_stderr(1024)
try:
yield "data: " + str(data) + "\n\n\"
return Response(generate(), mimetype='text/event-stream')
Just figured it out, didn't read the last paragraph of the docs.
If You want to keep the context of the previous request in the generator just change
return Response(generate(), mimetype='text/event-stream')
to
return Response(stream_with_context(generatE()), mimetype='text/event-stream')
For passing data i just used the "session" object to pass data and then remove it when im done using it.

Django - simplejson response

I'm using jQuery autocomplete plugin http://www.devbridge.com/projects/autocomplete/jquery/ to provide search suggestions in my web application where I want to send the response in json format.
Django views.py for sending the suggestions response:
def keywords_suggestions(request):
if request.is_ajax():
suggestions = []
q = request.POST.get('q')
try:
g = KeywordsModel.objects.filter(keyword__startswith=q).order_by('count')
except KeywordsModel.DoesNotExist:
return HttpResponse("")
else:
for i in range(0,len(g)):
global suggestions
suggestions.append(g[i].keyword)
to_json = {
"query": q,
"suggestions": suggestions
}
return HttpResponse(simplejson.dumps(to_json), mimetype='application/json')
Django models.py:
class KeywordsModel(models.Model):
keyword = models.CharField(max_length=40, blank=False)
count = models.IntegerField(max_length=20)
def __unicode__(self):
return self.keyword
jQuery code:
$("#add-keywords").keyup(function() {
$('#add-keywords').autocomplete({
serviceUrl:'/keywords_suggestions',
minChars:3,
maxHeight:220,
width:280,
zIndex: 9999,
params: { q: $('#add-keywords').val() },
onSelect: function(value, data){ $('#add-keywords').val(value); },
});
});
I'm getting this error when I type on the #add-keywords text box.
Request URL:http://127.0.0.1:8000/keywords_suggestions/?q=web&query=web
Request Method:GET
Status Code:500 INTERNAL SERVER ERROR
UPDATE
ValueError at /keywords_suggestions/
The view information.views.keywords_suggestions didn't return an HttpResponse object.
UPDATE-2
I'm having doubt in the suggestions variable, maybe global suggestions will have the problem. Am I doing it right?
Could anyone guide me to make it work?
UPDATE-3
<input type="text" id="add-keywords" name="add-keywords" title="e.g. Web developer, Javascript, Musician, Jazz" />
How to get the value of #add-keywords text box in the Django views.py. Does this work q = request.POST.get('add-keywords')?
Thanks!
the judgement request.is_ajax() returns False
The condition branches
try:
g = KeywordsModel.objects.filter(keyword__startswith=q).order_by('count')
except KeywordsModel.DoesNotExist:
return HttpResponse("")
else:
...
also could fail as ValueError if, for example, request.POST.get('q') results None
Plus, try '/keywords_suggestions/', note the suffix slash, instead of '/keywords_suggestions' in the serviceUrl:'/keywords_suggestions', line

Categories