Adding context from django_tables2 library to admin panel - django-tables2

I'm trying to use django_tables2 in Django admin panel.
Part of the library that I'm interested in is:
'''
class SingleTableMixin(TableMixinBase):
table_class = None
table_data = None
def get_table_class(self):
if self.table_class:
return self.table_class
if self.model:
return tables.table_factory(self.model)
raise ImproperlyConfigured(
"You must either specify {0}.table_class or
{0}.model".format(type(self).__name__)
)
def get_table(self, **kwargs):
table_class = self.get_table_class()
table = table_class(data=self.get_table_data(), **kwargs)
return RequestConfig(self.request,
paginate=self.get_table_pagination(table)).configure(
table
)
def get_table_data(self):
if self.table_data is not None:
return self.table_data
elif hasattr(self, "object_list"):
return self.object_list
elif hasattr(self, "get_queryset"):
return self.get_queryset()
klass = type(self).__name__
raise ImproperlyConfigured(
"Table data was not specified. Define {}.table_data".format(klass)
)
def get_table_kwargs(self):
return {}
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
table = self.get_table(**self.get_table_kwargs())
context[self.get_context_table_name(table)] = table
return context
'''
The problem is that context is not sent to admin panel. Can I import somehow this context from the last method?

Related

Adjust save location of Custom XCom Backend on a per task basis

I have posted a discussion question about this here as well https://github.com/apache/airflow/discussions/19868
Is it possible to specify arguments to a custom xcom backend? If I could force a task to return data (pyarrow table/dataset, pandas dataframe) which would save a file in the correct container with a "predictable file location" path, then that would be amazing. A lot of my custom operator code deals with creating the blob_path, saving the blob, and pushing a list of the blob_paths to xcom.
Since I work with many clients, I would prefer to have the data for Client A inside of the client-a container which uses a different SAS
When I save a file I consider that a "stage" of the data so I would prefer to keep it, so ideally I could provide a blob_path which matches the folder structure I generally use
class WasbXComBackend(BaseXCom):
def __init__(
self,
container: str = "airflow-xcom-backend",
path: str = guid(),
partition_columns: Optional[list[str]] = None,
existing_data_behavior: Optional[str] = None,
) -> None:
super().__init__()
self.container = container
self.path = path
self.partition_columns = partition_columns
self.existing_data_behavior = existing_data_behavior
#staticmethod
def serialize_value(self, value: Any):
if isinstance(value, pd.DataFrame):
hook = AzureBlobHook(wasb_conn_id="azure_blob")
with io.StringIO() as buf:
value.to_csv(path_or_buf=buf, index=False)
hook.load_string(
container_name=self.container,
blob_name=f"{self.path}.csv",
string_data=buf.getvalue(),
)
value = f"{self.container}/{self.path}.csv"
elif isinstance(value, pa.Table):
hook = AzureBlobHook(wasb_conn_id="azure_blob")
write_options = ds.ParquetFileFormat().make_write_options(
version="2.6", use_dictionary=True, compression="snappy"
)
written_files = []
ds.write_dataset(
data=value,
schema=value.schema,
base_dir=f"{self.container}/{self.path}",
format="parquet",
partitioning=self.partition_columns,
partitioning_flavor="hive",
existing_data_behavior=self.existing_data_behavior,
basename_template=f"{self.task_id}-{self.ts_nodash}-{{i}}.parquet",
filesystem=hook.create_filesystem(),
file_options=write_options,
file_visitor=lambda x: written_files.append(x.path),
use_threads=True,
max_partitions=2_000,
)
value = written_files
return BaseXCom.serialize_value(value)
#staticmethod
def deserialize_value(self, result) -> Any:
result = BaseXCom.deserialize_value(result)
if isinstance(result, str) and result.endswith(".csv"):
hook = AzureBlobHook(wasb_conn_id="azure_blob")
with io.BytesIO() as input_io:
hook.get_stream(
container_name=self.container,
blob_name=str(self.path),
input_stream=input_io,
)
input_io.seek(0)
return pd.read_csv(input_io)
elif isinstance(result, list) and ".parquet" in result:
hook = AzureBlobHook(wasb_conn_id="azure_blob")
return ds.dataset(
source=result, partitioning="hive", filesystem=hook.create_filesystem()
)
return result
It's not clear exactly what information you want to be able to retrieve to use as part of your "predictable file location". But there is a PR to pass basic things like dag_id, task_id etc on to serialize_value so that you can use them when naming your stored objects.
Until that is merged, you'll have to override BaseXCom.set.
You need to override BaseXCom.set
a working ,in production example
class MyXComBackend(BaseXCom):
#classmethod
#provide_session
def set(cls, key, value, execution_date, task_id, dag_id, session=None):
session.expunge_all()
# logic to use this custom_xcom_backend only with the necessary dag and task
if cls.is_task_to_custom_xcom(dag_id, task_id):
value = cls.custom_backend_saving_fn(value, dag_id, execution_date, task_id)
else:
value = BaseXCom.serialize_value(value)
# remove any duplicate XComs
session.query(cls).filter(
cls.key == key, cls.execution_date == execution_date, cls.task_id == task_id, cls.dag_id == dag_id
).delete()
session.commit()
# insert new XCom
from airflow.models.xcom import XCom # noqa
session.add(XCom(key=key, value=value, execution_date=execution_date, task_id=task_id, dag_id=dag_id))
session.commit()
#staticmethod
def is_task_to_custom_xcom(dag_id: str, task_id: str) -> bool:
return True # custom your logic here if necessary

