I’m new to django programming, not python, and could do with a hand.
I am attempting to make a website exclusive to a certain device. I have created a disallow page accessible by '/disallow/'. How do I go about running os/browser checks that then redirect in the event the os/browser is not on the verified list.
I know the information I am wanting to check will be in the request and I can use
request.META['HTTP_USER_AGENT']
However where do I write any logic required and how could I apply this to any page the user tries to access.
Any help would really be appreciated
Ed
You'll want a Django middleware. It sits in front of all response handlers, so it can capture every request and take any action on it that you require.
Simple example (untested), a function that returns a function:
your_app/middleware.py
def restrict_middleware(get_response):
def middleware(request):
if request.META['HTTP_USER_AGENT'] == ...:
return redirect('/disallow/')
else:
return get_response(request)
return middleware
Then register your_app.middleware.restrict_middleware in the MIDDLEWARE array in your settings file.
Note that such browser/OS detection relies on what the browser/OS itself is claiming that it is, and can easily be spoofed on the client. So don't use this for any security purposes.
Related
I am working on a small Pyramid web application (Python). One requirement is that the user resets the password after a fixed period of time, say, once a year. (I don't consider this requirement to help in terms of security, however, the customer's internal policy requires it.)
The password update should take place after a successful login. It is easy to add the logic to display the update password dialog after the login, but it is also possible that the user just navigates away using a bookmarked URL or the like.
What I would need to do is to overwrite the routing rules based on a property of the logged in user. However, the routing configuration seems to be just a set of static rules in Pyramid.
Is there a way to overwrite the routing rules based on the user's state, so that all requests to other views are forwarded/redirected to the password update dialog?
Assuming you have class based views and that you have set a session variable is_password_recent which is True if less than one year ago, you could put the following into each class's __init__():
class UserViews:
def __init__(self, request):
self.request = request
if not request.session["is_password_recent"]:
raise HTTPFound(
location=request.route_url(
"password_renew", _query={"return": request.path}
)
)
You could probably DRY it, too, by putting the logic into a method in a utils module and import it.
I found a solution using Pyramid events:
from pyramid.events import NewRequest, subscriber
#subscriber(NewRequest)
def intercept(event):
# use event.request to check if an interception/redirect is required
raise HTTPFound(location='route_to_form')
It is important to check the incoming request thoroughly. For example, paths including the route being used further in the process must be excluded, otherwise the application ends up in an infinite loop.
I have a view function that initiates user login requests
it looks something like this:
def initiate_login(request):
# get request parameters
return check_user_and_send_otp(login_id)
The request is then processed by another function
def check_user_and_send_otp(login_id):
# check if user exits
return send_otp_to_user(phone_number)
And then another function
def send_otp_to_user(phone_number):
# sends a message to user
return response
The problem is while testing my code, I don't want to send messages to a phone number while testing.
My login test function looks somewhat like this, is it possible to mock it without changing my code?
def test_login_initiator(self):
response = self.client.post(self.login_url, data=self.login_data, content_type="application/json", **self.headers)
self.assertEqual(response.status_code, 200)
All these functions that were called by others are located in seperate modules
If you don't want to actually receive the message on a physical phone, you can use online sms receivers. Check out this blog.
Additionally, you can send messages through other free online services like Way2sms. You just have to google them up. To do this from within Python, you need to use web parsing using urllib2/requests and beautifulsoup, which is a totally new question.
Or you can skip this function by simply commenting out the message sender code or returning true from the function.
If you wanna live dangerously, think about making a config file which can help you to make switches that tell whether to execute something or not.
The right thing to do would be use something like magic mock and structure the code into proper classes so that we can create mock objects for each of them.
I am new to Flask.
I have a public api, call it api.example.com.
#app.route('/api')
def api():
name = request.args.get('name')
...
return jsonify({'address':'100 Main'})
I am building an app on top of my public api (call it www.coolapp.com), so in another app I have:
#app.route('/make_request')
def index():
params = {'name':'Fred'}
r = requests.get('http://api.example.com', params=params)
return render_template('really_cool.jinja2',address=r.text)
Both api.example.com and www.coolapp.com are hosted on the same server. It seems inefficient the way I have it (hitting the http server when I could access the api directly). Is there a more efficient way for coolapp to access the api and still be able to pass in the params that api needs?
Ultimately, with an API powered system, it's best to hit the API because:
It's user testing the API (even though you're the user, it's what others still access);
You can then scale easily - put a pool of API boxes behind a load balancer if you get big.
However, if you're developing on the same box you could make a virtual server that listens on localhost on a random port (1982) and then forwards all traffic to your api code.
To make this easier I'd abstract the API_URL into a setting in your settings.py (or whatever you are loading in to Flask) and use:
r = requests.get(app.config['API_URL'], params=params)
This will allow you to make a single change if you find using this localhost method isn't for you or you have to move off one box.
Edit
Looking at your comments you are hoping to hit the Python function directly. I don't recommend doing this (for the reasons above - using the API itself is better). I can also see an issue if you did want to do this.
First of all we have to make sure the api package is in your PYTHONPATH. Easy to do, especially if you're using virtualenvs.
We from api import views and replace our code to have r = views.api() so that it calls our api() function.
Our api() function will fail for a couple of reasons:
It uses the flask.request to extract the GET arg 'name'. Because we haven't made a request with the flask WSGI we will not have a request to use.
Even if we did manage to pass the request from the front end through to the API the second problem we have is using the jsonify({'address':'100 Main'}). This returns a Response object with an application type set for JSON (not just the JSON itself).
You would have to completely rewrite your function to take into account the Response object and handle it correctly. A real pain if you do decide to go back to an API system again...
Depending on how you structure your code, your database access, and your functions, you can simply turn the other app into package, import the relevant modules and call the functions directly.
You can find more information on modules and packages here.
Please note that, as Ewan mentioned, there's some advantages to using the API. I would advise you to use requests until you actually need faster requests (this is probably premature optimization).
Another idea that might be worth considering, depending on your particular code, is creating a library that is used by both applications.
I am making an app that would translate websocket messages to AJAX requests to the server. Mainly the decision is based on the fact that Pyramid already has a good URL dispatch system and it would be stupid not to use it.
The question is if there is an easy way to dispatch a URL in Pyramid (possibly an instanced Request object) to it's according view callable and get the view callable? Or at least get the output of the view callable related to the request?
I have tried the script from "prequest.py" which basically emulates a whole HTTP client and gives you the response (I have still not managed to get it work, but a look through the sources makes sense anyway) and I wouldn't like to do it that way.
You can reuse the code from the pview command to turn a path into a view reference:
from pyramid.scripts.pviews import PViewsCommand
pvcomm = PViewsCommand([])
view = pvcomm._find_view(path, request.registry)
The actual code to do this is a little involved, but the PViewsCommand does it all for us already.
I have managed to do it using Router.invoke_subrequest in the latest version of Pyramid (1.4a1).
This enables all the features related to routing. URL dispatch, parameter passing, tweens.
You can read about it here: http://docs.pylonsproject.org/projects/pyramid/en/latest/api/request.html#pyramid.request.Request.invoke_subrequest
I have just started looking at web2py, so many things in the approach are nwe, such as the use of defaults for views etc.
I spent many hours trying to figure out how to get people to log in and in the end put
#auth.requires_login()
at the start of a controller method. This magically brought up a registration form after which the new user was logged in.
I am not sure I fully understand what is going on behind the scenes, but one step at a time.
However, I would like to provide a logout button and have no idea how that might be achieved. Clearly I need to somehow call the default logout. So I need to add a url to the submit form/button and presumably create a controller to match the url, but what will the method to logout look like?
In the user method are the exposes statements, but no idea what they mean or how to use them. All those dots confuse me.
I spent many hours trying to figure out how to get people to log in
Did you read this section of the book? It explains the use of #auth.requires_login() and how the default user() function works to expose the login functionality (as well how to create a separate action specifically for login if desired). In the scaffolding application, the default.py controller includes the following user() function to expose all of the Auth actions:
def user():
return dict(form=auth())
In a URL like "/myapp/default/user/[action]", the requested Auth action (i.e., the last element of the URL) will be available in request.args[0]. When the above function calls auth(), the Auth __call__() method reads the action from request.args[0] and then calls the appropriate Auth method. If the URL is "/myapp/default/user/login", auth() will ultimately call the auth.login() method, which will return (and handle the processing of) the login form. You can also call auth.login() directly if you want to create your own custom login action.
Similarly, the URL "/myapp/default/user/logout" will ultimately call the auth.logout() method, which will log out the user. So, if you want to enable logout, just generate a link to the logout URL -- the best way is to use the URL() function:
A('Logout', _href=URL('default', 'user', args='logout'))
Note, in the scaffolding application, the layout.html view uses auth.navbar() to insert the Auth navbar in the upper right of the page -- when a user is logged in, that navbar automatically includes a "Logout" link like the one above.