How to retrieve data from url using django urls - python

this is the call back URL which am getting from the payment gateway I am integrating with
http://127.0.0.1:8000/checkout/mfsuccess/?paymentId=060630091021527961&Id=060630091021527961
I want to extract the paymentId int from this URL so I can use it in my function
this is the URL line am using
path('checkout/mfsuccess/?<str:paymentId>', gateway_Success, name='mf_success'),
and this is my function
def gateway_Success(request, id):
payment_id = request.GET.get('id')
print(payment_id)
context = {
"payment_id": payment_id
}
return render(request, "carts/checkout-mf-success.html")
How I do that since the way am doing not working I am getting the following error
Not Found: /checkout/mfsuccess/
[20/Nov/2020 03:38:59] "GET /checkout/mfsuccess/?paymentId=060630091121528060&Id=060630091121528060 HTTP/1.1" 404 4378

You don't need to adjust your path() function to catch the URL query parameters
path('checkout/mfsuccess/', gateway_Success, name='mf_success'),
also, change your view as,
def gateway_Success(request):
id_ = request.GET.get('Id') # retrieving the `Id`
payment_id = request.GET.get('paymentId') # retrieving the `paymentId`
context = {
"payment_id": payment_id,
"id_": id_
}
return render(request, "carts/checkout-mf-success.html", context=context)
This is enough to catch the redirection.

Related

How to pass arguments to HTML form using flask in case of redirection

I want to pass some arguments to my HTML form from flask when using redirect(url_for('Some End-Point')) instead of render_template(). I have already visited both of these questions
redirect while passing arguments
How can I pass arguments into redirect(url_for()) of Flask?
but neither of them had the answer I am looking for. After some surfing I do find out that I have to use session for this but the problem is I don't know actually how to use that either. When I use this:
return redirect(url_for('register', neg_resp="Username Already Taken"))
the problem was, my output message do generate but came with URL instead and thus my jinja template doesn't receive it. Link from 120.0.0.1:5000/register/ changed to 120.0.0.1:5000/register/?=Username Already Taken
And when I do this:
return redirect(url_for('register'), neg_resp="Username Already Taken")
An error gets generated, TypeError: redirect() got an unexpected keyword argument 'neg_resp'
Here's my Python Code
# Setting Up Route for Register Page
#app.route('/register/', methods=['GET', 'POST'])
def register():
# Fetching Form Data
user = {
"name": request.form.get('name'),
"email": request.form.get('email'),
"username": request.form.get('username'),
"password": request.form.get('password'),
"tasks":[]
}
# Inserting data to Database and Redirecting to Login Page after Successful Registration
if user['name'] != None:
user['password'] = pbkdf2_sha256.encrypt(user['password'])
if mongo.db.appname.find_one({"username": user["username"]}):
return redirect(url_for('register'), neg_resp="Username Already Taken")
else:
mongo.db.appname.insert(user)
return redirect(url_for('login', pos_resp="Registered Successfully"))
return render_template('register.html')
Error
TypeError: redirect() got an unexpected keyword argument 'neg_resp'
This won't work:
return redirect(url_for('register'), neg_resp="Username Already Taken")
because it passes neg_resp as a parameter of redirect instead of url_for.
Here's a basic example of how to pass parameters between routes and to a template:
#app.route('/first/')
def first():
return redirect(url_for('second', passed_value='string value'))
#app.route('/second/')
def second():
passed_value = request.args.get('passed_value')
return render_template('index.html', val_name=passed_value)
So here's what I tried, I made a global dictionary and keep updating it wherever needed, now whenever I want to access some values I directly access it from my dictionary and render it using jinja templating. Apart from this method there are other ways as well like storing data in flask.session also one can use flask.flash() to render messages and access them using messages.get() function in their jinja template, but the problem with it is, it only provides a limited amount of size, if you pass an object or string of beyond that size, the browser simply ignores it and your messages will not be displayed because the message passed is in the form of browser-cookies. So, storing them in my global dictionary works for me:
Here's a small snippet of my final code which similarizes the code I have posted as question:
# Globals
info = {
'logged_in' : False,
'user' : {},
'tasks' : [],
'status' : {
'value' : '',
'positive' : True
}
}
def reset():
'''
function to reset the values of info object
'''
global info
info['logged_in'] = False
info['user'] = {}
info['tasks'] = []
info['status'] = {
'value' : '',
'positive' : True
}
# Setting Up Route for Register Page
#app.route('/register/', methods=['GET', 'POST'])
def register():
'''
function to register an account into the server and database
'''
global info
# Fetching Form Data
user = {
"name": request.form.get('name'),
"email": request.form.get('email'),
"username": request.form.get('username'),
"password": request.form.get('password'),
"tasks":[]
}
# Inserting data to Database and Redirecting to Login Page after Successful Registration
if user['name'] != None:
user['password'] = pbkdf2_sha256.encrypt(user['password'])
if mongo.db.appname.find_one({"username": user["username"]}):
info['status']['value'] = 'Username Already Taken'
info['status']['positive'] = False
return redirect(url_for('register'))
else:
mongo.db.appname.insert(user)
info['status']['value'] = 'Registered Successfully'
info['status']['positive'] = True
return redirect(url_for('login'))
status_val = info['status']['value']
positive_status = info['status']['positive']
reset()
return render_template('register.html', value = status_val, positive = positive_status)

