Django open an external link passing POST data - python

In my Django project i need to call from my function into my views.py an external page passing in POST format some data.
i do this:
in urls.py:
...
url(r'^gocard/(?P<lic_num>\w+)/$', go_ccredit),
...
in my views.py i create the function go_ccredit:
def go_ccredit(request, lic_num=None, **kwargs):
requests.post('https://www.example.com/form_test', data={'lid':lic_num,})
but i got an error because no HTTPResponse vas returned, and no page was open.
I need to open an external page because i need to populate some form field with my data (using POST) and some other have to be populated by user.
How can i open from my django function my external page passing data in POST ?
So many thanks in advance

Related

Send user data in python requests module

I am unable to send the user details along with requests module i had to hard code the user details in the data payload to identify the user.
full_url = ''.join(['http://', get_current_site(request).domain, '/am/reply'])
data = {
'agent_type':'trigger',
'input':platform,
'userid':request.user.id ####==>> had to send userid like this
}
a = requests.get(full_url,params=data)
Is there way to send all general request data using requests.?
And moreover the requests url the destination view i have implemented
def index(request):
if not request.user.is_authenticated:
return HttpResponseRedirect(reverse('login'))
And request.user.id is none when url is reached through requests module
In general how should i validate a request when using requests module
Django uses request and response objects to pass state through the system.
When a page is requested, Django creates an HttpRequest object that contains metadata about the request. Then Django loads the appropriate view, passing the HttpRequest as the first argument to the view function. Each view is responsible for returning an HttpResponse object.
Some of the middleware included in Django’s contrib apps set attributes on the request. If you don’t see the attribute on a request, be sure the appropriate middleware class like authenticationmiddleware,sessionmiddleware.
Following piece of code will give the user.id if and only if the user is authenticated.
def myview(request):
if request.user.is_authenticated:
print request.user.id
else:
... # Do something else.
https://docs.djangoproject.com/en/1.10/ref/request-response/
If I understood your question correctly, You are getting request in one view, and then making a call to other view using requests module. It that case the request object in index view will be totally different because that request was sent from your server where application works, not from user. You can only get data in index view using request.GET.get("userid") and so on. And then if you will need user info, just fetch it again from database using userid. Passing request object to other view using requests library is not possible.

Add upload file functionality in Django Admin

I have seen multiple replies for how to upload a file through Django ADMIN interface
There were two kind of replies:-
A) using django inline classes, as mentioned in link_A and link_B. I followed link_A
But for some reason it did not work for me. So is there something missing in the above links mentioned?
I am not sure what is the purpose of following code block in the link_A:-
def save(self, *args, **kwargs):
if not self.id:
... unzip your file ...
... encrypt your file if necessary ...
super(File, self).save(*args, **kwargs)
Question:- Django admin shall automatically perform a SAVE functionality for you. So, what is the purpose of the above SAVE function when DJANGO ADMIN shall automatically do it for you?
B)using upload file functionality in normal DJango code(Not Django admin). I followed the link. It mentions to write a View that handles a POST request. And using a ModelForm save it and render the view again
What I did:- Added a FileField() button file = models.FileField(storage=fs).
My understanding:- Normal Django code(Not DJANGO Admin), we have to write ModelForms and VIEWS to handle HTTP respnose and request methods. But Django admin hides HTTP response and request functionality from the end user. Somehow it performs handling of HTTP request and HTTP response behind the scene. So me bypassing Django admin and trying to manually capture POST request(just for file upload) as mentioned in the link does not sound right.
From my point of view I just need to add a FileField() button to the DJANGO ADMIN. When i hit the SAVE button DJANGO ADMIN should handle POST request behind the scene as it does for normal model fields.
Question:- Is my understanding of how a file should be uploaded using Django ADMIN interface correct?

Import excel data into models via django admin

