How I can make module connecting to external REST api? - django

I am doing simple app which has to connect to external REST api, get data in json and print it for the user. My questions are:
Where should I put/create a module which will connect to external REST api? I mean I could just write some code in views.py which connects to REST api and the passes the results to template but I want to separate it in some autonomic module which I could use in views.py like myapimodule.get_devices() which for example will connect and get data from example.com/api/device/get. I tried python and django for first time today so I just want to know where u put (and how) such modules in django app?
How I can connect to RESTAPI with django? I have for example username and password for http auth and address like example.com/api/device/get - what parts of django lib will allow me to use the restapi and retrieve data from it (in json format)?

There's really no "right" answer. It just depends on what's best for your needs.
To connect to an external REST API, take a look at the excellent Requests library.

The Requests library is worth learning. It will save you a lot of grief.
Did you try:
pip install chardet
before
pip install requests
?

Related

Connecting to mongo cloud using mongoengine

I have written a web app in django using mongoengine as a driver and am trying to host my database on mongodb cloud. In mongoengine's connect() method, according to what I understood from the documentation, specifying the url (specified in the connect section on the mongo cloud site) in the hostname argument should do the trick, however requests from the app to the mongo cloud keep timing out.
Where am I going wrong?
This is the call to the connect method in my setting.py file-
mongoengine.connect(db='scheduler', host='mongodb+srv://<user>:<password>#cluster0.oualt.mongodb.net/<db name>?retryWrites=true&w=majority')
Update: the specific error thrown on using the above url is this-
ServerSelectionTimeoutError
If you're using just mongoengine then Django will not detect that connect to the database, so you will not be able to use the Django ORM system to save instances of models etc.
If you want to use the ORM you would have to use a package like Djongo or djmongoengine
However, if you're not planning to use the ORM system then you can use just mongoengine.
I believe the connect url should be in this format:
mongodb+srv://<username>:<password>#<database-name>.mongodb.net/test?retryWrites=true&w=majority
Right now you seem to have the url to a specific cluster on your database.
So I was going through similar posts which had the same error ServerSelectionTimeoutError with djongo and pymongo as the drivers and one of the posts said that they had forgotten to whitelist their IP address on the mongo cloud site. I had done that during signup, but I repeated it anyways and for some reason the IP address was different and after that had been whitelisted, my app connected and started working. I have no explanation.
mongoengine works fine, but in terms of protocols you need another ext file that serves for your connection protocols, just pip install pymongo[srv]
def register_database(db_name:str):
connect(db=f"mongodb+srv://<username>:<password>#<cluster-name>.nwr5l.mongodb.net/{db_name}?retryWrites=true&w=majority", alias="default")

Advantages of using REST API framework over simple URL and view creation in Django?

It might be a silly question for many, but why can't I instead
Create a view in django that takes a request and returns HttpResponse in, say, JSON format
Map the view to a URL
Hit the URL from my browser or another server and use the result?
Thanks.
EDIT - Two approaches: Import some djangorestframework or tastypie and build an api in my application which will throw json responses VS building a view and tell it to return json response. Is there any huge advantage of using the first one?
I think you could make the same argument about any extension library. It just depends on how much you want to rebuild and what the existing library has that would be beneficial to your project.
Many times I've created custom endpoints without an API library when working with ajax requests inside my project. For that instance, using an API package is overkill. But for having a full API server, Django rest framework offers a lot of functionality.
Sure, you can make views that do what you suggested. But at some point are you going to want to authenticate through an HTTP request? Are you going to want to filter? Are you going to want to make permissions, or just have all endpoints open? Are you going to want to protect against CORS?
You can kind of go down the list of all the features of an API library and ask these questions about what you want to accomplish with your project. If you're working with any type of external application and your django project is just for an API server, usually it's best to go with Rest Framework. If you just have some one-off endpoints to receive ajax requests, usually you just want to build custom endpoints.

python-social-auth failure on Google App Engine

