Batch Editing in Flask-Admin - python

I'm using Flask-Admin and I want to be able to update many fields at once from the list view. It seemed like what I'm looking for is a custom action.
I was able to make it work, but I suspect not in the best way. I'm wondering if it could be done more "Flask"-ily.
What I do now, for example if I was updating all rows in table cars to have tires = 4:
A custom action in the CarView class collects the ids of the rows to be modified, a callback url from request.referrer, and the tablename cars, and returns render_template(mass_update_info.html) with these as parameters.
mass_update_info.html is an HTML form where the user specifies 1) the field they would like to change and 2) the value to change it to. On submit, the form makes a POST to a a certain view (do_mass_update) with this data (everything else is passed as hidden fields in this form).
do_mass_update uses the data sent to it to construct a SQL query string -- in its entirety, "UPDATE {} SET {}='{}' WHERE id IN ({})".format(table, column, value, ids) -- which is run via db.engine.execute().
The user is redirected to the callback url.
It bothers me that I don't seem to be using any of SQLAlchemy, but (from a newbie's perspective) it all seems to be based on the model objects e.g. User.query(...), while I only have access to the model/table name as a string. Can I get some kind of identifier from the model, pass that through, and do a lookup to retrieve the on the other side?

Related

How do you avoid SQL Injection attacks in your Django Rest APIs if using native ORM?

They say that by using Django ORM you are already protected against most SQL Injection attacks. However, I wanted to know if there are any additional measures that should or can be used to process user input? Any libraries like bleach?
The main danger of using a Django ORM is that you might give users a powerful tool to select, filter and aggregate over arbitrary fields.
Indeed, say for example that you make a form that enables users to select the fields to return, then you can implement this as:
data = MyModel.objects.values(*request.GET.getlist('fields'))
If MyModel has a ForeignKey to the user model named owner, then the user could forge a request with owner__password as field, and thus retrieve the (hashed) passwords. While Django stores for its default User model a hashed password, it still means that the hashed data is exposed and it might make it easier to thus retrieve passwords.
But even if there is no user model, it can result in the fact that users can forge requests where they use links to sensitive data, and thus can retrieve a large amount of sensitive data. The same can happen with arbitrary filtering, annotating, aggregating, etc.
What you thus should do is keep a list of acceptable values, and check that the request only contains these values, for example:
acceptable = {'title', 'description', 'created_at'}
data = [field for field in request.GET.getlist('fields') if field in acceptable]
data = MyModel.objects.values(*data)
If you for example make use of packages like django-filter [readthedocs.io] you list the fields that can be filtered and what lookups can be done for these fields. The other data in the request.GET will be ignored, and thus will prevent filtering with arbitrary fields.

Saving author of form Web2Py

How can I save & display the name of the user who submits a form saved in a database.
For example:
I have a form that allows users to review products.
I then have a table that lists these reviews.
On the table I want to list each users name besides each review.
You could add a reference field pointing to the db.auth_user table (or whatever table in which you store user data):
db.define_table('review',
...,
Field('reviewer', 'reference auth_user', default=auth.user_id, writable=False),
...)
With the above code, the default value for the "reviewer" field is the ID of the currently logged in user. The field is not writable, so the user has no way to change that (in the review entry form, you might also want to set its readable attribute to False, as there is no need for the author to see it).
Then to display the reviewer name along with the review, you could either do a join or use a recursive select (the former is more efficient if you are displaying many reviews at once, as the recursive select approach requires a separate database query to get each review's author).

Django's Model save flow

I noticed that there's no guarantee that the data base is updated synchronously after calling save() on a model.
I have done a simple test by making an ajax call to the following method
def save(request, id)
product = ProductModel.objects.find(id = id)
product.name = 'New Product Name'
product.save()
return HTTPResponse('success')
On the client side I wait for a response from the above method and then execute findAll method that retrieves the list of products. The returned list of products contains the old value for the name of the updated product.
However, if I delay the request for the list of products then it contains the new value, just like it is should.
This means that return HTTPResponse('success') if fired before the new values are written into the data base.
If the above is true then is there a way to return the HTTP response only after the data base is updated.
You should have mentioned App Engine more prominently. I've added it to the tags.
This is very definitely because of your lack of understanding of GAE, rather than anything to do with Django. You should read the GAE documentation on eventual consistency in the datastore, and structure your models and queries appropriately.
Normal Django, running with a standard relational database, would not have this issue.
The view should not return anything prior to the .save() function ends its flow.
As for the flow itself, the Django's docs declare it quite explicitly:
When you save an object, Django performs the following steps:
1) Emit a pre-save signal. The signal django.db.models.signals.pre_save is sent, allowing any functions listening for that signal to take some customized action.
2) Pre-process the data. Each field on the object is asked to perform any automated data modification that the field may need to perform.
Most fields do no pre-processing — the field data is kept as-is. Pre-processing is only used on fields that have special behavior. For example, if your model has a DateField with auto_now=True, the pre-save phase will alter the data in the object to ensure that the date field contains the current date stamp. (Our documentation doesn’t yet include a list of all the fields with this “special behavior.”)
3) Prepare the data for the database. Each field is asked to provide its current value in a data type that can be written to the database.
Most fields require no data preparation. Simple data types, such as integers and strings, are ‘ready to write’ as a Python object. However, more complex data types often require some modification.
For example, DateField fields use a Python datetime object to store data. Databases don’t store datetime objects, so the field value must be converted into an ISO-compliant date string for insertion into the database.
4) Insert the data into the database. The pre-processed, prepared data is then composed into an SQL statement for insertion into the database.
5) Emit a post-save signal. The signal django.db.models.signals.post_save is sent, allowing any functions listening for that signal to take some customized action.
Let me note that the behaviour you're receiving is possible if you've applied #transaction.commit_on_success decorator to your view, though, I don't see it in your code.
More on transactions: https://docs.djangoproject.com/en/1.5/topics/db/transactions/

