Skip to content

Commit 57770bd

Browse files
committed
Library:
Jam.py can now be deployed on PythonAnywhere. See How to deploy project on PythonAnywhere Directory of the project can be passed to the create_application function now (jam/wsgi.py module). Multiprocessing connection pool parameter removed from project Parameters Bugs related to processing of keyboard events by forms fixed Some bugs fixed Documentation: How to section created. That section will contain code examples that can be useful to quickly accomplish common tasks.
1 parent 344c5cb commit 57770bd

26 files changed

+4045
-75
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ dist/
77
build/
88
docs/_build/
99
*.xml
10-
*.lock
1110
/admin/
1211
/jam_docs/
1312
/css/
@@ -29,4 +28,5 @@ doc/_build/
2928
os
3029
jam*.zip
3130
wsgi.conf
31+
langs.lock
3232
xchanges.txt

demo/admin.sqlite

0 Bytes
Binary file not shown.

demo/static/files/tracks.csv

+3,505
Large diffs are not rendered by default.

docs/admin/_images/parameters.png

-1.45 KB
Loading

docs/admin/project/parameters.txt

+5-13
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,12 @@ On the General tab, you can specify general parameters of the project:
2727

2828
* **Debugging** - if this button is checked, the Werkzeug libarary bebugger will
2929
be invoked when an error on the server occurs.
30+
31+
* **Persistent connection** - if this checkbox is checked the application creates
32+
a connection pool otherwise a connection is created before executing sql query.
3033

3134
* **Connection pool size** — the size of the server database connection pool.
3235

33-
* **Multiprocessing connection pool** - if this checkbox is checked the framework
34-
creates connection pool by using multiprocessing python module - the
35-
connections will be created in different processes.
36-
37-
* **Persistent connection** - if this checkbox is checked and multiprocessing
38-
connection pool is selected, the framework creates connection in the main
39-
process. Before executing any statement, the framework checks if this
40-
connection is busy, if not, the statment is executed by this connection,
41-
otherwise multiprocessing connection pool is used.
42-
4336
* **Compressed JS, CSS files** - If this button is checked the server returns
4437
compressed *js* and *css* files when *index.html* page is loaded.
4538

@@ -79,9 +72,8 @@ On the General tab, you can specify general parameters of the project:
7972
* **Version** — specify the version of the project here.
8073

8174
.. note::
82-
When **Connection pool size**, **Multiprocessing connection pool** or
83-
**Persistent connection** parameters are changed, the server applicaton must be
84-
restarted for changes to take effect.
75+
When **Connection pool size** or **Persistent connection** parameters are
76+
changed, the server applicaton must be restarted for changes to take effect.
8577

8678

8779
Interface tab

docs/contents.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ Jam.py documentation contents
77

88
index
99

10-
.. toctree::
10+
.. toctree::
1111
:maxdepth: 3
1212