Flask-WTF: Queries of FormFields in FieldList are none after validate_on_submit

I'm trying to generate dynamic forms using Flask-WTF to create a new product based on some templates. A product will have a list of required key-value pairs based on its type, as well as a list of parts required to build it. The current relevant code looks as follows:
forms.py:
class PartSelectionForm(Form):
selected_part = QuerySelectField('Part', get_label='serial', allow_blank=True)
part_type = StringField('Type')
slot = IntegerField('Slot')
required = BooleanField('Required')
def __init__(self, csrf_enabled=False, *args, **kwargs):
super(PartSelectionForm, self).__init__(csrf_enabled=False, *args, **kwargs)
class NewProductForm(Form):
serial = StringField('Serial', default='', validators=[DataRequired()])
notes = TextAreaField('Notes', default='')
parts = FieldList(FormField(PartSelectionForm))
views.py:
#app.route('/products/new/<prodmodel>', methods=['GET', 'POST'])
#login_required
def new_product(prodmodel):
try:
model = db.session.query(ProdModel).filter(ProdModel.id==prodmodel).one()
except NoResultFound, e:
flash('No products of model type -' + prodmodel + '- found.', 'error')
return redirect(url_for('index'))
keys = db.session.query(ProdTypeTemplate.prod_info_key).filter(ProdTypeTemplate.prod_type_id==model.prod_type_id)\
.order_by(ProdTypeTemplate.prod_info_key).all()
parts_needed = db.session.query(ProdModelTemplate).filter(ProdModelTemplate.prod_model_id==prodmodel)\
.order_by(ProdModelTemplate.part_type_id, ProdModelTemplate.slot).all()
class F(forms.NewProductForm):
pass
for key in keys:
if key.prod_info_key in ['shipped_os','factory_os']:
setattr(F, key.prod_info_key, forms.QuerySelectField(key.prod_info_key, get_label='version'))
else:
setattr(F, key.prod_info_key, forms.StringField(key.prod_info_key, validators=[forms.DataRequired()]))
form = F(request.form)
if request.method == 'GET':
for part in parts_needed:
entry = form.parts.append_entry(forms.PartSelectionForm())
entry.part_type.data=part.part_type_id
entry.slot.data=slot=part.slot
entry.required.data=part.required
entry.selected_part.query = db.session.query(Part).join(PartModel).filter(PartModel.part_type_id==part.part_type_id, Part.status=='inventory')
if form.__contains__('shipped_os'):
form.shipped_os.query = db.session.query(OSVersion).order_by(OSVersion.version)
if form.__contains__('factory_os'):
form.factory_os.query = db.session.query(OSVersion).order_by(OSVersion.version)
if form.validate_on_submit():
...
Everything works as expected on a GET request, but on the validate_on_submit I get errors. The error is that all of the queries and query_factories for the selected_part QuerySelectFields in the list of PartSelectionForms is none, causing either direct errors in WTForms validation code or when Jinja2 attempts to re-render the QuerySelectFields. I'm not sure why this happens on the POST when everything appears to be correct for the GET.
I realized that although I set the required queries on a GET I'm not doing it for any PartSelectionForm selected_part entries on the POST. Since I already intended part_type, slot, and required to be hidden form fields, I added the following immediately before the validate_on_submit and everything works correctly:
for entry in form.parts:
entry.selected_part.query = db.session.query(Part).join(PartModel).\
filter(PartModel.part_type_id==entry.part_type.data, Part.status=='inventory')

Capturing Button Methods from a second Form using PyQT

