Skip to content

Commit 20a052a

Browse files
committed
initial commit
0 parents  commit 20a052a

File tree

9 files changed

+255
-0
lines changed

9 files changed

+255
-0
lines changed

.gitignore

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
5+
# C extensions
6+
*.so
7+
8+
# Distribution / packaging
9+
.Python
10+
env/
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
/lib/
17+
lib64/
18+
parts/
19+
sdist/
20+
var/
21+
*.egg-info/
22+
.installed.cfg
23+
*.egg
24+
25+
# PyInstaller
26+
# Usually these files are written by a python script from a template
27+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
28+
*.manifest
29+
*.spec
30+
31+
# Installer logs
32+
pip-log.txt
33+
pip-delete-this-directory.txt
34+
35+
# Unit test / coverage reports
36+
htmlcov/
37+
.tox/
38+
.coverage
39+
.cache
40+
nosetests.xml
41+
coverage.xml
42+
43+
# Translations
44+
*.mo
45+
*.pot
46+
47+
# Django stuff:
48+
*.log
49+
tests/openwisp2/media/
50+
tests/openwisp2/firmware/
51+
!tests/openwisp2/firmware/fake-img*.bin
52+
53+
# Sphinx documentation
54+
docs/_build/
55+
56+
# PyBuilder
57+
target/
58+
59+
# editors
60+
*.komodoproject
61+
.vscode
62+
63+
# other
64+
*.DS_Store*
65+
*~
66+
._*
67+
local_settings.py
68+
*.db
69+
*.tar.gz
70+
Pipfile
71+
72+
# celery
73+
tests/celerybeat*
74+
75+
# pycharm
76+
.idea

HISTORY.MD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
History

README.MD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
django-json-model-widget

json_model_widget/__init__.py

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{% load static %}
2+
3+
<style>
4+
.form-block {
5+
margin-left: 170px;
6+
}
7+
8+
.jsonwidgetbutton {
9+
padding: 10px 15px;
10+
}
11+
12+
.cursor {
13+
cursor: pointer;
14+
}
15+
</style>
16+
17+
<div class="form-block">
18+
19+
<div id="fieldjson">
20+
{% for k,v in json.items %}
21+
<p id="jsonrow{{ name }}{{ forloop.counter }}">
22+
<select name="jsonkey{{ name }}">
23+
{% for pair in col1 %}
24+
<option value="{{ pair.id }}"
25+
{% if pair.id== k|add:
26+
"0" %}selected{% endif %}>{{ pair }}</option>
27+
{% endfor %}
28+
</select>
29+
<select name="jsonvalue{{ name }}">
30+
{% for pair in col2 %}
31+
<option value="{{ pair.id }}" {% if pair.id== v %}selected{% endif %}>{{ pair }}</option>
32+
{% endfor %}
33+
</select>
34+
<img class="delete-row-button cursor" src="{% static 'json_model_widget/images/icon-deletepair.svg' %}"
35+
alt="False">
36+
</p>
37+
38+
{% endfor %}
39+
</div>
40+
41+
<input class="jsonwidgetbutton" type="button" id="but" onclick="addrow()" value="Добавить пару"/>
42+
43+
<script type="text/javascript">
44+
if (!$) {
45+
$ = django.jQuery;
46+
}
47+
48+
$(document).on('click', '.delete-row-button', function () {
49+
$(this).parent('p').remove()
50+
})
51+
52+
function addrow() {
53+
console.log("ok");
54+
$("#fieldjson").append(`<p><select name="jsonkey{{ name }}">
55+
{% for pair in col1 %}
56+
<option value="{{ pair.id }}">{{ pair }}</option>
57+
{% endfor %}
58+
</select>
59+
<select name="jsonvalue{{ name }}">
60+
{% for pair in col2 %}
61+
<option value="{{ pair.id }}">{{ pair }}</option>
62+
{% endfor %}
63+
</select>
64+
<img class="delete-row-button cursor" src="{% static 'json_model_widget/images/icon-deletepair.svg' %}" alt="False">
65+
</p>`)
66+
};
67+
</script>
68+
69+
</div>