1313
intro/index
1414
programming/index
1515
faq/index
16+
how to/index
1617
admin/index
1718
refs/index
1819
releases/index
+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
=================================
2+
Export to / import from csv files
3+
=================================
4+
5+
First, in the client module of the item we create two buttons that execute the
6+
corresponding functions when you click on them:
7+
8+
.. code-block:: js
9+
10+
function on_view_form_created(item) {
11+
var csv_import_btn = item.add_view_button('Import csv file'),
12+
csv_export_btn = item.add_view_button('Export csv file');
13+
csv_import_btn.click(function() { csv_import(item) });
14+
csv_export_btn.click(function() { csv_export(item) });
15+
}
16+
17+
function csv_export(item) {
18+
item.server('export_scv', function(file_name, error) {
19+
if (error) {
20+
item.alert_error(error);
21+
}
22+
else {
23+
var url = [location.protocol, '//', location.host, location.pathname].join('');
24+
url += 'static/files/' + file_name;
25+
window.open(encodeURI(url));
26+
}
27+
});
28+
}
29+
30+
function csv_import(item) {
31+
task.upload('static/files', {callback: function(file_name) {
32+
item.server('import_scv', [file_name], function(error) {
33+
if (error) {
34+
item.warning(error);
35+
}
36+
item.refresh_page(true);
37+
});
38+
}});
39+
}
40+
41+
These functions execute the following functions defined in the server module.
42+
In this module we use the Python csv module. We do not export system fields -
43+
primary key field and deletion flag field.
44+
45+
Below is the code for Python 3:
46+
47+
.. code-block:: py
48+
49+
import os
50+
import csv
51+
52+
def export_scv(item):
53+
copy = item.copy()
54+
copy.open()
55+
file_name = item.item_name + '.csv'
56+
path = os.path.join(item.task.work_dir, 'static', 'files', file_name)
57+
with open(path, 'w', encoding='utf-8') as csvfile:
58+
fieldnames = []
59+
for field in copy.fields:
60+
if not field.system_field():
61+
fieldnames.append(field.field_name)
62+
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
63+
writer.writeheader()
64+
for c in copy:
65+
dic = {}
66+
for field in copy.fields:
67+
if not field.system_field():
68+
dic[field.field_name] = field.text
69+
writer.writerow(dic)
70+
return file_name
71+
72+
def import_scv(item, file_name):
73+
copy = item.copy()
74+
path = os.path.join(item.task.work_dir, 'static', 'files', file_name)
75+
with open(path, 'r', encoding='utf-8') as csvfile:
76+
copy.open(open_empty=True)
77+
reader = csv.DictReader(csvfile)
78+
for row in reader:
79+
print(row)
80+
copy.append()
81+
for field in copy.fields:
82+
if not field.system_field():
83+
field.text = row[field.field_name]
84+
copy.post()
85+
copy.apply()
86+
87+
For Python 2, this code looks like this:
88+
89+
.. code-block:: py
90+
91+
import os
92+
import csv
93+
94+
def export_scv2(item):
95+
copy = item.copy()
96+
copy.open()
97+
file_name = item.item_name + '.csv'
98+
path = os.path.join(item.task.work_dir, 'static', 'files', file_name)
99+
with open(path, 'wb') as csvfile:
100+
fieldnames = []
101+
for field in copy.fields:
102+
if not field.system_field():
103+
fieldnames.append(field.field_name.encode('utf8'))
104+
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
105+
writer.writeheader()
106+
for c in copy:
107+
dic = {}
108+
for field in copy.fields:
109+
if not field.system_field():
110+
dic[field.field_name.encode('utf8')] = field.text.encode('utf8')
111+
writer.writerow(dic)
112+
return file_name
113+
114+
def import_scv2(item, file_name):
115+
copy = item.copy()
116+
path = os.path.join(item.task.work_dir, 'static', 'files', file_name)
117+
with open(path, 'rb') as csvfile:
118+
item.task.execute('delete from %s' % item.table_name)
119+
copy.open(open_empty=True)
120+
reader = csv.DictReader(csvfile)
121+
for row in reader:
122+
print(row)
123+
copy.append()
124+
for field in copy.fields:
125+
if not field.system_field():
126+
field.text = row[field.field_name.encode('utf8')].decode('utf8')
127+
copy.post()
128+
copy.apply()