I am super new to PyQT ... I am using QT Designer for my forms. I am confused about where to put my event handling for the second form in my project.
I have the following .py files :
main.py
Ui_make_render_folders.py (generated from the Qt designer ui file)
Ui_prefs.py (generated from the Qt designer ui file)
Mainwindow.py (this is where all the even handling for the main form
lives)
icons_rc.py (resource file)
make_render_folders.py (where all my custom functions live)
Here is a picture of the script running :
click to see script running << CLICK HERE
My question is ... where does the even handling for my prefs window go ???? I cant figure out where to put my [b]on_btn_released() for the buttons on y 2nd form.[/b] Also I am not sure I am instantiating that dialog properly. Currently I am adding this code to the top of my MainWindow.py.
Finally what does #pyqSignature("") do ? And do I need it ?
"""
This is where all teh MainWindow logic sits
"""
import os
import os.path
from PyQt4.QtGui import QMainWindow, QFileDialog, QTreeWidgetItem, QDialog
from PyQt4.QtCore import pyqtSignature, QString
from make_folders import make_render_folders
from Ui_make_render_folders import Ui_MainWindow
from Ui_prefs import Ui_prefs
class Prefs(QDialog, Ui_prefs):
def __init__(self, parent = None):
QDialog.__init__(self, parent)
self.setupUi(self)
#pyqtSignature("")
def on_btn_get_ref_dir_released(self):
print '2nd form'
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent = None):
"""
Constructor
"""
QMainWindow.__init__(self, parent)
self.setupUi(self)
self.prefs = QDialog()
ui = Ui_prefs()
ui.setupUi(self.prefs)
#pyqtSignature("")
def on_btn_process_released(self):
print 'process'
no_of_shots = self.spn_no_of_shots.value()
#spot_path = self.le_proj_path.text()+'\\'+self.lst_spots.selectedItems()[0].text()
spot_path_string = 'self.le_proj_path.text())+os.sep,'
spot_path_string += str(self.lst_spots.selectedItems()[0].text())
os.path.join(spot_path_string)
save_position = self.lst_spots.selectedItems()[0]
if no_of_shots > 0:
if self.cmb_mode.currentText() == 'Create Shots':
print ('creating shots')
for x in range(1, no_of_shots+1):
make_render_folders.create_shot_folder(spot_path, x)
else:
print ('inserting shots')
if self.lst_shots.count() > 0:
t =self.lst_shots.selectedItems()[0].text()
cur_shot = t[2:]
cur_shot_val = int(cur_shot)
cur_index = self.lst_shots.currentRow()
print('sel_value :'+cur_shot)
print('sel_index :'+str(cur_index))
next_shot_index = int(cur_index)+1
print('nextshot_index ='+str(next_shot_index))
next_shot_text = self.lst_shots.item(next_shot_index).text()
next_shot_val = int(next_shot_text[2:])
print('nextshot value ='+str(next_shot_val))
insert_space = next_shot_val - cur_shot_val
print(str(insert_space))
if no_of_shots > (insert_space-1) :
print "not enough space - please reduce shots to insert"
else:
print('insert the shots')
for x in range(cur_shot_val,(cur_shot_val+no_of_shots) ):
print (str(x))
make_render_folders.insert_shot_folder(spot_path, x+1)
make_render_folders.populate_shot_list(self)
self.lst_shots.setCurrentRow(0)
#pyqtSignature("")
def on_btn_quit_released(self):
print 'quit'
self.close()
#pyqtSignature("")
def on_cmb_mode_currentIndexChanged(self, ret_text):
print ret_text
#pyqtSignature("")
def on_le_proj_path_editingFinished(self):
print "editingFinished le_proj_path"
def on_le_new_spot_name_textChanged(self):
if len(self.le_new_spot_name.text()) > 0 :
self.btn_add_spot.setEnabled(True)
else :
self.btn_add_spot.setEnabled(False)
#pyqtSignature("")
def on_btn_add_spot_released(self):
v_NewSpotFolder = self.le_new_spot_name.text()
v_rPath = self.le_proj_path.text()
x = make_render_folders.create_spot_folder(v_NewSpotFolder,v_rPath)
if x :
self.le_new_spot_name.clear()
make_render_folders.populate_spots_list(self)
#pyqtSignature("")
def on_actionLoad_Project_triggered(self):
print "actionLoad_Project"
self.lst_shots.clear()
self.lst_spots.clear()
proj_dir = str(QFileDialog.getExistingDirectory(self, 'Select Project'))
print proj_dir
if os.path.exists(proj_dir):
print 'the file is there'
elif os.access(os.path.dirname(proj_dir), os.W_OK):
print 'the file does not exists but write privileges are given'
else:
print 'can not write there'
p = os.path.join(proj_dir+os.sep,'renders')
self.le_proj_path.setText(p)
make_render_folders.populate_spots_list(self)
#pyqtSignature("")
def on_actionConfig_triggered(self):
print "config"
self.prefs.show()
#pyqtSignature("")
def on_actionQuit_triggered(self):
print "ActionQuit"
#pyqtSignature("")
def on_btn_get_folders_released(self):
make_render_folders.populate_spots_list(self)
def on_lst_spots_itemClicked (self):
print "got you"
self.lst_shots.clear()
make_render_folders.populate_shot_list(self)
Thanks !!!
Event handling for the Prefs window can go anywhere. Personally I always prefer to give each window its own file.
So the py files would look something like:
Mainwindow.py (Main form events etc)
Ui_make_render_folders.py (Qt Designer generated UI)
prefs.py (Prefs form events etc)
ui_prefs.py (Qt Designer generated UI)
your other files...
Initialisation: (MainWindow.py)
from PyQt4.QtGui import QMainWindow
from Ui_make_render_folders import Ui_MainWindow
#prefs here refers to the file: prefs.py. PrefWindow is the class within this file.
from prefs import PrefWindow
class MainWindow(QMainWindow):
def __init__(self, parent=None):
#Better way to initialise
super(MainWindow, self).__init__(parent)
self.main = Ui_MainWindow()
self.main.setupUi(self)
#initialise prefs to variable
self.prefs = PrefWindow(self)
# Rest of init...
Note: initialising of second form will be similar to above.
You should place all events for prefs form within its class.
From the function that calls Prefs:
#pyqtSlot()
def on_actionConfig_triggered(self):
print "config"
self.prefs.exec_() # Will block main window while its open.
# Use self.prefs.show() if you want user to be able to interact with main window
Finally: pyqtSignature
On http://pyqt.sourceforge.net/Docs/PyQt4/old_style_signals_slots.html it states that:
'The QtCore.pyqtSignature() serves the same purpose as the pyqtSlot() decorator but has a less Pythonic API.'
Better to use pyqtSlot()