json_model_widget/widgets.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import json
2+
3+
from django.forms import Widget
4+
from django.template.loader import render_to_string
5+
6+
7+
class JsonPairInputs(Widget):
8+
"""
9+
A widget to display JsonField as a list of select field pairs that represent two models.
10+
11+
Usage:
12+
class ArticleAdminForm(forms.ModelForm):
13+
class Meta:
14+
widgets = {
15+
'authors': JsonPairInputs(User, Role)
16+
}
17+
18+
"""
19+
20+
def __init__(self, model1, model2, *args, **kwargs):
21+
"""
22+
A widget to display JsonField as a list of select field pairs that represent two models.
23+
24+
kwargs:
25+
key_attrs -- html attributes applied to the 1st input box pairs
26+
val_attrs -- html attributes applied to the 2nd input box pairs
27+
28+
"""
29+
self.key_attrs = {}
30+
self.val_attrs = {}
31+
if "key_attrs" in kwargs:
32+
self.key_attrs = kwargs.pop("key_attrs")
33+
if "val_attrs" in kwargs:
34+
self.val_attrs = kwargs.pop("val_attrs")
35+
Widget.__init__(self, *args, **kwargs)
36+
37+
self.col1 = model1.objects.all()
38+
self.col2 = model2.objects.all()
39+
40+
def render(self, name, value, attrs=None, renderer=None) -> str:
41+
"""
42+
43+
Renders widget into an html string
44+
45+
:param name: field name
46+
:param value: json string of a two-tuple list automatically passed in by django
47+
:param attrs: automatically passed in by django (unused)
48+
:param renderer: automatically passed in by django (unused)
49+
:return: rendered string
50+
"""
51+
if value is None or value.strip() is '':
52+
value = '{}'
53+
54+
context = {
55+
"col1": self.col1,
56+
"col2": self.col2,
57+
"json": json.loads(value),
58+
"name": name
59+
}
60+
61+
return render_to_string('json_model_widget/json_model_widget.html', context=context)
62+
63+
def value_from_datadict(self, data, files, name) -> str:
64+
"""
65+
Returns the json representation of the key-value pairs
66+
sent in the POST parameters
67+
68+
:param data: request.POST or request.GET parameters
69+
:param files: request.FILES
70+
:param name: the name of the field associated with this widget
71+
:return: stringified json
72+
"""
73+
res = {}
74+
75+
if f'jsonkey{name}' in data and f'jsonvalue{name}' in data:
76+
keys = data.getlist(f'jsonkey{name}')
77+
values = list(map(int, data.getlist(f'jsonvalue{name}')))
78+
res = dict(zip(keys, values))
79+
return json.dumps(res)

requirements.txt

126 Bytes
Binary file not shown.

setup.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from setuptools import setup, find_packages
2+
3+
with open('README.md') as readme_file:
4+
README = readme_file.read()
5+
6+
with open('HISTORY.md') as history_file:
7+
HISTORY = history_file.read()
8+
9+
setup_args = dict(
10+
name='django-json-model-widget',
11+
version='0.0.1',
12+
description='Custom flat json field widget for model pairs',
13+
long_description_content_type="text/markdown",
14+
long_description=README + '\n\n' + HISTORY,
15+
license='MIT',
16+
packages=find_packages(),
17+
author='Oleg Galichkin',
18+
author_email='galij899@yandex.ru',
19+
keywords=['django', 'django-admin', 'django-admin-widget'],
20+
url='https://github.com/galij899',
21+
download_url='https://pypi.org/project/'
22+
)
23+
24+
if __name__ == '__main__':
25+
setup(**setup_args)

0 commit comments

Comments
 (0)