I need the Django Admin interface to accept administrator uploads of Excel files where the data in each Excel file is inserted into my database models. How can I make such an “Upload” button appear on a Django model admin page, where clicking the button asks the administrator to choose an .xls file, whose data then gets added to database once its upload is complete?
I have done this, but I just set up a simple view with a file upload (actually this makes more sense than adding it directly into a Django admin page, as one edit page = one model instance,and I assume that your excel contains multiple models).
in forms.py, a simple form with a file upload field
class ImportExcelForm(forms.Form):
file = forms.FileField(label= "Choose excel to upload")
in views.py, a view to process the upload
def test_flowcell(request):
c = RequestContext(request, {'other_context':'details here'})
if request.method == 'POST': # If the form has been submitted...
form = ImportExcelForm(request.POST, request.FILES) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
excel_parser= ExcelParser()
success, log = excel_parser.read_excel(request.FILES['file'] )
if success:
return redirect(reverse('admin:index') + "pages/flowcell_good/") ## redirects to aliquot page ordered by the most recent
else:
errors = '* Problem with flowcell * <br><br>log details below:<br>' + "<br>".join(log)
c['errors'] = mark_safe(errors)
else:
c['errors'] = form.errors
else:
form = ImportExcelForm() # An unbound form
c['form'] = form
return render_to_response('sequencing/file_upload.html')
and as suggested in the other post use xlrd to read the data in from the excel file. I have a separate file ExcelParser.py for this
import xlrd
class ExcelParser(object, excel_name):
#transaction.commit_on_success
def read_excel(self):
wb = xlrd.open_workbook(excel_name)
...
do your parsing in here.....
...
(May I add, that excel is a terrible, and error prone way to import data. I do a lot of it at my work, and am trying to convince management that there are far better solutions.)
I'm not sure about the Django side of things, but you can use xlrd to read and manipulate Excel files. There is a free PDF which explains this called Working with Excel files in Python
django-import-export could be helpful.
It creates two buttons "import" and "export" for admin objects and permits select many types of extensions, including xls. It also show the data do be imported and asks to be confirmed before execute the execution.
You just need to include it in INSTALLED_APPS and create an import-export resource of the class you want to upload and a subclass of ImportExportModelAdmin related to the resource class created before to show buttons in admin.
more info at:
http://django-import-export.readthedocs.org/en/latest/getting_started.html
https://github.com/bmihelac/django-import-export.

Ajax form handling in django admin

