Flask-AppBuilder equivalent of SQLite WHERE clause to filter column data - python-3.x

I'm new to Flask and have started designing a front end for an inventory management database using Flask-AppBuilder.
I have created several models and have have managed to display my sqlite data in tables using Flask-AppBuilder's views.
However, I don't seem to be able to find the equivalent of SQLite WHERE clause to filter or "restrict" column data. I've been reading a lot about sqlalchemy, filters, queries but this has left me more confused that anything else and the explanations seem to be extremely elaborate and complicated to do something which is extremely simple.
Assuming we reproduce the following SQLite query in Flask-AppBuilder:
SELECT Field_A
FROM Table_A
WHERE Field_A = 'some text'
with:
result = session.query(Table_A).filter_by(Field_A = 'some text').all()
Where does the above line of code go in my app?
Considering I have the following Class:
class Table_A(Model):
id = Column(Integer, primary_key=True)
Field_A = Column(String)
def __repr__(self):
return self
and View:
class Table_AView(ModelView):
datamodel = SQLAInterface(Table_AView)
label_columns = {'Field_A':'A'}
list_columns = ['Field_A']

After much digging flask-appbuilder uses it's own filterclass in order to enable you to filter your views.
All the classes are referenced here on GitHub:
Flask Filter Clases List
Also not the difference between FilterEqual and FilterEqualFunction here:
What is the difference between : FilterEqual and FilterEqualFunction?
For other customisation and first port of call of Flask-appbuilder go straight to the API Reference where you'll find a couple of examples of the filterclass in action.
In essence it is extremely simple. In your views.py code within the ModelView class you want to filter simply add base_filters = [['field_A', FilterEqual, 'abc']] like so:
`class Table_AView(ModelView):
datamodel = SQLAInterface(Table_AView)
label_columns = {'Field_A':'A'}
list_columns = ['Field_A']
base_filters = [['field_A', FilterEqual, 'abc']]`
This will only show the lines where the field_A variable is equal to abc.
Hope this helps someone as it took me nearly (sigh) two weeks to figure it out...

SQLALchemy is an ORM (Object-Relational Mapping), it mean that you dont have to deal with raw SQL, you will call a function that you "build" (by adding filters in your case). It will transparently generate an SQL query, execute it, and return the result as python objects.
I would suggest you to read closely at sqlalchemy documentation about filters again, especially filter_by :
http://docs.sqlalchemy.org/en/latest/orm/query.html#sqlalchemy.orm.query.Query.filter_by
It is the easiest way to apply a WHERE with sqlalchemy.
If you have declared correctly the model for Table_A, you should be able to use it so:
result = session.query(Table_A).filter_by(Field_A = 'some text').all()
Here session.query(Table_A).filter_by(Field_A = 'some text') will generate the SQL, and .all() will execute it.

Related

Sorting custom columns with django-datatables-view

Using Django 3, python 3.6, django-datatable-view 1.19.1
Trying to do a datatable with columns from my model and computed before output ones.
I draw all values that I needed but after trying to sort custom column getting an error:
Cannot resolve keyword 'XXXX' into field. Choices are: ...
I've found a way to register a column as virtual column, without db source, but it was in django-datatable-view 0.5.4 docs but those ways don't work anymore. In last version documentation links with info that I need are unavailable.
Please, help me to figure out, how can I deal with custom computed columns from my model's fields( sort, render )
This is a little tricky now.
To define computed fields:
class ListJson(BaseDatatableView):
columns = ["id", "status_code", "computed_field"]
order_columns = ["id", "status_code"]
# Override render_column method
def render_column(self, row, column):
if column == "computed_field":
return row.computed_field()
else:
return super(ListJson, self).render_column(row, column)
This allows you to return the computed_field method value().
The situation becomes complicated when we want to sort on calculated fields. In this case, it is best to disable serverSide operations in JavaScript
$.extend($.fn.dataTable.defaults, {
serverSide: false,
});
However, you will then have to return all the lines at once, which can kill the server.
If you want to sort on the backend side, you need to arrange and return the appropriate queryset with a virtual field.
class ListJson(BaseDatatableView):
def get_initial_queryset(self):
return qs
Just build your query like THIS.

How to capture many to many field values via get_initial command

