Change configuration setting based on URL in Flask - python-2.7

I am new to Flask, i have three sections in config.py file
say
class Config(object):
DEBUG = False
TESTING = False
DATABASE_URI = 'sqlite://:memory:'
class ProductionConfig(Config):
DATABASE_URI = 'mysql://user#localhost/foo'
class DevelopmentConfig(Config):
DEBUG = True
class TestingConfig(Config):
TESTING = True
And as per documentation we can pass one the config at a time and run the app so the app will run for the passed config settings only.
I am looking changing the config based on url pattern,
so say if url is:
http://127.0.0.1:8080/api/app/hello should use app.config.from_object(ProductionConfig)
http://127.0.0.1:8080/api/app_dev/hello should use app.config.from_object(DevelopmentConfig)
http://127.0.0.1:8080/api/app_test/hello should use app.config.from_object(TestingConfig)
Is it possible while running app i want to change config based on url pattern so that i dont have to run multiple instance of app at time.
Please guide me how can i catch the url pattern in middleware to change configuration file.

It sounds like what you might be looking for is application dispatching, where each app is the same except for the configuration file that is loaded.
here is a solution for a very similar issue, except it uses subdomain dispatching rather than URL dispatching as you have requested.
The basic concept should apply, and taking this together with the examples in the first link should give you a good start for developing code that suits your needs.

You can do this inside a route endpoint
app.config['DEBUG'] = True
but it affects the whole app object. So when you GET /api/app_dev/hello and then /api/app/whatever; you are still using app_dev config.

In config file you can set API
_PATH. and in blueprint you need to set this parameter for required APIs

Related

Changing API endpoint between development and production (React/Django)

I am developing a react app inside of a django project and connect them using the Django rest framework. For making API calls from within the react app I am using axios.
Now in my development environment, I obviously call a localhost URL to access the API. For this, I have a file that contains an axios instance:
import axios from "axios";
export const axiosInstance = axios.create({
baseURL: "http://127.0.0.1:8000/api/",
timeout: 60000,
});
Obviously, my API calls don't work in production as the URL differs from the one above. I am compiling my react app to a static file which I include in my django project so I don't think I could really add any code that checks for the environment.
One idea that I had is that I could include a file into my project that I would not push into production and then check for whether this file exists or not and adjust the url in an if statement. However, I am not sure if that is a good solution or how I would implement this in plain Javascript.
I am happy to hear any thoughts on this
Edit
After thinking about my question, it actually doesn't make any sense - I am compiling my file before committing it so it can't be dynamic anyways. What I actually need is one main.js file which I am using in development and another one that I would use in production. However, I have no idea how I could achieve this as I am not bundling any files in production? Maybe there is a way of always bundling two files - one with the localhost url and the other one with my production url.
I am using the django-webpack-loader application which tells my django application which file to load into the html file. By accessing environment variables, I could arrange that change. But how do I tell webpack to make the two distinct bundles?
I think you could use something like dotenv to access environment variables to configure your baseURL.
This question asks if it is possible, and there are many solutions discussed there, like using .env and configuring it with webpack at build time, mind that with the last one you'll require dotenv-webpack plugin.
// separate js file
baseURL = ""
FirstEndpoint = `${baseURL}/addition/`
...etc
change the baseURL in production.

Recommended way of talking to a Django application URL, from within a view of the same application?

I have a Django application, and need to deal with the following:
One of my views, needs to make a POST request to another URL endpoint of the same application.
In order to do so, I use the requests module. I assemble the URL of the endpoint I need to call, dump the POST parameters, and perform the call.
This works fine for the most part, however fails miserably when testing, since the view that corresponds to the URL that I talk to, knows nothing about the state of the testing environment.
The code is similar to this:
from django.conf import settings
import json
def view1(request, *args, **kwargs):
url = 'http://api.%s/view2/' % settings.DOMAIN
r = requests.post(
url,
data=json.dumps({'key': 'value'}),
)
// Notice that the ``url`` is a url of the actual deployed application,
// and therefore knows nothing about testing and its state. That's where
// it goes wrong.
The question is, is there a way that this can behave correctly in testing? I use the django.test.client.Client class for creating my test requests. As far as I know, instances of this class talk directly to the URL mapper. Therefore the url that I construct in the view is simply an external http request to the deployed application, instead of the tested application.
Thanks.
One way to solve this is to mock the response from the URL for the purposes of the tests. I'd suggest using a lightweight mocking library, such as this:
http://blog.moertel.com/posts/2011-11-07-a-flyweight-mocking-helper-for-python.html
See the example code. It's very similar to your situation. I've used both of these in combination with requests and flask, but not django.

How to alter django settings based on current request?

