Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
memopol
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
32
Issues
32
List
Boards
Labels
Service Desk
Milestones
Merge Requests
6
Merge Requests
6
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Political Memory
memopol
Commits
1125cbf6
Commit
1125cbf6
authored
Oct 13, 2016
by
Nicolas Joyard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add autocomplete to search forms
parent
c334858e
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
142 additions
and
126 deletions
+142
-126
setup.py
setup.py
+1
-1
src/memopol/context_processors.py
src/memopol/context_processors.py
+7
-12
src/memopol/forms.py
src/memopol/forms.py
+77
-0
src/memopol/settings.py
src/memopol/settings.py
+1
-1
src/memopol/static/css/custom.css
src/memopol/static/css/custom.css
+3
-3
src/memopol/templates/_base_search.html
src/memopol/templates/_base_search.html
+14
-108
src/memopol/urls.py
src/memopol/urls.py
+13
-0
src/memopol/views/autocomplete.py
src/memopol/views/autocomplete.py
+26
-1
No files found.
setup.py
View file @
1125cbf6
...
...
@@ -11,7 +11,7 @@ setup(name='political-memory',
author_email
=
'cortex@worlddomination.be'
,
url
=
'http://github.com/political-memory/political_memory/'
,
install_requires
=
[
'django-autocomplete-light==3.
1.6
'
,
'django-autocomplete-light==3.
2.0
'
,
'django-autoslug>=1.9,<1.10'
,
'django-bootstrap3>=6,<7'
,
'django-coffeescript>=0.7,<0.8'
,
...
...
src/memopol/context_processors.py
View file @
1125cbf6
from
.forms
import
DossierSearchForm
,
RepresentativeSearchForm
from
memopol_settings.models
import
Setting
from
representatives.models
import
Chamber
,
Group
def
search_form_options
(
request
):
d
=
{}
# Note: Those queries needs to be eval in the template so that we can cache
# it efficiently
d
[
'chambers'
]
=
Chamber
.
objects
.
all
()
d
[
'countries'
]
=
Group
.
objects
.
filter
(
kind
=
'country'
)
d
[
'parties'
]
=
Group
.
objects
.
filter
(
kind
=
'group'
)
d
[
'delegations'
]
=
Group
.
objects
.
filter
(
kind
=
'delegation'
)
d
[
'committees'
]
=
Group
.
objects
.
filter
(
kind
=
'committee'
)
return
d
def
search_forms
(
request
):
return
{
'representative_search_form'
:
RepresentativeSearchForm
(
request
.
GET
),
'dossier_search_form'
:
DossierSearchForm
(
request
.
GET
)
}
def
intro_text
(
request
):
...
...
src/memopol/forms.py
0 → 100644
View file @
1125cbf6
from
django
import
forms
from
dal
import
autocomplete
,
forward
from
representatives.models
import
Chamber
,
Group
,
Representative
from
representatives_votes.models
import
Dossier
class
RepresentativeSearchForm
(
forms
.
Form
):
search
=
forms
.
CharField
(
required
=
False
,
label
=
'Name'
,
widget
=
forms
.
TextInput
(
attrs
=
{
'placeholder'
:
''
})
)
scoremin
=
forms
.
FloatField
(
required
=
False
,
label
=
'Between'
,
widget
=
forms
.
NumberInput
(
attrs
=
{
'placeholder'
:
'Min. score'
})
)
scoremax
=
forms
.
FloatField
(
required
=
False
,
label
=
'and'
,
widget
=
forms
.
NumberInput
(
attrs
=
{
'placeholder'
:
'Max. score'
})
)
chamber
=
forms
.
ModelChoiceField
(
queryset
=
Chamber
.
objects
.
all
(),
required
=
False
,
widget
=
autocomplete
.
ModelSelect2
(
url
=
'chamber-autocomplete'
,
)
)
country
=
forms
.
ModelChoiceField
(
queryset
=
Group
.
objects
.
filter
(
kind
=
'country'
),
required
=
False
,
widget
=
autocomplete
.
ModelSelect2
(
url
=
'group-autocomplete'
,
forward
=
(
forward
.
Const
(
'country'
,
'kind'
),)
)
)
party
=
forms
.
ModelChoiceField
(
queryset
=
Group
.
objects
.
filter
(
kind
=
'group'
),
required
=
False
,
widget
=
autocomplete
.
ModelSelect2
(
url
=
'group-autocomplete'
,
forward
=
(
forward
.
Const
(
'group'
,
'kind'
),)
)
)
committee
=
forms
.
ModelChoiceField
(
queryset
=
Group
.
objects
.
filter
(
kind
=
'committee'
),
required
=
False
,
widget
=
autocomplete
.
ModelSelect2
(
url
=
'group-autocomplete'
,
forward
=
(
forward
.
Const
(
'committee'
,
'kind'
),)
)
)
delegation
=
forms
.
ModelChoiceField
(
queryset
=
Group
.
objects
.
filter
(
kind
=
'delegation'
),
required
=
False
,
widget
=
autocomplete
.
ModelSelect2
(
url
=
'group-autocomplete'
,
forward
=
(
forward
.
Const
(
'delegation'
,
'kind'
),)
)
)
class
DossierSearchForm
(
forms
.
Form
):
search
=
forms
.
CharField
(
required
=
False
,
label
=
'Name'
,
widget
=
forms
.
TextInput
(
attrs
=
{
'placeholder'
:
''
})
)
chamber
=
forms
.
ModelChoiceField
(
queryset
=
Chamber
.
objects
.
all
(),
required
=
False
,
widget
=
autocomplete
.
ModelSelect2
(
url
=
'chamber-autocomplete'
,
)
)
src/memopol/settings.py
View file @
1125cbf6
...
...
@@ -133,7 +133,7 @@ TEMPLATE_LOADERS = (
TEMPLATE_CONTEXT_PROCESSORS
=
global_settings
.
TEMPLATE_CONTEXT_PROCESSORS
+
(
'django.template.context_processors.request'
,
'memopol.context_processors.search_form
_option
s'
,
'memopol.context_processors.search_forms'
,
'memopol.context_processors.intro_text'
)
...
...
src/memopol/static/css/custom.css
View file @
1125cbf6
...
...
@@ -99,7 +99,7 @@ label {
font-weight
:
400
;
}
.form-control
,
input
,
textarea
{
.form-control
,
.control-label
,
input
,
textarea
{
color
:
#212121
!important
;
}
...
...
@@ -129,7 +129,7 @@ label {
box-shadow
:
inset
0
1px
1px
rgba
(
0
,
0
,
0
,
0.075
),
0
0
8px
rgba
(
102
,
175
,
233
,
0.6
);
}
textarea
,
textarea
.form-control
,
input
.form-control
,
input
[
type
=
text
],
input
[
type
=
password
],
input
[
type
=
email
],
input
[
type
=
number
],
[
type
=
text
]
.form-control
,
[
type
=
password
]
.form-control
,
[
type
=
email
]
.form-control
,
[
type
=
tel
]
.form-control
,
[
contenteditable
]
.form-control
{
textarea
,
textarea
.form-control
,
input
.form-control
,
input
[
type
=
text
],
input
[
type
=
number
],
input
[
type
=
password
],
input
[
type
=
email
],
input
[
type
=
number
],
[
type
=
text
]
.form-control
,
[
type
=
number
]
.form-control
,
[
type
=
password
]
.form-control
,
[
type
=
email
]
.form-control
,
[
type
=
tel
]
.form-control
,
[
contenteditable
]
.form-control
{
padding
:
0
;
border
:
none
;
border-radius
:
0
;
...
...
@@ -138,7 +138,7 @@ textarea, textarea.form-control, input.form-control, input[type=text], input[typ
box-shadow
:
inset
0
-1px
0
#ddd
;
}
textarea
:focus
,
textarea
.form-control
:focus
,
input
.form-control
:focus
,
input
[
type
=
text
]
:focus
,
input
[
type
=
password
]
:focus
,
input
[
type
=
email
]
:focus
,
input
[
type
=
number
]
:focus
,
[
type
=
text
]
.form-control
:focus
,
[
type
=
password
]
.form-control
:focus
,
[
type
=
email
]
.form-control
:focus
,
[
type
=
tel
]
.form-control
:focus
,
[
contenteditable
]
.form-control
:focus
{
textarea
:focus
,
textarea
.form-control
:focus
,
input
.form-control
:focus
,
input
[
type
=
text
]
:focus
,
input
[
type
=
number
]
:focus
,
input
[
type
=
password
]
:focus
,
input
[
type
=
email
]
:focus
,
input
[
type
=
number
]
:focus
,
[
type
=
text
]
.form-control
:focus
,
[
type
=
number
]
.form-control
:focus
,
[
type
=
password
]
.form-control
:focus
,
[
type
=
email
]
.form-control
:focus
,
[
type
=
tel
]
.form-control
:focus
,
[
contenteditable
]
.form-control
:focus
{
-webkit-box-shadow
:
inset
0
-2px
0
#487ED6
;
box-shadow
:
inset
0
-2px
0
#487ED6
;
}
...
...
src/memopol/templates/_base_search.html
View file @
1125cbf6
{% load i18n memopol_tags %}
{% load fontawesome %}
{% load bootstrap3 %}
<form
class=
"form-horizontal hidden-print"
method=
"GET"
action=
"{% url "
representative-list
"
%}"
>
<div
class=
"input-group"
>
...
...
@@ -30,97 +31,20 @@
aria-expanded=
"{% if view == 'representative_list' and filter.data %}true{% else %}false{% endif %}"
id=
"form-rep"
>
<form
id=
"rep-search-form"
class=
"form-horizontal"
method=
"GET"
action=
"{% url "
representative-list
"
%}"
>
<div
class=
"form-group"
>
<label
class=
"col-sm-3"
for=
"search-rep"
>
{% trans "Name" %}
</label
>
<div
class=
"col-
sm-9
"
>
<input
type=
"text"
class=
"form-control"
name=
"search"
id=
"search-rep"
value=
"{{ filter.data.search }}"
>
{% bootstrap_field representative_search_form.search layout='horizontal' %}
<div
class=
"row"
>
<div
class=
"col-
md-7
"
>
{% bootstrap_field representative_search_form.scoremin layout='horizontal' horizontal_label_class='col-md-5' horizontal_field_class='col-md-7' placeholder='prout' %}
</div>
</div>
<div
class=
"form-group"
>
<label
class=
"col-sm-3"
for=
"score-min"
>
{% trans "Score between" %}
</label>
<div
class=
"col-sm-4"
>
<input
type=
"number"
class=
"form-control"
name=
"scoremin"
id=
"score-min"
value=
"{{ filter.data.scoremin }}"
>
</div>
<label
class=
"col-sm-1"
for=
"score-max"
>
{% trans "and" %}
</label>
<div
class=
"col-sm-4"
>
<input
type=
"number"
class=
"form-control"
name=
"scoremax"
id=
"score-max"
value=
"{{ filter.data.scoremax }}"
>
</div>
</div>
<div
class=
"form-group"
>
<label
class=
"col-sm-3"
for=
"chamber-rep"
>
{% trans "Chamber" %}
</label>
<div
class=
"col-sm-9"
>
<select
class=
"form-control"
id=
"chamber-rep"
name=
"chamber"
>
<option
value=
""
>
{% trans "All" %}
</option>
{% for chamber in chambers %}
<option
{%
if
filter.data.chamber =
chamber.id|cast_str
%}
selected
{%
endif
%}
value=
"{{ chamber.id }}"
>
{{ chamber.name }}
</option>
{% endfor %}
</select>
</div>
</div>
<div
class=
"form-group"
>
<label
class=
"col-sm-3"
for=
"country"
>
{% trans "Country" %}
</label>
<div
class=
"col-sm-9"
>
<select
class=
"form-control"
id=
"country"
name=
"country"
>
<option
value=
""
>
{% trans "All" %}
</option>
{% for country in countries %}
<option
{%
if
filter.data.country =
country.id|cast_str
%}
selected
{%
endif
%}
value=
"{{ country.id }}"
>
{% if country.abbreviation %}{{ country.abbreviation }}
–
{% endif %}
{{ country.name }}
</option>
{% endfor %}
</select>
</div>
</div>
<div
class=
"form-group"
>
<label
class=
"col-sm-3"
for=
"party"
>
{% trans "Party" %}
</label>
<div
class=
"col-sm-9"
>
<select
class=
"form-control"
id=
"party"
name=
"party"
>
<option
value=
""
>
{% trans "All" %}
</option>
{% for party in parties %}
<option
{%
if
filter.data.party =
party.pk|cast_str
%}
selected
{%
endif
%}
value=
"{{ party.pk }}"
>
{% if party.abbreviation %}{{ party.abbreviation }}
–
{% endif %}
{{ party.name }}
</option>
{% endfor %}
</select>
<div
class=
"col-md-5"
>
{% bootstrap_field representative_search_form.scoremax layout='horizontal' horizontal_label_class='col-md-2' horizontal_field_class='col-md-10' %}
</div>
</div>
<div
class=
"form-group"
>
<label
class=
"col-sm-3"
for=
"committee"
>
{% trans "Committee" %}
</label>
<div
class=
"col-sm-9"
>
<select
class=
"form-control"
id=
"committee"
name=
"committee"
>
<option
value=
""
>
{% trans "All" %}
</option>
{% for committee in committees %}
<option
{%
if
filter.data.committee =
committee.pk|cast_str
%}
selected
{%
endif
%}
value=
"{{ committee.pk }}"
data-url=
"{% url "
representative-list
"
%}?
committee=
{{
committee.pk
}}"
>
{% if committee.abbreviation %}{{ committee.abbreviation }}
–
{% endif %}
{{ committee.name }}
</option>
{% endfor %}
</select>
</div>
</div>
<div
class=
"form-group"
>
<label
class=
"col-sm-3"
for=
"delegation"
>
{% trans "Delegation" %}
</label>
<div
class=
"col-sm-9"
>
<select
class=
"form-control"
id=
"delegation"
name=
"delegation"
>
<option
value=
""
>
{% trans "All" %}
</option>
{% for delegation in delegations %}
<option
{%
if
filter.data.delegation =
delegation.pk|cast_str
%}
selected
{%
endif
%}
value=
"{{ delegation.pk }}"
data-url=
"{% url "
representative-list
"
%}?
delegation=
{{
delegation.pk
}}"
>
{{ delegation.name }}
</option>
{% endfor %}
</select>
</div>
</div>
{% bootstrap_field representative_search_form.chamber layout='horizontal' %}
{% bootstrap_field representative_search_form.country layout='horizontal' %}
{% bootstrap_field representative_search_form.party layout='horizontal' %}
{% bootstrap_field representative_search_form.committee layout='horizontal' %}
{% bootstrap_field representative_search_form.delegation layout='horizontal' %}
<button
type=
"submit"
class=
"btn btn-default"
>
{% trans "Search" %}
</button>
</form>
</div>
...
...
@@ -133,26 +57,8 @@
<div
class=
"collapse{% if view == 'dossier_list' and filter.data %} in{% endif %}"
aria-expanded=
"{% if view == 'dossier_list' and filter.data %}true{% else %}false{% endif %}"
id=
"form-dossier"
>
<form
id=
"dossier-search-form"
class=
"form-horizontal"
method=
"GET"
action=
"{% url "
dossier-list
"
%}"
>
<div
class=
"form-group"
>
<label
class=
"col-sm-3"
for=
"search-dossier"
>
{% trans "Name" %}
</label>
<div
class=
"col-sm-9"
>
<input
type=
"text"
class=
"form-control"
name=
"search"
id=
"search-dossier"
value=
"{{ filter.data.search }}"
>
</div>
</div>
<div
class=
"form-group"
>
<label
class=
"col-sm-3"
for=
"chamber-dossier"
>
{% trans "Chamber" %}
</label>
<div
class=
"col-sm-9"
>
<select
class=
"form-control"
name=
"chamber"
id=
"chamber-dossier"
>
<option
value=
""
>
{% trans "All" %}
</option>
{% for chamber in chambers %}
<option
{%
if
filter.data.chamber =
chamber.id|cast_str
%}
selected
{%
endif
%}
value=
"{{ chamber.id }}"
>
{{ chamber.name }}
</option>
{% endfor %}
</select>
</div>
</div>
{% bootstrap_field dossier_search_form.search layout='horizontal' %}
{% bootstrap_field dossier_search_form.chamber layout='horizontal' %}
<button
type=
"submit"
class=
"btn btn-default"
>
{% trans "Search" %}
</button>
</form>
...
...
src/memopol/urls.py
View file @
1125cbf6
...
...
@@ -9,6 +9,8 @@ from views.autocomplete import (
ProposalAutocomplete
,
RepresentativeAutocomplete
,
ThemeAutocomplete
,
ChamberAutocomplete
,
GroupAutocomplete
,
)
from
views.charts
import
ThemeScoresJSONView
,
ChamberScoresJSONView
...
...
@@ -146,6 +148,17 @@ urlpatterns = [
name
=
'theme-autocomplete'
,
),
url
(
r
'^autocomplete/chamber/$'
,
ChamberAutocomplete
.
as_view
(),
name
=
'chamber-autocomplete'
,
),
url
(
r
'^autocomplete/group/$'
,
GroupAutocomplete
.
as_view
(),
name
=
'group-autocomplete'
,
),
# Theme list
...
...
src/memopol/views/autocomplete.py
View file @
1125cbf6
...
...
@@ -4,7 +4,7 @@ from dal import autocomplete
from
django.db.models
import
Q
from
representatives.models
import
Representative
from
representatives.models
import
Representative
,
Chamber
,
Group
from
representatives_votes.models
import
Proposal
from
memopol_themes.models
import
Theme
...
...
@@ -43,3 +43,28 @@ class ThemeAutocomplete(autocomplete.Select2QuerySetView):
qs
=
qs
.
filter
(
name__icontains
=
self
.
q
)
return
qs
class
ChamberAutocomplete
(
autocomplete
.
Select2QuerySetView
):
def
get_queryset
(
self
):
qs
=
Chamber
.
objects
.
all
()
if
self
.
q
:
qs
=
qs
.
filter
(
Q
(
name__icontains
=
self
.
q
)
|
Q
(
abbreviation__icontains
=
self
.
q
))
return
qs
class
GroupAutocomplete
(
autocomplete
.
Select2QuerySetView
):
def
get_queryset
(
self
):
qs
=
Group
.
objects
.
all
()
kind
=
self
.
forwarded
.
get
(
'kind'
,
None
)
if
kind
:
qs
=
qs
.
filter
(
kind
=
kind
)
if
self
.
q
:
qs
=
qs
.
filter
(
Q
(
name__icontains
=
self
.
q
))
return
qs
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment