I am attempting to combine Flask-Admin and a Flask S3 Tool Suite written by someone to store images to Amazon S3 simple storage. The tool I am trying to specifically use is the S3Saver functionality and in the article link the user goes on to say that to incorporate this tool, I would ideally use it on a flask-admin callback.
However, I cannot find a list of Flask-Admin callbacks anywhere. I have done my homework and I have literally checked the entire docs and source code for these callbacks Flask-Admin documentation .
In flask_admin.contrib.sqla I found some methods that kind of resembled a callback but its not what I am looking for. I imagine that it is something close to Rails's before_action and after_action. Can someone please point me in the right direction?
By the way this is the actual quote from the article
If you wanted to handle deleting files in the admin as well, you could (for example) use s3-saver, and hook it in to one of the Flask-Admin event callbacks
What callbacks are those?
Flask-Admin Callback Functions (as far as I know)
after_model_change(form, model, is_created)
#Called from create_model after successful database commit.
after_model_delete(model)
#Called from delete_model after successful database commit (if it has any meaning for a store backend).
on_form_prefill(form,id)
# Called from edit_view, if the current action is rendering the form rather than receiving client side input, after default pre-filling has been performed.
on_model_change(form,model,is_created)
#Called from create_model and update_model in the same transaction (if it has any meaning for a store backend).
on_model_delete(model)
# Called from delete_model in the same transaction (if it has any meaning for a store backend).
More info at http://flask-admin.readthedocs.org/en/latest/api/mod_model/ (search for "Called from")
Here is the documentation for Flask Admin events :
https://flask-admin.readthedocs.org/en/latest/api/mod_model/#flask_admin.model.BaseModelView.on_form_prefill
on_form_prefill(form, id) Perform additional actions to pre-fill the edit form.
Called from edit_view, if the current action is rendering the form
rather than receiving client side input, after default pre-filling has
been performed.
By default does nothing.
You only need to override this if you have added custom fields that
depend on the database contents in a way that Flask-admin can’t figure
out by itself. Fields that were added by name of a normal column or
relationship should work out of the box.
Parameters: form – Form instance id – id of the object that is going
to be edited
on_model_change(form, model, is_created) Perform some actions before a model is created or updated.
Called from create_model and update_model in the same transaction (if
it has any meaning for a store backend).
By default does nothing.
Parameters: form – Form used to create/update model model – Model
that will be created/updated is_created – Will be set to True if model
was created and to False if edited
on_model_delete(model) Perform some actions before a model is deleted.
Called from delete_model in the same transaction (if it has any
meaning for a store backend).
By default do nothing.
Related
I want to create a new model which uses the https://developer.microsoft.com/en-us/graph/graph-explorer api as a data source as i want to have additional info on the user.
Using a computed property on the model does not work as it is going to query for each instance in the set.
So, i want to have the model relate to a new model which has the api as it´s data source.
I could not find anything on this topic, besides maybe abusing the from_db() method, if this even works.
It appears that what you're trying to do is to cache data from an external API that relates to, and augments/enriches, your user model data. If so, you can simply use a custom user model (instead of Django's default; this is a highly-recommended practice anyway) and then simply store the external API data in serialized form in a TextField attribute of your custom user model (let's call it user_extras; you can write model methods that serializes and deserializes this field for convenience upon access in your views).
The key challenge then is how to keep user_extras fresh, without doing something terrible performance-wise or hitting some constraint like API call limits. As you said, we can't do API queries in computed properties. (At least not synchronously.) One option then is to have a batch job/background task that regularly goes through your user database to update the user_extras in some controlled, predictable fashion.
I'm working with Flask-restplus and I am at a point where I would like to associate each User in my user model to a type of profile, where each user can be associated with one or many profile types. I'm wondering how you guys would go about this. So far, here's what I'm thinking/planning to do. NOTE: I'm not very experienced in web development, so there's a chance I don't know the best way to accomplish this.
Step 1: Create a one-to-many (clients need to also be employees, see below) field (profile_types) relating to a static table that just lists all possible profile options. EXAMPLE:
PK PROFILE TYPE
1 provider
2 employee
3 client
.....
The idea here is to track different information and allow for different views/endpoints for users who are tied to certain profile types. Example, employees would provide a valid login authentication and be directed to page A while a client would be directed to page B, etc. We're also planning on collecting different data points within each profile model.
So an instance of a user might look like this, user1.profile == [client, employee'].
NOTE: This is more important for data collection (ie age of employee, start date, etc) than it is for creating directives based on permissions.
Step 2: Upon creating the new user, a signal fires off the creation of a profile based on the profile_types supplied to the user instance. I've used signals with django in the past, is there a signal library for Flask?
Step 3: An empty profile instance(s) now exists for that user. It will be up to a superuser to upload data in bulk or manually fill out profile information.
Is this a sensible way to go about this? My other though is to create a bunch of Boolean fields in the User model is_provider, is_employee, is_client, etc. All fields that are True get assigned a profile instance. What's the best way to go about this?
Thanks everyone!
Seeing that are you try to validate multiple profile types, you may use
if user.profile_type in ['employee', 'client']
Now, if you want to add an super user I think you can use this
if user.profile_type in ['employee', 'client'] and user.profile_type == 'superuser'
Now, you relationship is more like 'many-to-many', because you are saying that an client also needs to be an employee, if you mean that some endpoints needs to be accessible for employees and clients, then you need to use a 'many-to-one' relationship (an Stackoverflow question which explains what is that)
For your instances, there is Flask Marshmallow, which has an amazing compatibility with Flask SQLAlchemy if you are using an database, but Flask Marshmallow can work alone.
I am wondering on how to implement pure controller functions in a Django's' "biased" MVC scheme. Let me explain it on an example.
Let's say I have a model of an Invoice, which has some attributes (say net, gross etc.). I can present it to the user using a view + template. And that's fine and easy.
But now, I want to send this invoice to a client. This is a more complicated thing, inluding more models (i.e. create an addressed Package model, get a number and let's say few other thing including creating and modifying not only Invoice model itself, but also creating and updating few other model types and instances.
I want this "action" to be available in multiple places of my web application, so going by the book I need to create a view with those actions implemented and bind it to some URL. Probably it should be implemented in POST action.
My questions are:
What kind of generic view should it be (just View? DetailView? other?).
Where should this View redirect after succesfull "send"? The simplest answer would be to redirect to the same referring page, but is this a correct way?
What if I want this "action" to be ran in background (say, send all unsend invoices at midnight) using celery or such? Of course I can make this a celery task and call it in a view. But is this clean django'ish solution? Where do you store such pure business methods in an app/project?
I see lots of apps using Form objects to validate data and then passing the data to the model, while putting absolutely no validation in the model. I feel it's better to put core validation in the model itself (e.g., no users under the age of 18, ever) to be run regardless of the context. In other words, I don't care how the user is being created (whether through web ui or command line), the core rules should always apply.
I'm using SQLAlchemy (within a Pyramid application), and I would like to define my core validation rules within the model in a way that my forms (WTForms) always respect the core rules defined in the model so that all data is consistent.
Is anybody else already doing this, or something similar?
Something similar to this php solution.
SQLAlchemy allows you to register listeners, which are invoked when certain events occur, for example you can register an event to be triggered when a model's field is modified. From SQLAlchemy documentation:
Listeners have the option to return a possibly modified version of the
value, when the retval=True flag is passed to listen():
def validate_phone(target, value, oldvalue, initiator):
"Strip non-numeric characters from a phone number"
return re.sub(r'(?![0-9])', '', value)
# setup listener on UserContact.phone attribute, instructing
# it to use the return value
listen(UserContact.phone, 'set', validate_phone, retval=True)
A validation function like the above can also raise an exception such
as ValueError to halt the operation.
So, as you see, you can either modify or reject values for certain field at the model level.
I'm not sure if your form library integrates with this feature, but it definitely should not be too difficult to roll your own solution.
I'm basically building a very trivial form. Let's stick to the books/publisher examples given in the django tutorials and build upon that.
I have a user login to the web app, at which point the first thing they can do is click on a publisher. This publisher then gets saved for their session. Upon that I take them to a create book form. In there I embed the the publisher's id from the database into a hidden field.
Upon the user submitting an HTTP POST, I do something like:
mybookform = BookForm(request.POST)
if mybookform.is_valid():
abook = mybookform.save(commit=False)
abook.publisher_id = request.POST['publisher_id']
mybookform.save()
Yes there's a few naive things done here, such as blindly grabbing the publisher_id and verifying if it's indeed a real publisher id, amongst other security issues. Let's just not pay attention to that for the moment.
My question is, is there a better way of handling this? Although hypothetically this example doesn't make logistical sense, in my particular app the example actually makes sense. The problem is I get a ValueError exception saying publisher_id needs to be a Publisher instance.
Now I can easily retrieve a publisher instance with Publisher.objects.filter(id=..) and use that instead. The question is, is it really necessary? Can I avoid the additional query to the database and somehow update this form instance in a more 'elegant' fashion?
Also, is it possible to somehow embed the publisher in a hidden field so that I do not need to do mybookform.save(commit=False) and just do mybookform = BookForm(request.POST) followed by mybookform.save() immediately?
Retrieving the instance of the publisher does protect against client-side changes that might reference a completely invalid publisher.
To your second question, yes you can include that field as a hidden field by overriding the field in the ModelForm with the approriate form field setting the widget to HiddenInput.
There is no better way to do this.
I would use the get_object_or_404 function for this.
And yes, you can prevent this to be modified by the user by setting the model field to editable=False,