I am slowly progressing in my django journey, but this one has me stumped. I am trying to populate a CreateView with a different model via a copy command using the get_initial override. All of the attributes copy as I would expect with the exception of the ManytoMany fields. I've researched this topic most of today, and found the following which is very close to what I'm trying to figure out KeyError: 'manager' in django get_initial.
My View...
class BookView(LoginRequiredMixin,CreateView):
model = Book
template_name = 'book/titles.html'
form_class = BookForm
def get_initial(self):
initial = super(BookView, self).get_initial()
author = author.objects.get(pk=self.kwargs["pk"])
initial = author.__dict__.copy()
initial.update({
"author": author.name,
}}
for field in self.form_class.base_fields.items():
value = getattr(self.get_object(), field)
if field == 'author':
value = self.get_object().author.all()
initial.update({field: value})
return initial
I incorporated the suggested change based on the issue that I found on SO, but I still am getting a 'manager" KeyError. I am ultimately trying to populate the manytomanyfield in my model and then save the values, but to no avail. Any suggests are appreciated!
What a difference a day makes....
def get_initial(self):
initial = super(BookView, self).get_initial()
author = author.objects.get(pk=self.kwargs["pk"])
initial = author.__dict__.copy()
initial.update({
"author": author.name.all(),
}}
return initial
I added a .all() after the reference to the manytomanyfield in my initial get and also update the form to get the field in question. Much cleaner than a few hacks I kinda got working along the way.

How to convert Rep[T] to T in slick 3.0?

I used a code, generated from slick code generator.
My table has more than 22 columns, hence it uses HList
It generates 1 type and 1 function:
type AccountRow
def AccountRow(uuid: java.util.UUID, providerid: String, email: Option[String], ...):AccountRow
How do I write compiled insert code from generated code?
I tried this:
val insertAccountQueryCompiled = {
def q(uuid:Rep[UUID], providerId:Rep[String], email:Rep[Option[String]], ...) = Account += AccountRow(uuid, providerId, email, ...)
Compiled(q _)
}
I need to convert Rep[T] to T for AccountRow function to work. How do I do that?
Thank you
;TLDR; Not possible
Explanation
There are two levels of abstraction in Slick: Querys and DBIOActions.
When you're dealing with Querys, you have to access your schema definitions, and rows, Reps and, basically, it's very constrained as it's the closest level of abstraction to the actual DB you're using. A Rep refers to an hypothetical value in the database, not in your program.
Then you have DBIOActions, which are the next level... not just some definition of a query, but the execution of it. You usually get DBIOActions when getting information out of a query, like with the result method or (TADAN!) when inserting rows.
Inserts and Updates are not queries and so what you're trying to do is not possible. You're dealing with DBIOAction (the += method), and Query stuff (the Rep types). The only way to get a Rep inside a DBIOAction is by executing a Query and obtaining a DBIOAction and then composing both Actions using flatMap or for comprehensions (which is the same).

sqlalchemy reflecting table and inserting a row

im building a wrapper for a db_connector using sqlalchemy...
since im trying to stay generic i presume i wont know what tables il have and thus i cant use orm line of development.... trying to use the reflection system, where i reflect the table from the database and trying to create new Object from this table in order to insert the new info i got from user.
at the moment my func gets table_name as the table to insert into a new row and row_arguments, as list with arguments for new row...
im struggling creating new object of that table, more precise object of a row for the table, which i think if id manage doing that all would be swell and using session i would manage to add the new row.
my question is how can i create that kind of object from the things i pass? i got engine,Session,metadata in the class itself defined....
def insertRow(self,table_name,row_arguments):
self.table = self.getTablesInDB(table_name)
self.session = self.Session()
class Test(object):
pass
mapper(Test,self.table)
string =""
for i in row_arguments:
string += i
insert = Test()
self.session.add(insert)
self.session.commit()
in middle of code i have lots of things i tried, nothing seem to succeedd.... im kinda hopeless and out of ideas, please help
idea is to not know with what kind of tables im facing before retrieving them by the way
What if you try :
def insertRow(self,table_name,row_arguments):
table = self.getTablesInDB(table_name)
self.session = self.Session()
# Considering row_arguents is a dict {"colname1":value, "colname2":value}
insert = table(**row_arguments)
self.session.add(insert)
self.session.commit()

Construct Completely Ad-hoc Slick Query

Pardon my newbieness but im trying to build a completely ad-hoc query builder using slick. From our API, I will get a list of strings that is representative of the table, as well as another list that represents the filter for the tables, munge then together to create a query. The hope is that I can take these and create the inner join. A similar example of what i'm trying to do would be JIRA's advanced query builder.
I've been trying to build it using reflection but I've come across so many blocking issues i'm wondering if this is even possible at all.
In code this is what I want to do:
def getTableQueryFor(tbl:String):TableQuery[_] = {
... a matcher that returns a tableQueries?
... i think the return type is incorrect b/c erasure?
}
def getJoinConditionFor:(tbl1:String, tbl2:String) => scala.slick.lifted.Column[Boolean] = (l:Coffees,r:Suppies) => {
...a matcher
}
Is the Following even possible?
val q1 = getTableQueryFor("coffee")
val q2 = getTableQueryFor("supply")
val q3 = q1.innerJoin.q2.on(getJoinCondition("coffee", "supply")
edit: Fixed grammar issue.

Resources