I'm running multiple sites from a single django instance, and expect the framework to eventually serve several hundred sites from one or several installations.
I need to patch some django settings based on the current request. I've written some middleware to monkey patch the settings, but I need these settings to be patched before the middleware gets invoked because other apps aren't taking the monkey-patched changes (i.e. apps get run then middleware gets run so the apps don't use the monkey-patched settings).
I should also add this is mainly for the benefit of third-party apps that I haven't written, so I don't want to go round adding decorators or anything like that because that would mess up my upgrade path.
So:
How can I get access to the current request in an app's init.py file?
Will an app's init.py get called once per request or only once? If it's only once, how else could I do this so I can manipulate the settings once per request?
Is it safe to do this kind of monkey patching? I know it makes code a bit more opaque, but I don't want to use different wsgi files per site because I want to allow users to edit some of these settings and have my monkey patching come from the database.
Is there a better solution that would allow certain settings to be stored in the database?
This module - django-tupperware does what you are asking about: https://bitbucket.org/jiaaro/django-tupperware/
Give it a try.
Never ever ever change settings on the fly. You cannot predict how the application may one day be deployed, and in most of them the project will fail in.. interesting ways.
If you really want to have hundreds of sites which will be dynamically reconfigured all the time, you might try to Djangos django/conf/__init__.py which is used to supply the settings to the rest of the framework. You might be able to alter it in a way it depends on the request and it's Host field. Or you'll get many interesting failures at the very least.
My solution to this problem is to give each request, ALL the settings and update them on the fly with a middleware, how do i do this?
Is rather simple:
This is the middleware that does it all
from django.conf import settings
class DumpObject: pass
class Settings(object):
def process_request(self,request):
request.settings = DumpObject()
for setting in dir(settings):
if not setting.startswith('__'):
setattr(request.settings, setting, getattr(settings,setting))
The DumpObject is just there so i can use the object.property notation, it could have been a dictionary, but i wanted to keep some similarity in the syntax.
This assumes that none of your settings name starts with __ which is a fair assumption.
So if i want to override a particular setting, i don't keep a settings file i do it in this middleware. like this:
class Settings(object):
def process_request(self,request):
request.settings = DumpObject()
for setting in dir(settings):
if not setting.startswith('__'):
setattr(request.settings, setting, getattr(settings,setting))
if 'mydomain' in str(request.host): #this is thanks to django-hosts project
request.settings.GOOGLE_ANALYTICS_ID = '89298393-238'
Of course this doesnt take into account the problem of accessing the settings the old way
from django.conf import settings
settings.GOOGLE_ANALYTICS_ID = 'the value in settings.py'
But it really doesn't matter because you will probably only want to change the settings on the context of having a request object, available.

How to make Django url dispatcher use subdomain?

I have a vague idea on how to solve this, but really need a push :)
I have a Django app running with apache (mod_wsgi). Today urls look like this:
http://site.com/category/A/product/B/
What I would like to do is this:
http://A.site.com/product/B
This means that the url dispatcher some how needs to pick up the value found in the subdomain and understand the context of this instead of only looking at the path. I see two approaches:
Use .htaccess and rewrites so that a.site.com is a rewrite. Not sure if this does the trick since I don't fully understand what the django url dispatcher framework will see in that case?
Understanding how the url dispatcher DO work I could write a filter that looks at valid sub domains and provides this in a rewritten format to the url dispatcher code.
Any hints or solutions are very much appreciated! Thanks.
Have you looked at django.contrib.sites? I think a combination of that, setting SITE_ID in your settings.py, and having one WSGI file per "site" can take care of things.
EDIT: -v set.
django.contrib.sites is meant to let you run multiple sites from the same Django project and database. It adds a table (django.contrib.sites.models.Site) that has domain and name fields. From what I can tell, the name can mean whatever you want it to, but it's usually the English name for the site. The domain is what should show up in the host part of the URL.
SITE_ID is set in settings.py to the id of the site being served. In the initial settings.py file, it is set to 1 (with no comments). You can replace this with whatever code you need to set it to the right value.
The obvious thing to do would be to check an environment variable, and look up that in the name or domain field in the Site table, but I'm not sure that will work from within the settings.py file, since that file sets up the database connection parameters (circular dependency?). So you'll probably have to settle for something like:
SITE_ID = int(os.environ.get('SITE_ID', 1)
Then in your WSGI file, you do something like:
os.environ['SITE_ID'] = 2
and set that last number to the appropriate value. You'll need one WSGI file per site, or maybe there's a way to set SITE_ID from within the Apache setup. Which path to choose depends on the site setup in question.
The sites framework is most powerful where you use Site as the target of a ForeignKey or ManyToManyField so that you can link your model instances (i.e. records) to specific sites.
Mikes solution is correct if you want to have multiple sites with same apps with different content (sites module) on multiple domains or subdomains, but it has a drawback that you need to be running multiple instances of the Django process.
A better solution for the main problem about multiple domains or subdomains is to use a simple middleware that handles incoming requests with the process_request() function and changing the documented urlconf attribute (link) of the request object to the URLconf you want to use.
More details and an example of the per-request or per-domain URL dispatcher can be found at:
http://gw.tnode.com/0483-Django/
Try adding a wildcard subdomain: usually *.

How do I set the Application Id in appengine?

I'm using Django along with appengine. When I try to save a record, I'm getting the error
"app_id must not be empty". The application name has been set in app.yaml. I also added
os.environ['APPLICATION_ID'] = 'test' in main.py. However, I continue to get the same error.
When I try to save a record, I'm getting the error "app_id must not be empty".
When I'm using appengine as "standalone" e.g. (unit testing) in order to fix the "app_id must not be empty" error I always execute:
app_id = 'XXXXXX'
os.environ['APPLICATION_ID'] = app_id
datastore_path = os.path.join(tempfile.gettempdir(),'dev_appserver.datastore')
history_path = os.path.join(tempfile.gettempdir(),'dev_appserver.datastore.history')
require_indexes = False
apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap()
datastore = datastore_file_stub.DatastoreFileStub(app_id, datastore_path, history_path, require_indexes=require_indexes)
apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', datastore)
just before my code that use the Google App Engine datastore.
If you run the appserver locally you shouldn't need this code because all the magic is made by the framework reading the app.yaml file
I haven't seen your error before. Note that you can't use the native Django database functions without using the "Django Helper" application:
http://code.google.com/appengine/articles/appengine_helper_for_django.html
You do not need to use Django Helper if you are only using parts of Django (but using native App Engine Models for storage):
http://code.google.com/appengine/docs/python/datastore/overview.html