Django Unit Testing testing views

I am testing my views using Django Unit testing. I am making get and post requests with params to check what status i get back.
But the problem how to check for context variables which are retuned in the response?
For example, on the View Cities page, I make a get request, the context dict in the view has the variable cities. So I want to check for context.
resp = self.client.post(
path=reverse('upload_video'),
data={"video_url": video_url, "pro": 1}
)
self.assertEqual(resp.status_code, 200)
Condition is True both ways, if the form is invalid or valid it returns 200. If I can check for context, then I can check what has been retuned from the view in response.
What I tried
=> resp.__dict__
{'templates': [], '_handler_class': None, '_headers': {'vary': ('Vary', 'Cookie'), 'content-type': ('Content-Type', 'application/json')}, '_charset': 'utf-8', '_closable_objects': [], 'cookies': <SimpleCookie: >, 'client': <django.test.client.Client object at 0x112bace10>, '_base_content_is_iter': False, 'context': None, 'request': {u'CONTENT_LENGTH': 202, u'wsgi.input': <django.test.client.FakePayload object at 0x113667990>, u'REQUEST_METHOD': 'POST', u'PATH_INFO': '/upload/video/modal/', u'CONTENT_TYPE': u'multipart/form-data; boundary=BoUnDaRyStRiNg', u'QUERY_STRING': ''}, '_container': ['{"error": {"msg": "Pro: Select a valid choice. That choice is not one of the available choices.", "head": null}}']}
Check _container has that variable. The form is invalidated, and retuned an error in the context. but when I do the following i get None
=> resp.context
None
Test
import os
from django.contrib.auth import authenticate
from django.core.urlresolvers import reverse
from django.test import TestCase
def test_video_upload(self):
""" Test that video upload is successful """
self.create_and_login(username="su", password="su", is_superuser=True)
video_urls = [
u"https://www.youtube.com/watch?v=abc",
u"https://vimeo.com/32222",
u"http://www.dailymotion.com/video/rer"
]
for video_url in video_urls:
resp = self.client.post(
path=reverse('upload_video'),
data={"video_url": video_url, "pro": 1}
)
set_trace() #Breakpoint
a = resp.context[-1] # <=== Not getting it here.
self.assertEqual(resp.status_code, 200) #passes
videos = Video.objects.all()
self.assertEqual(len(videos), 3)
View
ctx = {}
if request.method == Enums.Request.POST:
video_form = UploadVideoEasyForm(data=request.POST)
if video_form.is_valid():
video, log = video_form.save(request=request)
msg = 'Successfully Uploaded, View: here'.format(video.get_absolute_url())
ctx[Enums.ResponseAlert.Success] = {'msg': msg}
else:
ctx[Enums.ResponseAlert.Error] = make_alert(msg=form_error_to_string(video_form))
return HttpResponse(json.dumps(ctx), content_type="application/json")
elif request.method == Enums.Request.GET:
ctx['upload_video'] = UploadVideoEasyForm()
if request.user.is_authenticated() and request.user.is_superuser:
return render_to_response('new/modals/upload_video.html', context_instance=RequestContext(request, ctx))
Cheers.
The resp (An instance of django.test.Response) should have an context attribute.
You can access context value using context[..]:
self.assertEqual(resp.context['cities'], ...)

JSON data not reaching view pyramid