GTK TreeView with ListStore don't display anything. Python and SQLite3 used

I use GTK and Python for developing an application.
I want to load TreeView elements (1 column) from SQLite3 database.
But something go wrong (without any error)!
Here is a whole code:
#!/usr/bin/python
import sys
import sqlite3 as sqlite
from gi.repository import Gtk
from gi.repository import Notify
def notify(notifer, text, notificationtype=""):
Notify.init("Application")
notification = Notify.Notification.new (notifer, text, notificationtype)
notification.show ()
def get_object(gtkname):
builder = Gtk.Builder()
builder.add_from_file("main.ui")
return builder.get_object(gtkname)
def base_connect(basefile):
return sqlite.connect(basefile)
class Handler:
def main_destroy(self, *args):
Gtk.main_quit(*args)
def hardwaretool_clicked(self, widget):
baselist = get_object("subjectlist")
baselist.clear()
base = base_connect("subjectbase")
with base:
cur = base.cursor()
cur.execute("SELECT * FROM sub")
while True:
row = cur.fetchone()
if row == None:
break
iter = baselist.append()
print "row ", row[0]
baselist.set(iter, 0, row[0])
cur.close()
def gamestool_clicked(self, widget):
print("gamestool clicked!!!!! =)")
def appstool_clicked(self, widget):
print("appstool clicked!!!!! =)")
def fixtool_clicked(self, widget):
notify("Charmix","Fix Applied", "dialog-ok")
def brokenfixtool_clicked(self, widget):
notify("Charmix","Broken Fix Report Sended", "dialog-error")
def sendfixtool_clicked(self, widget):
notify("Charmix","Fix Sended", "dialog-information")
class CharmixMain:
def __init__(self):
builder = Gtk.Builder()
builder.add_from_file("main.ui")
self.window = builder.get_object("main")
self.subject = builder.get_object("subjectlist")
self.problem = builder.get_object("problemlist")
self.toolbar = builder.get_object("toolbar")
self.hardwaretool = builder.get_object("hardwaretool")
self.gamestool = builder.get_object("gamestool")
self.appstool = builder.get_object("appstool")
self.fixtool = builder.get_object("fixtool")
self.brokenfixtool = builder.get_object("brokenfixtool")
self.sendfixtool = builder.get_object("sendfixtool")
builder.connect_signals(Handler())
context = self.toolbar.get_style_context()
context.add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)
if __name__ == "__main__":
Charmix = CharmixMain()
Charmix.window.show()
Gtk.main()
I'm interested in this part (not working normally):
def hardwaretool_clicked(self, widget):
baselist = get_object("subjectlist")
baselist.clear()
base = base_connect("subjectbase")
with base:
cur = base.cursor()
cur.execute("SELECT * FROM sub")
while True:
row = cur.fetchone()
if row == None:
break
iter = baselist.append()
print "row ", row[0]
baselist.set(iter, 0, row[0])
cur.close()
TreeView(subjecttree) don't display anything, but print "row ", row[0] works fine and display all the strings.
Please, help me.
Maybe i need to repaint TreeView or thomething like that?
Do you know, how can I get it?
The problem is in your get_object method.
When you do:
builder = Gtk.Builder()
builder.add_from_file("main.ui")
you're actually creating a new window; even if you are using the same ui file, you are creating a completely different widget.
One way to get around the problem of accesing the widgets you need to process with your handler is to pass them as parameter of the constructor:
class Handler(object):
def __init__(self, widget1, widget2):
self.widget1 = widget1
self.widget2 = widget2
...
You can use those widgets on the handler's method afterwards.
Another way of accesing the widgets in a more 'decoupled' way is to add the object you want to use as the last parameter of the connect method when you're connecting signals; the drawback is that you would have to do this manually (since Glade doesn't provide this posibility)
self.widget.connect('some-signal', handler.handler_method, object_to_use)