I am attempting to follow Tutorial: Adding Facebook/Twitter/Google Authentication to a Django Application. The only thing I am doing differently is that I am running DjangoAppEngine on the Google App Engine development server, otherwise everything is exactly as per the tutorial.
When I get to Step 4 and actually try to authenticate with Facebook, I am getting a runtime error:
error('illegal IP address string passed to inet_pton',)
Request Method: GET
Request URL: http://localtest.com:8080/o/complete/facebook/?redirect_state=FG4K...UG1k
Django Version: 1.6.11
Exception Type: RuntimeError
Exception Location: /Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/remote_api/remote_api_stub.py in _MakeRealSyncCall, line 235
Python Executable: /usr/local/opt/python/bin/python2.7
Python Version: 2.7.11
Obviously FB is passing an approval back to my app, as the request URL includes the callback path.
It appears that something in the GoogleAppEngineLauncher is trying to look up an address and is not receiving the right data in? I'm not really sure.
In trying to resolve this, I've come across a single comment somewhere suggesting to a user that SimpleAuth might be a better way to go, but I don't understand why and I'm not really sure I want to start over if I am just missing something obvious.
Does anyone know why I am getting this error and what I can do to correct it?
It happens because the Facebook SDK depends on the awesome requests library. However, requests doesn't work on Google App Engine since the platform has some restrictions. You have to use their urlfetch APIs to fetch external contents on Google App Engine.
So yes, the official Facebook SDK won't work. You have to roll your own solution or find one that works. SimpleAuth is one of the solution that is known to have worked.
UPDATE: the original answer (starting with 'HOWEVER') is no longer necessary, just use requests 2.10.0 or above, urllib3 1.15.1 or above, and requests_toolbelt 0.6.2 or above and perform the following in your main():
from requests_toolbelt.adapters import appengine
appengine.monkeypatch()
HOWEVER if you're using older versions of requests and/or urllib3, then you need the patches below:
This can be accomplished using a patched version of requests along with the requests-toolbelt package. Threads that apply:
HTTPS not working on Google App Engine #1905
urllib3 / Contrib Modules / Google App Engine
Fixes the AppEngineManager to work within the requests framework #763
Add AppEngineAdapter for GAE users #114
Adds a monkeypatch() function that ensures all Sessions use the AppEngineAdapter compatibility class. #119
I've applied all of this and now have python-social-auth and facebook-sdk working in both local test (the dev server) and production (full App Engine).
In your vendored libraries, ensure that you have requests_toolbelt. (pip install -t lib requests_toolbelt). Then "monkeypatch" appengine support before python-social-auth ever calls requests. In my project/wsgi.py, I added the following lines:
from requests_toolbelt.adapters import appengine
appengine.monkeypatch()
python-social-auth depends on requests, so it should also exist in your vendor directory.
You must also ensure you are using requests version >= 2.10.0. This has not been released yet, so you can fake it. Edit lib/requests/__init__.py so that __build__ = 0x021000. You also must upgrade the packaged version of urllib3 in the lib/requests/packages/ directory to the latest version.
This is what worked for me.

Live notification/chat in django

I am making a website with django now and I want to implement a live notification feature like the one on facebook or SE.
I did some research and it seems although there's two options: ajax long polling and websockets, the latter is the way to go.
However, as you know the go to plugin for websocket 'socket.io' turns out to be a node.js plugin and the django port only seems to support python 2 and the project seems pretty much dead. I am using python 2.7 as my project interpreter but I want to future proof myself so that if I upgrade to python3 later, I don't find myself not being able to use this functionality.
So my question is this:
Is there a straight forward and future ready way to implement websocket which will be used to send live notifications and chats in django env?
Django itself is build in blocking manner, i.e. with synchronous approach. So, you cannot open persistent websocket with django app, as it will block entire django thread.
If you want to enable notification/chat within django project environment, i would recommend to use centrifuge. It is written in python, but async (non-blocking) framework is used: tornado.
But, you don't need to even know how it works, as it provides simple REST api to communicate with it.
Simplified workflow, check docs for more details:
Start centrifuge at same server, as your django project (or on another but with low latency between them)
Your front-end will open websocket with centrifuge, not with django project.
When you need to send notification, send it to centrifuge from django via REST api, and centrifuge will deliver it to needed clients!
I've already tried it and it works!
Django doesn't provide what you're looking for out of the box. You'll have to use a third party library. One that works across frameworks is Pusher.
I think you must go for Firebase it gives you awesome synchronization and any how you are going to use chat on frontend so its does not have to do anything with django environment so you can update you backend asynchron in callback with firbase. Also firebase with AngularJS provides you really really awesome three way binding.

Should my web based app be a consumer of my api?

I will be developing a mobile app (iPhone) and a web based app (Django) soon. For the mobile app I will be creating a REST api (most likely using Django) to send data back and forth from phone to server.
When I comes time to create the web based version does it make sense to just create it as any other client of the api. In other words both the mobile app and the web app will get there data from an external API over HTTP. Or should the web based app have direct access to the database that the api is using and just get its data that way?
Break it into three "sections". The first uses a Python API to manipulate the database. The second interfaces your REST API with your Python API. The third talks web and uses the Python API.
I would create the web application to serve the API to the mobile client. That is, give the web based application direct access to the database. This will simplify your XML / JSON RESTful resource access.
I would say no, don't use the API for the HTML version. If you design your Django well, you can end up with less code than using the API for the HTML version. You also get to retain the ability to have a web designer work with the Django templates whenever the boss wants the spelling changed on something.
I'd suggest trying to define a base app for your iPhone app to interface with, and then extend that within a second app for the HTML version. App1 would have all of your models (including business logic), and a views.py for processing the data to/from the iPhone. Then create App2 which uses App1.models, but creates its own views.py. With any luck, you'll find yourself with the ability to change nothing but the template used to render the output, so you can reuse your views by passing the template as an argument.
For example:
App1.views:
def list(request, template="list.json"):
list = Model.objects.filter(deleted=False).filter(user=request.user)
list.reverse()
## Lots of other logic to work on the list.
return render_to_response(template, {list: list,})
App2.views:
def list(request, template="list.html"):
return App1.views.list(request, template=template)
I think the answer to this question has changed over time. A year ago when asked it was probably still too much hassle to do this, but now I'd definitely say yes - using your API as the basis is the smart thing to do. As Web sites use more HTML5 and Mobile apps get smarter it really makes sense to have all your "UIs" read/writing from the same API layer. This will give you much more flexibility in the future.