I need to store an object on my flask.Flask instance. The naive approach would be just assigning an attribute like this.
app = flask.Flask(__name__)
app.my_object = MyObject()
I'm planning on referencing it later in an application context like this:
flask.current_app.my_object
I doubt this method is thread save though. Is there a correct method to do this that is encouraged by Flask? If not, how would you safely implement the approach above?
I ended up with using the config object.
app.config['MY_OBJECT'] = MyObject()
You can reference it like this in a request.
current_app.config['MY_OBJECT']
Related
I've registered the flask-mongoengine extension in my Flask app and initialized it.
I now want to access its conn property as I want to do pure MongoDB queries too.
>> app.extensions
{'csrf': <flask_wtf.csrf.CSRFProtect object at 0x00000213B72AB940>,
'mail': <flask_mail._Mail object at 0x00000213B72ABCF8>,
'mongoengine': {
<flask_mongoengine.MongoEngine object at 0x00000213B72ABDD8>: {
'app': <Flask 'app'>,
'conn': MongoClient(host=['xxx'], document_class=dict, tz_aware=False, connect=True, ssl=True, replicaset='Cluster0-shard-0', authsource='admin', retrywrites=True, read_preference=Primary())
}
},
'rq2': <flask_rq2.app.RQ object at 0x00000213B5DE8940>,
'security': <flask_security.core._SecurityState object at 0x00000213B734EE10>
}
Is there a way to access the conn property other than the very convoluted (and error-prone):
>> list(app.extensions.get('mongoengine').values())[0].get('conn')
MongoClient(host=['xxx'], document_class=dict, tz_aware=False, connect=True, ssl=True, replicaset='Cluster0-shard-0', authsource='admin', retrywrites=True, read_preference=Primary())
Does flask-mongoengine have a method to access its properties?
The MongoEngine instance has a connection attribute, use that.
You don't need to use app.extensions; that's more of an internal data structure for extensions to keep track of their own state when they need to access this from the current app context.
In your own code, just keep a reference to the MongoEngine instance you created. The documentation uses:
db = MongoEngine(app)
or
db = MongoEngine()
# in an app factory, attach to an app with db.init_app(app)
and so you can use:
db.connection
Next, there is also a current_mongoengine_instance() utility function that essentially gives you the same object as what your code already achieved. Use it like this:
from flask_mongoengine import current_mongoengine_instance
current_mongoengine_instance().connection
As a side note: the way this extension uses app.extensions is ... over-engineered and redundant. The rationale in the source code is:
# Store objects in application instance so that multiple apps do not
# end up accessing the same objects.
but multiple apps already have separate app.extensions dictionaries. While this method does let you use multiple mongoengine connections, you still then can't use this data structure to distinguish between different connections with only the current app context. The implementation for current_mongoengine_instance() only further illustrates that the extension doesn't have a proper strategy for handling multiple connections. You just get the 'first' one, whatever that may mean in the context of unordered dictionaries. The Flask SQLAlchemy extension instead uses a single extension instance to manage multiple connections via a system called binds.
You can also reach the underlying pymongo.Collection from any of your Document class by
class MyDocument(Document):
name = StringField()
MyDocument(name='John').save()
coll = MyDocument._get_collection()
print(coll.find_one({'name': 'John'}))
I need to do a callout to webservice from my ApexController class. To do this, I have an asycn method with attribute #future (callout=true). The webservice call needs to refeence an object that gets populated in save call from VF page.
Since, static (future) calls does not all objects to be passed in as method argument, I was planning to add the data in a static Map and access that in my static method to do a webservice call out. However, the static Map object is getting re-initalized and is null in the static method.
I will really appreciate if anyone can give me some pointeres on how to address this issue.
Thanks!
Here is the code snipped:
private static Map<String, WidgetModels.LeadInformation> leadsMap;
....
......
public PageReference save() {
if(leadsMap == null){
leadsMap = new Map<String, WidgetModels.LeadInformation>();
}
leadsMap.put(guid,widgetLead);
}
//make async call to Widegt Webservice
saveWidgetCallInformation(guid)
//async call to widge webserivce
#future (callout=true)
public static void saveWidgetCallInformation(String guid) {
WidgetModels.LeadInformation cachedLeadInfo =
(WidgetModels.LeadInformation)leadsMap.get(guid);
.....
//call websevice
}
#future is totally separate execution context. It won't have access to any history of how it was called (meaning all static variables are reset, you start with fresh governor limits etc. Like a new action initiated by the user).
The only thing it will "know" is the method parameters that were passed to it. And you can't pass whole objects, you need to pass primitives (Integer, String, DateTime etc) or collections of primitives (List, Set, Map).
If you can access all the info you need from the database - just pass a List<Id> for example and query it.
If you can't - you can cheat by serializing your objects and passing them as List<String>. Check the documentation around JSON class or these 2 handy posts:
https://developer.salesforce.com/blogs/developer-relations/2013/06/passing-objects-to-future-annotated-methods.html
https://gist.github.com/kevinohara80/1790817
Side note - can you rethink your flow? If the starting point is Visualforce you can skip the #future step. Do the callout first and then the DML (if needed). That way the usual "you have uncommitted work pending" error won't be triggered. This thing is there not only to annoy developers ;) It's there to make you rethink your design. You're asking the application to have open transaction & lock on the table(s) for up to 2 minutes. And you're giving yourself extra work - will you rollback your changes correctly when the insert went OK but callout failed?
By reversing the order of operations (callout first, then the DML) you're making it simpler - there was no save attempt to DB so there's nothing to roll back if the save fails.
For my Flash Builder 4.6 Project I have a http service defined which looks at a url from our website.
What I'd like to be able to do though is to change the web service url on the fly within the app. i.e. using the existing url as default but having an admin/settings screen to change where the web service points (either stored in our sqlite database or in local memory).
This would be so that we could allow our customers to host their own version of the website/database but still be able to use/download the app through the app stores.
Has anyone had any experience with doing this?
EDIT: Adding some more details after the comments below.
When I created the HTTP Service through the FlashBuilder wizard it creates two web service classes a super class and a sub class which inherits from the super class. All of the code that the wizard populates goes into the super class.
I can assume that the code I need to put in would be in the sub class. But I do not know which function I'd put it in or how.
Below is a sample of the Super's constructor:
// initialize service control
_serviceControl = new mx.rpc.http.HTTPMultiService("websitehere");
var operations:Array = new Array();
var operation:mx.rpc.http.Operation;
var argsArray:Array;
operation = new mx.rpc.http.Operation(null, "loginRequest");
operation.url = "login.php";
operation.method = "GET";
argsArray = new Array("un","pw");
operation.argumentNames = argsArray;
operation.serializationFilter = serializer0;
operation.properties = new Object();
operation.properties["xPath"] = "/";
operation.contentType = "application/x-www-form-urlencoded";
operation.resultType = valueObjects.Data;
operations.push(operation);
_serviceControl.operationList = operations;
I'm not sure what property of the _serviceControl variable I would need to alter.
Also when I search for my website in my code it brings back a .fml file inside a .model directory which seems to get auto refreshed if I change the service url through the wizard. Would this not cause an issue?
I then have the challenge of accessing the user defined url. Within the app we use an sqlite database to store data but I think it would probably be better to use a 'SharedObject' which we also use to know what account they are logged into. How reliable is this? I assume I would be able to access this via the Service?
Though the awkward thing is that we were planning to have this configurable on a settings screen that would have been accessed after logging in. But to log in it would already need to know which server to point to.
if im reading your question correctly then your main ambition is to dynamically change the url for the services based on a user defined variable.
This is very easy to accomplish and even easier to accomplish if you are using parsley / spicelib.
a few points
dont change the code in the super file, this will get overwritten whenever the service gets refreshed. change everything in its generated sub-Class.
Shared Objects are very good for small quantities of data but should never be used for massive datasets i.e storing a big arraycollection.
Anyway here is how i achieve this.
In the SubClass you can change the constructor function.
Here is how i change my urls based on a config variable but you can just as easily use a SharedObject instead.
public function SubClassConstructor(){
if(CONFIG::DOMAIN_IDENT == "development" || CONFIG::DOMAIN_IDENT == "dev" || CONFIG::DOMAIN_IDENT == "d"){
_serviceControl.endpoint = "http://yoururl1";
}
else if(CONFIG::DOMAIN_IDENT == "production" || CONFIG::DOMAIN_IDENT == "prod" || CONFIG::DOMAIN_IDENT == "p"){
_serviceControl.endpoint = "http://yoururl2";
}
}
Of course this isn't exactly what your looking for but its a working solution, of course you can use Bindings to a Global ApplicationModel or direct reference to the SharedObject i guess you already know how to use the SharedObject.
Ask if you need any further help or guidance.
As cghrmauritius' solution didn't quite work for me, I am posting up the final solution that did work in my situation.
public function subConstructor()
{
super();
_serviceControl.baseURL = "http://url1";
}
Obviously for my final solution I need to implement the shareobject as well but overriding the url was my main priority.
We have a wrapper around a suds (SOAP) request, that we use like this throughout our app:
from app.wrapper import ByDesign
bd = ByDesign()
Unfortunately, this instantiation is made at several points per request, causing suds to redownload the WSDL file, and I think we could save some time by making bd = ByDesign() return a singleton.
Since suds is not threadsafe, it'd have to be a singleton per request.
The only catch is, I'd like to make it so I don't have to change any code other than the app.wrapper.ByDesign class, so that I don't have to change any code that calls it. If there wasn't the 'singleton per request' requirement, I'd do something like this:
class ByDesignRenamed(object):
pass
_BD_INSTANCE = None
def ByDesign():
global _BD_INSTANCE
if not _BD_INSTANCE:
_BD_INSTANCE = ByDesignRenamed()
return _BD_INSTANCE
But, this won't work in a threaded server environment. Any ideas for me?
Check out threading.local(), which is somewhere between pure evil and the only way to get things going. It should probably be something like this:
import threading
_local = threading.local()
def ByDesign():
if 'bd' not in _local.__dict__:
_local.bd = ByDesignRenamed()
return _local.bd
Further reading:
Why is using thread locals in Django bad?
Thread locals in Python - negatives, with regards to scalability?
Here two of my model classes:
class DashboardVersion(models.Model):
name = models.CharField(_("Dashboard name"),max_length=100)
description = models.TextField(_("Description/Comment"),null=True,blank=True)
modifier = models.ForeignKey(User,editable=False,related_name="%(app_label)s_%(class)s_modifier_related")
modified = models.DateField(editable=False)
class Goal(models.Model):
goal = models.TextField(_("Goal"))
display_order = models.IntegerField(default=99999)
dashboard_version = models.ForeignKey(DashboardVersion)
When a Goal is edited, added, deleted, etc., I want to change the DashboardVersion.modifier to the user who modified it and the DashboardVersion.modifed to the current date.
I am trying to implement this using signals. It seems though, that the post_save signal does not contain the request. Or can I get it from somewhere or do I have to create my own signal?
Or, should I do something completely different?
Thanks! :-)
Eric
I'd say the most straightforward thing to do would be to just update the DashboardVersion in the view that processes the Goal update. If you have multiple views in the same module that handle Goal updates, you could factor out the DashboardVersion update logic into a separate function.
If you're dead set on using signals, you could probably hack something together with a thread locals middleware, but I'd say the simplest approach is usually best.