how to raise a WidgetActionExecutionError for multiple fields with z3cform?

I'm using a form where I want to have the required field missing error on many fields depending on the value of one other field.
The use case: the use have to choose between two shipping mode (postale or print). if postale is choosen but fields about address has not been filled I want to raise the error.
Here is some code
class ILivraisonForm(interface.Interface):
livraison = schema.Choice(title=_(u"Mode de livraison"),
vocabulary=vocabulary.livraison)
livraison_civility = schema.Choice(title=_(u"Civility (livraison)"),
vocabulary=userdata.gender_vocabulary,
required=False)
livraison_name = schema.TextLine(title=_(u"Name (livraison)"),
required=False)
livraison_firstname = schema.TextLine(title=_(u"Firstname (livraison)"),
required=False)
livraison_add1 = schema.TextLine(title=_(u"Address line 1 (livraison)"),
required=False)
livraison_add2 = schema.TextLine(title=_(u"Address line 2 (livraison)"),
required=False)
livraison_pc = schema.TextLine(title=_(u"Postal code (livraison)"),
required=False)
livraison_city = schema.TextLine(title=_(u"City (livraison)"),
required=False)
livraison_phone = schema.TextLine(title=_(u"Phone"),
required=False)
accepted = schema.Bool(title=_(u"Accept CGV"),
description=_(u"Click here to read the CGV"),
required=True)
class LivraisonForm(form.Form):
fields = field.Fields(ILivraisonForm)
#button.buttonAndHandler(_(u"Valider"))
def handleApply(self, action):
data, errors = self.extractData()
message = IStatusMessage(self.request)
if errors:
self.status = _(u"Please fix errors")
return
if not data['accepted']:
self.status = _(u'You must accept')
raise WidgetActionExecutionError('accepted',
interface.Invalid(_(u'You must accept')))
if data['livraison'] == 'mail' \
and ( not data['livraison_name'] or not data['livraison_firstname'] \
or not data['livraison_add1'] or not data['livraison_pc'] \
or not data['livraison_city']):
self.status = _(u'You must add your postal address')
raise ???
You don't need to raise anything; just add a return instead of a raise right where you are.
In addition, you can set error messages on individual widgets in an action handler, provided you create a zope.schema.ValidationError subclass:
from zope.schema import ValidationError
class AddressMissing(ValidationError):
__doc__ = _(u'error_noaddress', u'Please provide an address')
and then in the handler:
from z3c.form.interfaces import IErrorViewSnippet
from zope import component
def handleApply(self, action):
# ....
widget = self.widgets['livraison_add1']
error = component.getMultiAdapter(
(AddressMissing(), self.request, widget, widget.field,
self, self.context), interfaces.IErrorViewSnippet)
error.update()
widget.error = error
You can do this for all affected widgets.
Alternatively, you can have this handled using an invariant:
from zope.interface import invariant, Invalid
class ILivraisonForm(interface.Interface):
# ....
#invariant
def validatePostalAddress(data):
if data.livraison. != 'mail':
return
for field in ('name', 'firstname', 'add1', 'pc', 'city'):
if not data['livraison_' + field]:
raise Invalid(_(u'error_noaddress', u'Please provide an address'))
and the error will be set when you call self.extractData().

Resources