docs/how to/global_scripts.txt

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
==================================================
2+
How do I write functions which have a global scope
3+
==================================================
4+
5+
Each function defined in the server or client module of an item becomes an
6+
attribute of the item.
7+
8+
Thus, using the
9+
:doc:`task tree </programming/task_tree>`,
10+
you can access any function declared in the client or server module in any
11+
project module.
12+
13+
For example, if we have a function ``some_func`` declared in the Customers client
14+
module, we can execute it in any module of the project.
15+
Note that the task is a global variable on the client.
16+
17+
.. code-block:: js
18+
19+
task.customers.some_func()
20+
21+
On the server, the task is not global, but an item that triggered / called it is
22+
passed to each event handler and function called by the
23+
:doc:`server </refs/client/abstr_item/m_server>`
24+
method. Therefore, if the ``some_func`` function is declared in the Customers
25+
server module, it can be executed in a function or event handler as follows:
26+
27+
.. code-block:: js
28+
29+
def on_apply(item, delta, params):
30+
item.task.customers.some_func()
31+
32+
33+
Note that event handlers are just functions and can also be called from other
34+
modules.
35+
36+
37+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
=============================
2+
How to add a button to a form
3+
=============================
4+
5+
The simplest way to add a button to an edit / view from is to use
6+
:doc:`add_edit_button </refs/client/item/m_add_edit_button>` /
7+
:doc:`add_view_button </refs/client/item/m_add_view_button>`
8+
correspondinly. You can call this functions in the
9+
:doc:`on_edit_form_created </refs/client/item/on_edit_form_created>` /
10+
:doc:`on_view_form_created </refs/client/item/on_view_form_created>`
11+
event handlers.
12+
13+
For example the Customers item uses this code in its client module to add
14+
buttons to a view form:
15+
16+
.. code-block:: js
17+
18+
function on_view_form_created(item) {
19+
item.table_options.multiselect = false;
20+
if (!item.lookup_field) {
21+
var print_btn = item.add_view_button('Print', {image: 'icon-print'}),
22+
email_btn = item.add_view_button('Send email', {image: 'icon-pencil'});
23+
email_btn.click(function() { send_email() });
24+
print_btn.click(function() { print(item) });
25+
item.table_options.multiselect = true;
26+
}
27+
}
28+
29+
In this code the item's
30+
:doc:`lookup_field </refs/client/item/at_lookup_field>`
31+
attribute is checkув and if it is defined (the view form is not created to select a
32+
value for a lookup field) the two buttons are created and for them JQuery click
33+
events are assigned to ``send_email`` and ``print`` functions declared in that
34+
module.
35+
36+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
=======================================
2+
How to deploy project on PythonAnywhere
3+
=======================================
4+
5+
* In Application Builder, set the **Persistent connection** attribute in the
6+
:doc:`Project parameters </admin/project/parameters>`
7+
to ``false``.
8+
9+
You can do this later in the Application Builder after deployment.
10+
In this case, you must restart the server.
11+
12+
* Use pip to install Jam.py. To do this, open the bash console and run the
13+
following command (for Python 3.7):
14+
15+
.. code-block:: console
16+
17+
pip3.7 install --user jam.py
18+
19+
* Create a zip archive of your project folder, upload the archive in the **Files**
20+
tab and unzip it.
21+
22+
We assume that you are registered as *username* and your project is now located
23+
in the */home/username/project_folder* directory.
24+
25+
* Open the **Web** Tab. Add a new web app. In the Code section specify
26+
27+
* Source code: */home/username/project_folder*
28+
29+
* Working directory: */home/username/project_folder*
30+
31+
In the WSGI configuration file:/var/www/username_pythonanywhere_com_wsgi.py file
32+
add the following code
33+
34+
.. code-block:: py
35+
36+
import os
37+
import sys
38+
39+
path = '/home/username/project_folder'
40+
if path not in sys.path:
41+
sys.path.append(path)
42+
43+
from jam.wsgi import create_application
44+
application = create_application(path)
45+
46+
* Reload the server.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
=================================
2+
how to execute script from client
3+
=================================
4+
5+
6+
You can use
7+
:doc:`server </refs/client/abstr_item/m_server>`
8+
method to send a request to the server to execute a function defined in the
9+
server module of an item.
10+
11+
En the example below we create the ``btn`` button that is a JQuery object.
12+
Then we use its click method to attach a function that calls the
13+
:doc:`server </refs/client/abstr_item/m_server>`
14+
method of the item to run the ``calculate`` function defined in the server module
15+
of the item.
16+
17+
The code in the client module:
18+
19+
.. code-block:: js
20+
21+
function on_view_form_created(item) {
22+
var btn = item.add_view_button('Calculate', {type: 'primary'});
23+
btn.click(function() {
24+
item.server('calulate', [1, 2, 3], function(result, error) {
25+
if (error) {
26+
item.alert_error(error);
27+
}
28+
else {
29+
console.log(result);
30+
}
31+
})
32+
});
33+
}
34+
35+
36+
The code in the server module:
37+
38+
.. code-block:: py
39+
40+
def calculate(item, a, b, c):
41+
return a + b + c

docs/how to/index.txt

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
======
2+
How to
3+
======
4+
5+
Here is a useful code that you can use in your applications:
6+
7+
.. toctree::
8+
:maxdepth: 2
9+
10+
global_scripts
11+
how_to_add_a_button_to_a_form
12+
how_to_execute_script_from_client
13+
to_append_a_record_without_view_form
14+
export_import_csv_files
15+
how_to_deploy_project_on_pythonanywhere

0 commit comments

Comments
 (0)