I'm trying to build a page where when the user presses a button a variable which initially is 0 increments with 1. This number is then sent asynchronously to the server by using jQuery AJAX.
What I have so far is:
In my __init__.py file:
def main(global_config, **settings):
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind = engine)
Base.metadata.bind = engine
config = Configurator(settings = settings)
config.include('pyramid_jinja2')
config.add_static_view('static', 'static')
config.add_static_view('scripts', 'scripts')
# Removed the other views
config.add_route("declare_usage", '/user/{user_id}/{address_id}/declare')
config.add_route("declare_usage_json",'/user/{user_id}/{address_id}/declare.json')
config.scan()
My HTML + Jinja2:
#Removed code for simplicity
<div id="button_add">Add</div>
{{val}}
My JS:
$(document).ready(function(){
var room = 0;
jQuery.ajax({type:'POST',
url: '/user/1/5/declare', #I use a direct user ID and a direct address ID as I'm not sure how to send this to JS from Pyramid ... yet :).
data: JSON.stringify(room),
contentType: 'application/json; charset=utf-8'});
$('#button_add').click(function(){
room = room + 1;
});
});
My view code:
#view_config(route_name = 'declare_usage', renderer = 'declara.jinja2')
#view_config(route_name = 'declare_usage_json', renderer = 'json')
def declara_consum(request):
#Removed code for simplicity
val = request.POST.get('room') #I get a "None value in my html" if I change to request.json_body -> I get an error that there is no json to be parsed.
return { 'val' : val }
What happens is that when I open the debugger the POST request is successful with no data and on the page I get 2 options for 'val':
None -> When I use val = request.POST.get('room')
Error ValueError: No JSON object could be decoded -> When I use val = request.json_body
Also, still can't get it to work if in my JS i change url to be /user/1/5/declare.json and/or data to {'room' : room}
Can somebody please point out what I'm doing wrong?
you don't need another route declare_usage_json, just need separate two function like this
#view_config(route_name = 'declare_usage', renderer = 'declara.jinja2')
def declara_consum(request):
# this will response to your jinja2
return { 'val' : val }
#view_config(route_name = 'declare_usage', xhr=True, renderer = 'json')
def declara_consum_ajax(request):
# this will response to your asynchronously request
val = request.POST.get('room')
return { 'val' : val }
when you send a request using ajax, this will goto the second function.
$.ajax({
type: 'POST',
url: '/user/1/5/declare',
data: {'room' : room},
dataType: 'json'
}).done(function(response){
// update your data at html
});

Django sending data to front-end. 'dict' object has no attribute '_meta'

I have these methods:
def get_all_from_database():
urls = Url.objects.all()
ips = Ip.objects.all()
context = {
'urls': serializers.serialize('json', urls),
'ip': serializers.serialize('json', ips)
}
return context
and the method that sends data to using ajax:
def send_results(request):
if request.is_ajax():
address = request.POST.get('url')
process_data(address, email_to, email_from)
context = get_all_from_database()
return HttpResponse(json.dumps(context), content_type='application/json')
But this raises error : INTERNAL SERVER ERROR 500 'dict' object has no attribute '_meta'.
Wheres the mistake, and how to correct it ?
You cant use serializers.serialize method with dict list that you got from values call:
urls = Url.objects.all().values('address', 'cnt')
Use default queryset:
urls = Url.objects.all()
ips = Ip.objects.all()
In you example context['urls'] value already in json format, and you cant use json.dumps() for json data.
You can use this example:
json.dumps({
'urls': Urls.objects.all().values_list('address', 'cnt'),
'ips': Ip.objects.all().values_list('address', 'cnt')
}), 'json')
urls = Url.objects.all().values('address', 'cnt')
ips = Ip.objects.all().values('address', 'cnt')
The above lines returns dict objects, try:
urls = Url.objects.all().values('address', 'cnt').values_list()
ips = Ip.objects.all().values('address', 'cnt').values_list()
Then you will have urls as a list containing the tuples:
[(address_1, cnt_1), (address_2, cnt_2), ...]
see: QuerySet API reference
I think it should be :
res=json.dumps({
'urls': list(Urls.objects.all().values_list('address', 'cnt')),
'ips': list(Ip.objects.all().values_list('address', 'cnt'))
}), 'json')
return HttpResponse(res,content_type="application/json")

Django & Haystack: Beautify the search url

I have a problem with Django and Haystack. I'm trying to beautify the url (example.com/search/?q=hey in example/search/hey/) as follows:
def go(request):
"""
Search > Beautify
"""
search_query = request.GET.get('q', None)
return HttpResponseRedirect(reverse('search.views.root', kwargs={
'search_query': search_query,
}))
def root(request, search_query):
"""
Search > Root
"""
form = HaystackSearchForm(request.GET)
tutorials = form.search()
return render(request, 'search/search_root.html', {
'search_query' : search_query,
'tutorials' : tutorials,
})
The problem is that it doesn't work because the request for the go function is not the same than the root function. I want to find a way to pass the appropriate request to the HaystackForm (which mean with the query).

Categories