I have two models:
class Customer(models.Model):
(...)
class CustomerMemo(models.Model):
(...)
customer = models.ForeignKey(Customer)
text = models.TextField()
And in my admin.py
class MemoInline(admin.StackedInline):
model = CustomerMemo
class Customer(admin.ModelAdmin):
(...)
inlines = (MemoInline,)
I want to make autosave for these inline fields.
I think there should be ajax request every 30 seconds.
But now there two questons:
How to make ajax request which gets requred data from admin page?
How would be better to add admin custom view which handle this ajax request?
I've read about dajax, but I can't get how it could help me with my task.
Thanks
Redefine admin template and add a JS with some function which will gather form data with $(form).serialize() and make an ajax POST to the server. URL for POST can be admin page itself (if you don't mind overwriting the object) or you can write your own view with necesssary form and formsets. Maybe you'll also need to add value of the "Save" button to POST load.

How to redirect with post data (Django)

When processing a POST request in the Django views.py file, I sometimes need to redirect it to another url. This url I'm redirecting to is handled by another function in the same Django views.py file. Is there a way of doing this and maintaining the original POST data?
UPDATE: More explanation of why I want to do this.
I have two web apps (let's call them AppA and AppB) which accept data entered into a text field by the user. When the the user clicks submit, the data is processed and detailed results are displayed. AppA and AppB expect different types of data. Sometimes a user mistakenly posts AppB type data to AppA. When this happens I want to redirect them to AppB and show the AppB results or at least have it populated with the data they entered into AppA.
Also:
The client wants two separate apps rather than combining them into just one.
I can't show the code as it belongs to a client.
UPDATE 2:
I've decided that KISS is the best principle here. I have combined the two apps into one which makes things simpler and more robust; I should be able to convince the client it's the best way to go too. Thanks for all the great feedback. If I was going to maintain two apps as described then I think sessions would be the way to do this - thanks to Matthew J Morrison for suggesting that. Thanks to Dzida as his comments got me thinking about the design and simplification.
If you faced such problem there's a slight chance that you might need to revise your designs.
This is a restriction of HTTP that POST data cannot go with redirects.
Can you describe what are you trying to accomplish and maybe then we can think about some neat solution.
If you do not want use sessions as Matthew suggested you can pass POST params in GET to the new page (consider some limitations such as security and max length of GET params in query string).
UPDATE to your update:)
It sounds strange to me that you have 2 web apps and those apps use one views.py (am I right?). Anyway consider passing your data from POST in GET to the proper view (in case data is not sensitive of course).
I think how I would probably handle this situation would be to save the post data in session, then remove it when I no longer need it. That way I can access the original post data after a redirect even though that post is gone.
Will that work for what you're trying to do?
Here is a code sample of what I'm suggesting: (keep in mind this is untested code)
def some_view(request):
#do some stuff
request.session['_old_post'] = request.POST
return HttpResponseRedirect('next_view')
def next_view(request):
old_post = request.session.get('_old_post')
#do some stuff using old_post
One other thing to keep in mind... if you're doing this and also uploading files, i would not do it this way.
You need to use a HTTP 1.1 Temporary Redirect (307).
Unfortunately, Django redirect() and HTTPResponseRedirect
(permanent) return only a 301 or 302. You have to implement it yourself:
from django.http import HttpResponse, iri_to_uri
class HttpResponseTemporaryRedirect(HttpResponse):
status_code = 307
def __init__(self, redirect_to):
HttpResponse.__init__(self)
self['Location'] = iri_to_uri(redirect_to)
See also the django.http module.
Edit:
on recent Django versions, change iri_to_uri import to:
from django.utils.encoding import iri_to_uri
use requests package.Its very easy to implement
pip install requests
then you can call any urls with any method and transfer data
in your views import requests
import requests
to post data, follow the format
r = requests.post('http://yourdomain/path/', data = {'key':'value'})
to get the absolute url in django view, use
request.build_absolute_uri(reverse('view_name'))
Thus the django view code looks like
r = requests.post(
request.build_absolute_uri(reverse('view_name')),
data = {'key':'value'}
)
where r is the response object with status_code and content attribute.
r.status_code gives the status code(on success it will be 200) and r.content gives the body of response. There is a json method(r.json()) that will convert response to json format
requests
requests.post
Just call your new view from your old view using the same request object.
Of course it won't result in a redirect as such, but if all you care about is 'transferring' data from one view to the other, then it should work.
I tested the following snippet and it works.
from django.views.generic import View
class MyOldView(View):
def post(self, request):
return MyNewView().post(request)
class MyNewView(View):
def post(self, request):
my_data = request.body
print "look Ma; my data made it over here:", my_data
You can use render and context with with it:
Render(request,"your template path", {'vad name' : var value}
You can recive vars in template :
{% If var name %}
{{ var name }}
{% endif %}
I faced a similar issue recently.
Basically I had a form A, upon submitting it another form B would show up, which contains some results + a form. Upon submitting B, i wanted to display some alert to user and keep user on B only.
The way I solved this, is by displaying the results in a <output> field, in B.
<output name="xyz" value="xyz">{{xyz}}</output>
And I used the same view for A->B and B->B. Now I just had to distinguish if the request is coming from A or B and render accordingly.
def view1(request):
if "xyz" in request.POST:
# request from B
# do some processing
return render(request, 'page.html', {"xyz":request.POST["xyz"]})
else:
# request from A
res = foo() # some random function
return render(request, 'page.html', {"xyz":res})
But this only works if form B is small and not that dynamic.
If you are using a redirect after processing the POST to AppB, you can actually get away with calling the AppB method from the AppA method.
An Example:
def is_appa_request(request):
## do some magic.
return False or True
is_appb_request = is_appa_request
def AppA(request):
if is_appb_request(request):
return AppB(request)
## Process AppA.
return HttpResponseRedirect('/appa/thank_you/')
def AppB(request):
if is_appa_request(request):
return AppA(request)
## Process AppB.
return HttpResponseRedirect('/appb/thank_you/')
This should yield a transparent experience for the end-user, and the client who hired you will likely never know the difference.
If you're not redirecting after the POST, aren't you worried about duplicate data due to the user refreshing the page?
You can redirect with session using request.session["key"] as shown below:
# "views.py"
from django.shortcuts import redirect
def my_view(request):
# Here
request.session["message"] = "success"
return redirect("https://example.com")
# "index.html"
{{ request.session.message }} {# success #}

Categories

Resources