CouchDB - How to create dynamic design docs based on end user input

I have been reading up more on CouchDB and really like it (master:master replication is one of the primary reasons I want to use it).
However, I have a query to ask of you guys... I cam from php, and used the Drupal CMS fairly often. One of my favorite (probably of the drupal community as a whole) was the 'Views' plugin written by MerlinOfChaos. The idea is that an admin can use the views ui system, to create a dynamic stream of content from the database. This content could be from any content type (blog posts, articles, users, image, et. al.) and could be filtered, ordered, arranged in grids, and so on. One simple example is creating a source of content for a animating slider. Where the admin could go in at any time and change what is shown in there. Though typically I would set it up as the most 5 recent of content type X.
So with something like mongo, I could kinda see how to could do this. A fairly advanced parser that would then convert what the admin wants into a db query. Since mongo is all based on dynamic querying, it is very doable. However, I want to use couch.
I have seen that I can create a view that takes a parameter and will return results based on that (such as a parameter of the 5 article id's you want displayed). But what if I want to be able to build something more advanced from the UI? would I just add more parameters? For example, say the created view selects all documents with the value 'contentType' = 'post' and the argument is the id/page title. But what if I want the end user to also be able to choose the content type that the view queries against. Or the 5 most recent articles as long as the content type is one of 3 different values?
Another thing this makes me think of, is once a view like this is created and saved to the db, and called for the first time, it spends the time to build the results. Would you do this on a production/live system?
Part of the idea is that I want an end user to be able to create a custom feed of content on their profile page based on articles and posts on the site. and to be able to filter them and make their own categories, so to speak and label them. Such as their 'tech' feed, and their 'food' feed.
I am still new to couch and still have reading to do. But this is something that was buggins me and I am trying to wrap my head around it. Since the product I have in mind is going to be heavily dynamic based on the end users input.
The application itself will be written in python
In a nutshell, you would need to emit something like this in the view:
emit([doc.contentType, doc.addDate], doc); // emit the entire doc,
// add date is timestamp (assuming)
or
emit([doc.contentType, doc.addDate], null); // use with include_docs=true
Then, when you need to fetch the listing:
startkey=["post",0]&endkey=["post",999999999]&limit=5&descending=true
Explain:
startkey = ["post",0] = contentType is post, and addDate >= 0
endkey = ["post",9999999999] = contentType is post, and addDate <= 9999999999
limit = 5, limit to five posts
descending = true = sort descending, which is sort by adddDate descending
To overcome the drawback of updating views on live db,
you can also create a new design(view) doc.
So, at least your existing code and view won't be affected.
Only after your new view is created,
you deploy the latest code to switch to this new view,
and you can retire the older view.

How to update a model

Assume I have a model definition like this:
class Image(db.Model):
id = db.StringProperty()
url = db.URLProperty()
Now I want to add some fields to this model to make it look like this:
class Image(db.Model):
id = db.StringProperty()
url = db.URLProperty()
width = db.IntegerProperty()
height = db.IntegerProperty()
So, this new model will be applied properly to newly added Image entities. But I also want to update already existing entities so that they contained these two new fields and fill them with values. Will an already existing entity get these two fields automatically so when I refer to them, it will give me empty fields or will it cause an error? I suppose I will have to create a helper function that will go through all existing entities and set new fields values, right? So, what should I keep in mind and how to better do this model update? I think it will happen sometimes as the application emerges, so I think it would be useful to have some straightforward flow to do that.
This exact scenario is covered in the GAE docs (articles section):
Updating your model's schema.
Basically just change the model definition as you've done, then perform some operation to supply default values for all your extant entities. There are several ways to do the second part - the article describes one.
No already exisiting entity won't get these two fields automatically or it won't assume it to None. It will cause an error when those fields are accessed in existing objects. Only solution avaliable now is to use remote_apy and write your own script to update the existing records. It won't be big deal, write a script to get all the records in the datastore and to set some default values for the new attributes..
Setting_Up_remote_api
Update_schema

Categories