├── .coveragerc
├── .gitignore
├── .travis.yml
├── LICENSE
├── MANIFEST.in
├── README.md
├── base.json
├── docs
├── Makefile
├── conf.py
├── index.rst
└── search_box.png
├── fabfile.py
├── manage.py
├── requirements.txt
├── requirements
├── common.txt
├── dev.txt
├── preprod.txt
├── prod.txt
└── test.txt
├── search_listview
├── __init__.py
├── forms.py
├── list.py
├── settings
│ ├── __init__.py
│ ├── base.py
│ ├── dev.py
│ ├── preprod.py
│ ├── prod.py
│ ├── test.py
│ └── unittest.py
├── static
│ └── search_listview
│ │ └── js
│ │ └── search_listview.js
├── templates
│ ├── base.html
│ └── search_listview
│ │ ├── pagination.html
│ │ ├── search_and_page.html
│ │ └── search_box.html
├── tests
│ ├── __init__.py
│ ├── admin.py
│ ├── fixture.json
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── templates
│ │ └── tests
│ │ │ ├── list.html
│ │ │ ├── list_reverse.html
│ │ │ └── list_reverse_brand.html
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── urls.py
└── wsgi.py
├── setup.py
└── tox.ini
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | source = search_listview/
3 | omit = search_listview/settings/*
4 | search_listview/wsgi.py
5 | **/__*
6 | **/tests.py
7 | **/migrations*
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.py[cod]
2 | __pycache__
3 |
4 | # C extensions
5 | *.so
6 |
7 | # Packages
8 | *.egg
9 | *.egg-info
10 | dist
11 | build
12 | eggs
13 | parts
14 | bin
15 | var
16 | sdist
17 | develop-eggs
18 | .installed.cfg
19 | lib
20 | lib64
21 |
22 | # Sphinx
23 | _build
24 | _static
25 | _template
26 |
27 | # Installer logs
28 | pip-log.txt
29 |
30 | # Unit test / coverage reports
31 | .coverage
32 | .tox
33 | nosetests.xml
34 | htmlcov/
35 |
36 | # Translations
37 | *.mo
38 |
39 | # Mr Developer
40 | .mr.developer.cfg
41 | .project
42 | .pydevproject
43 | .settings
44 | *.sublime-*
45 | .fab_tasks~
46 | *.db
47 |
48 | .coverage*
49 |
50 | env*
51 | .vscode*
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - "3.5"
4 | install:
5 | - pip install coveralls
6 | - pip install tox
7 | script: tox
8 | after_success: coveralls
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Quentin SCHROTER
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 | include requirements.txt
3 | recursive-include search_listview/static *
4 | recursive-include search_listview/templates/search_listview *.html
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Django-SearchableListView
2 | =========================
3 |
4 | [](https://travis-ci.org/SchroterQuentin/django-search-listview)
5 | [](https://coveralls.io/github/SchroterQuentin/Django-SearchableListView)
6 | [](https://landscape.io/github/SchroterQuentin/django-search-listview/master)
7 |
8 | ListView which can be searchable, paginate and which doesn't lose query parameter and page number
9 |
10 | Installation
11 | ------------
12 |
13 | This library need jQuery ( and Bootstrap for the frond-end )
14 | To install it in your vitualenv on your django project
15 |
16 | ```{r, engine='bash', count_lines}
17 | pip install django-search-listview
18 | ```
19 |
20 | ```python
21 | INSTALLED_APPS = [
22 | ...
23 | 'search_listview',
24 | ]
25 | ```
26 |
27 |
28 | Only paginate ListView
29 | ----------------------
30 |
31 | ```python
32 | from search_listview.list import SearchableListView
33 |
34 | class ListDevicePaginate(SearchableListView):
35 | model = Device
36 | template_name = "tests/list.html"
37 | paginate_by = 10
38 | ```
39 |
40 | Paginate + Searchable ListView
41 | ------------------------------
42 |
43 | ```python
44 | from search_listview.list import SearchableListView
45 |
46 | class ListDeviceSearchablePaginate(SearchableListView):
47 | model = Device
48 | template_name = "tests/list.html"
49 | paginate_by = 10
50 | searchable_fields = ["inventory_number", "model_device", "model_device__brand__provider",
51 | "model_device__brand__name"]
52 | specifications = {
53 | "model_device__brand__name": "__icontains"
54 | }
55 | ```
56 |
57 | Put the parameter for the query in **searchable_fields** which will be use to filter the queryset. The specifications which be use in the same way.
58 |
59 | In the template
60 | ---------------
61 |
62 | - Where you want the pagination and the search box
63 |
64 | ```html
65 |
66 | {% include "search_listview/search_and_page.html" %}
67 |
68 | ```
69 |
70 | - In the footer
71 |
72 | ```html
73 |
74 |
75 |
78 | ```
79 |
80 | Now you have a beautifull box with all the fields you need.
81 |
82 | 
83 |
--------------------------------------------------------------------------------
/base.json:
--------------------------------------------------------------------------------
1 | [{"model": "tests.provider", "pk": 1, "fields": {"name": "Provider0"}}, {"model": "tests.provider", "pk": 2, "fields": {"name": "Provider1"}}, {"model": "tests.provider", "pk": 3, "fields": {"name": "Provider2"}}, {"model": "tests.provider", "pk": 4, "fields": {"name": "provider3"}}, {"model": "tests.provider", "pk": 5, "fields": {"name": "ProviderApple"}}, {"model": "tests.brand", "pk": 1, "fields": {"provider": [1, 2], "name": "HTC"}}, {"model": "tests.brand", "pk": 2, "fields": {"provider": [2, 3, 4], "name": "Samsung"}}, {"model": "tests.brand", "pk": 3, "fields": {"provider": [5], "name": "Apple"}}, {"model": "tests.modeldevice", "pk": 1, "fields": {"name": "M9", "brand": 1}}, {"model": "tests.modeldevice", "pk": 2, "fields": {"name": "A9", "brand": 1}}, {"model": "tests.modeldevice", "pk": 3, "fields": {"name": "Iphone6s", "brand": 3}}, {"model": "tests.modeldevice", "pk": 4, "fields": {"name": "Iphone7", "brand": 3}}, {"model": "tests.modeldevice", "pk": 5, "fields": {"name": "Galaxy", "brand": 2}}, {"model": "tests.device", "pk": 1, "fields": {"inventory_number": 1, "model_device": 1}}, {"model": "tests.device", "pk": 2, "fields": {"inventory_number": 2, "model_device": 1}}, {"model": "tests.device", "pk": 3, "fields": {"inventory_number": 3, "model_device": 1}}, {"model": "tests.device", "pk": 4, "fields": {"inventory_number": 4, "model_device": 1}}, {"model": "tests.device", "pk": 5, "fields": {"inventory_number": 5, "model_device": 1}}, {"model": "tests.device", "pk": 6, "fields": {"inventory_number": 10, "model_device": 2}}, {"model": "tests.device", "pk": 7, "fields": {"inventory_number": 11, "model_device": 2}}, {"model": "tests.device", "pk": 8, "fields": {"inventory_number": 12, "model_device": 2}}, {"model": "tests.device", "pk": 9, "fields": {"inventory_number": 13, "model_device": 2}}, {"model": "tests.device", "pk": 10, "fields": {"inventory_number": 14, "model_device": 2}}, {"model": "tests.device", "pk": 11, "fields": {"inventory_number": 20, "model_device": 3}}, {"model": "tests.device", "pk": 12, "fields": {"inventory_number": 21, "model_device": 3}}, {"model": "tests.device", "pk": 13, "fields": {"inventory_number": 22, "model_device": 3}}, {"model": "tests.device", "pk": 14, "fields": {"inventory_number": 23, "model_device": 3}}, {"model": "tests.device", "pk": 15, "fields": {"inventory_number": 24, "model_device": 3}}, {"model": "tests.device", "pk": 16, "fields": {"inventory_number": 25, "model_device": 3}}, {"model": "tests.device", "pk": 17, "fields": {"inventory_number": 26, "model_device": 3}}, {"model": "tests.device", "pk": 18, "fields": {"inventory_number": 27, "model_device": 4}}, {"model": "tests.device", "pk": 19, "fields": {"inventory_number": 28, "model_device": 4}}, {"model": "tests.device", "pk": 20, "fields": {"inventory_number": 29, "model_device": 4}}, {"model": "tests.device", "pk": 21, "fields": {"inventory_number": 30, "model_device": 4}}, {"model": "tests.device", "pk": 22, "fields": {"inventory_number": 31, "model_device": 4}}, {"model": "tests.device", "pk": 23, "fields": {"inventory_number": 32, "model_device": 4}}, {"model": "tests.device", "pk": 24, "fields": {"inventory_number": 100, "model_device": 5}}, {"model": "tests.device", "pk": 25, "fields": {"inventory_number": 101, "model_device": 5}}, {"model": "tests.device", "pk": 26, "fields": {"inventory_number": 102, "model_device": 5}}, {"model": "tests.device", "pk": 27, "fields": {"inventory_number": 103, "model_device": 5}}, {"model": "tests.device", "pk": 28, "fields": {"inventory_number": 104, "model_device": 5}}, {"model": "tests.device", "pk": 29, "fields": {"inventory_number": 105, "model_device": 5}}, {"model": "tests.device", "pk": 30, "fields": {"inventory_number": 106, "model_device": 5}}, {"model": "tests.device", "pk": 31, "fields": {"inventory_number": 107, "model_device": 5}}, {"model": "tests.device", "pk": 32, "fields": {"inventory_number": 108, "model_device": 5}}, {"model": "tests.device", "pk": 33, "fields": {"inventory_number": 109, "model_device": 5}}, {"model": "tests.device", "pk": 34, "fields": {"inventory_number": 110, "model_device": 5}}, {"model": "tests.device", "pk": 35, "fields": {"inventory_number": 111, "model_device": 5}}, {"model": "tests.device", "pk": 36, "fields": {"inventory_number": 112, "model_device": 5}}, {"model": "tests.device", "pk": 37, "fields": {"inventory_number": 113, "model_device": 5}}, {"model": "tests.device", "pk": 38, "fields": {"inventory_number": 114, "model_device": 5}}, {"model": "tests.device", "pk": 39, "fields": {"inventory_number": 115, "model_device": 5}}, {"model": "tests.device", "pk": 41, "fields": {"inventory_number": 211, "model_device": 1}}, {"model": "tests.device", "pk": 42, "fields": {"inventory_number": 212, "model_device": 1}}, {"model": "tests.device", "pk": 43, "fields": {"inventory_number": 213, "model_device": 1}}, {"model": "tests.device", "pk": 44, "fields": {"inventory_number": 214, "model_device": 1}}, {"model": "tests.device", "pk": 45, "fields": {"inventory_number": 215, "model_device": 1}}, {"model": "tests.device", "pk": 46, "fields": {"inventory_number": 2110, "model_device": 2}}, {"model": "tests.device", "pk": 47, "fields": {"inventory_number": 2111, "model_device": 2}}, {"model": "tests.device", "pk": 48, "fields": {"inventory_number": 2112, "model_device": 2}}, {"model": "tests.device", "pk": 49, "fields": {"inventory_number": 2113, "model_device": 2}}, {"model": "tests.device", "pk": 91, "fields": {"inventory_number": 901, "model_device": 1}}, {"model": "tests.device", "pk": 92, "fields": {"inventory_number": 902, "model_device": 1}}, {"model": "tests.device", "pk": 93, "fields": {"inventory_number": 903, "model_device": 1}}, {"model": "tests.device", "pk": 94, "fields": {"inventory_number": 904, "model_device": 1}}, {"model": "tests.device", "pk": 95, "fields": {"inventory_number": 905, "model_device": 1}}, {"model": "tests.device", "pk": 96, "fields": {"inventory_number": 9010, "model_device": 2}}, {"model": "tests.device", "pk": 97, "fields": {"inventory_number": 9011, "model_device": 2}}, {"model": "tests.device", "pk": 98, "fields": {"inventory_number": 9012, "model_device": 2}}, {"model": "tests.device", "pk": 99, "fields": {"inventory_number": 9013, "model_device": 2}}, {"model": "tests.device", "pk": 410, "fields": {"inventory_number": 2114, "model_device": 2}}, {"model": "tests.device", "pk": 411, "fields": {"inventory_number": 2120, "model_device": 3}}, {"model": "tests.device", "pk": 412, "fields": {"inventory_number": 2121, "model_device": 3}}, {"model": "tests.device", "pk": 413, "fields": {"inventory_number": 2122, "model_device": 3}}, {"model": "tests.device", "pk": 414, "fields": {"inventory_number": 2123, "model_device": 3}}, {"model": "tests.device", "pk": 415, "fields": {"inventory_number": 2124, "model_device": 3}}, {"model": "tests.device", "pk": 416, "fields": {"inventory_number": 2125, "model_device": 3}}, {"model": "tests.device", "pk": 417, "fields": {"inventory_number": 2126, "model_device": 3}}, {"model": "tests.device", "pk": 418, "fields": {"inventory_number": 2127, "model_device": 4}}, {"model": "tests.device", "pk": 419, "fields": {"inventory_number": 2128, "model_device": 4}}, {"model": "tests.device", "pk": 420, "fields": {"inventory_number": 2129, "model_device": 4}}, {"model": "tests.device", "pk": 421, "fields": {"inventory_number": 2130, "model_device": 4}}, {"model": "tests.device", "pk": 422, "fields": {"inventory_number": 2131, "model_device": 4}}, {"model": "tests.device", "pk": 423, "fields": {"inventory_number": 2132, "model_device": 4}}, {"model": "tests.device", "pk": 424, "fields": {"inventory_number": 21100, "model_device": 5}}, {"model": "tests.device", "pk": 425, "fields": {"inventory_number": 21101, "model_device": 5}}, {"model": "tests.device", "pk": 426, "fields": {"inventory_number": 21102, "model_device": 5}}, {"model": "tests.device", "pk": 427, "fields": {"inventory_number": 21103, "model_device": 5}}, {"model": "tests.device", "pk": 428, "fields": {"inventory_number": 21104, "model_device": 5}}, {"model": "tests.device", "pk": 429, "fields": {"inventory_number": 21105, "model_device": 5}}, {"model": "tests.device", "pk": 430, "fields": {"inventory_number": 21106, "model_device": 5}}, {"model": "tests.device", "pk": 431, "fields": {"inventory_number": 21107, "model_device": 5}}, {"model": "tests.device", "pk": 432, "fields": {"inventory_number": 21108, "model_device": 5}}, {"model": "tests.device", "pk": 433, "fields": {"inventory_number": 21109, "model_device": 5}}, {"model": "tests.device", "pk": 434, "fields": {"inventory_number": 21110, "model_device": 5}}, {"model": "tests.device", "pk": 435, "fields": {"inventory_number": 21111, "model_device": 5}}, {"model": "tests.device", "pk": 436, "fields": {"inventory_number": 21112, "model_device": 5}}, {"model": "tests.device", "pk": 437, "fields": {"inventory_number": 21113, "model_device": 5}}, {"model": "tests.device", "pk": 438, "fields": {"inventory_number": 21114, "model_device": 5}}, {"model": "tests.device", "pk": 439, "fields": {"inventory_number": 21115, "model_device": 5}}, {"model": "tests.device", "pk": 910, "fields": {"inventory_number": 9014, "model_device": 2}}, {"model": "tests.device", "pk": 911, "fields": {"inventory_number": 9020, "model_device": 3}}, {"model": "tests.device", "pk": 912, "fields": {"inventory_number": 9021, "model_device": 3}}, {"model": "tests.device", "pk": 913, "fields": {"inventory_number": 9022, "model_device": 3}}, {"model": "tests.device", "pk": 914, "fields": {"inventory_number": 9023, "model_device": 3}}, {"model": "tests.device", "pk": 915, "fields": {"inventory_number": 9024, "model_device": 3}}, {"model": "tests.device", "pk": 916, "fields": {"inventory_number": 9025, "model_device": 3}}, {"model": "tests.device", "pk": 917, "fields": {"inventory_number": 9026, "model_device": 3}}, {"model": "tests.device", "pk": 918, "fields": {"inventory_number": 9027, "model_device": 4}}, {"model": "tests.device", "pk": 919, "fields": {"inventory_number": 9028, "model_device": 4}}, {"model": "tests.device", "pk": 920, "fields": {"inventory_number": 9029, "model_device": 4}}, {"model": "tests.device", "pk": 921, "fields": {"inventory_number": 9030, "model_device": 4}}, {"model": "tests.device", "pk": 922, "fields": {"inventory_number": 9031, "model_device": 4}}, {"model": "tests.device", "pk": 923, "fields": {"inventory_number": 9032, "model_device": 4}}, {"model": "tests.device", "pk": 924, "fields": {"inventory_number": 90100, "model_device": 5}}, {"model": "tests.device", "pk": 925, "fields": {"inventory_number": 90101, "model_device": 5}}, {"model": "tests.device", "pk": 926, "fields": {"inventory_number": 90102, "model_device": 5}}, {"model": "tests.device", "pk": 927, "fields": {"inventory_number": 90103, "model_device": 5}}, {"model": "tests.device", "pk": 928, "fields": {"inventory_number": 90104, "model_device": 5}}, {"model": "tests.device", "pk": 929, "fields": {"inventory_number": 90105, "model_device": 5}}, {"model": "tests.device", "pk": 930, "fields": {"inventory_number": 90106, "model_device": 5}}, {"model": "tests.device", "pk": 931, "fields": {"inventory_number": 90107, "model_device": 5}}, {"model": "tests.device", "pk": 932, "fields": {"inventory_number": 90108, "model_device": 5}}, {"model": "tests.device", "pk": 933, "fields": {"inventory_number": 90109, "model_device": 5}}, {"model": "tests.device", "pk": 934, "fields": {"inventory_number": 90110, "model_device": 5}}, {"model": "tests.device", "pk": 935, "fields": {"inventory_number": 90111, "model_device": 5}}, {"model": "tests.device", "pk": 936, "fields": {"inventory_number": 90112, "model_device": 5}}, {"model": "tests.device", "pk": 937, "fields": {"inventory_number": 90113, "model_device": 5}}, {"model": "tests.device", "pk": 938, "fields": {"inventory_number": 90114, "model_device": 5}}, {"model": "tests.device", "pk": 939, "fields": {"inventory_number": 90115, "model_device": 5}}, {"model": "tests.device", "pk": 941, "fields": {"inventory_number": 90211, "model_device": 1}}, {"model": "tests.device", "pk": 942, "fields": {"inventory_number": 90212, "model_device": 1}}, {"model": "tests.device", "pk": 943, "fields": {"inventory_number": 90213, "model_device": 1}}, {"model": "tests.device", "pk": 944, "fields": {"inventory_number": 90214, "model_device": 1}}, {"model": "tests.device", "pk": 945, "fields": {"inventory_number": 90215, "model_device": 1}}, {"model": "tests.device", "pk": 946, "fields": {"inventory_number": 902110, "model_device": 2}}, {"model": "tests.device", "pk": 947, "fields": {"inventory_number": 902111, "model_device": 2}}, {"model": "tests.device", "pk": 948, "fields": {"inventory_number": 902112, "model_device": 2}}, {"model": "tests.device", "pk": 949, "fields": {"inventory_number": 902113, "model_device": 2}}, {"model": "tests.device", "pk": 9410, "fields": {"inventory_number": 902114, "model_device": 2}}, {"model": "tests.device", "pk": 9411, "fields": {"inventory_number": 902120, "model_device": 3}}, {"model": "tests.device", "pk": 9412, "fields": {"inventory_number": 902121, "model_device": 3}}, {"model": "tests.device", "pk": 9413, "fields": {"inventory_number": 902122, "model_device": 3}}, {"model": "tests.device", "pk": 9414, "fields": {"inventory_number": 902123, "model_device": 3}}, {"model": "tests.device", "pk": 9415, "fields": {"inventory_number": 902124, "model_device": 3}}, {"model": "tests.device", "pk": 9416, "fields": {"inventory_number": 902125, "model_device": 3}}, {"model": "tests.device", "pk": 9417, "fields": {"inventory_number": 902126, "model_device": 3}}, {"model": "tests.device", "pk": 9418, "fields": {"inventory_number": 902127, "model_device": 4}}, {"model": "tests.device", "pk": 9419, "fields": {"inventory_number": 902128, "model_device": 4}}, {"model": "tests.device", "pk": 9420, "fields": {"inventory_number": 902129, "model_device": 4}}, {"model": "tests.device", "pk": 9421, "fields": {"inventory_number": 902130, "model_device": 4}}, {"model": "tests.device", "pk": 9422, "fields": {"inventory_number": 902131, "model_device": 4}}, {"model": "tests.device", "pk": 9423, "fields": {"inventory_number": 902132, "model_device": 4}}, {"model": "tests.device", "pk": 9424, "fields": {"inventory_number": 9021100, "model_device": 5}}, {"model": "tests.device", "pk": 9425, "fields": {"inventory_number": 9021101, "model_device": 5}}, {"model": "tests.device", "pk": 9426, "fields": {"inventory_number": 9021102, "model_device": 5}}, {"model": "tests.device", "pk": 9427, "fields": {"inventory_number": 9021103, "model_device": 5}}, {"model": "tests.device", "pk": 9428, "fields": {"inventory_number": 9021104, "model_device": 5}}, {"model": "tests.device", "pk": 9429, "fields": {"inventory_number": 9021105, "model_device": 5}}, {"model": "tests.device", "pk": 9430, "fields": {"inventory_number": 9021106, "model_device": 5}}, {"model": "tests.device", "pk": 9431, "fields": {"inventory_number": 9021107, "model_device": 5}}, {"model": "tests.device", "pk": 9432, "fields": {"inventory_number": 9021108, "model_device": 5}}, {"model": "tests.device", "pk": 9433, "fields": {"inventory_number": 9021109, "model_device": 5}}, {"model": "tests.device", "pk": 9434, "fields": {"inventory_number": 9021110, "model_device": 5}}, {"model": "tests.device", "pk": 9435, "fields": {"inventory_number": 9021111, "model_device": 5}}, {"model": "tests.device", "pk": 9436, "fields": {"inventory_number": 9021112, "model_device": 5}}, {"model": "tests.device", "pk": 9437, "fields": {"inventory_number": 9021113, "model_device": 5}}, {"model": "tests.device", "pk": 9438, "fields": {"inventory_number": 9021114, "model_device": 5}}, {"model": "tests.device", "pk": 9439, "fields": {"inventory_number": 9021115, "model_device": 5}}]
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # User-friendly check for sphinx-build
11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13 | endif
14 |
15 | # Internal variables.
16 | PAPEROPT_a4 = -D latex_paper_size=a4
17 | PAPEROPT_letter = -D latex_paper_size=letter
18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
19 | # the i18n builder cannot share the environment and doctrees with the others
20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21 |
22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
23 |
24 | help:
25 | @echo "Please use \`make ' where is one of"
26 | @echo " html to make standalone HTML files"
27 | @echo " dirhtml to make HTML files named index.html in directories"
28 | @echo " singlehtml to make a single large HTML file"
29 | @echo " pickle to make pickle files"
30 | @echo " json to make JSON files"
31 | @echo " htmlhelp to make HTML files and a HTML help project"
32 | @echo " qthelp to make HTML files and a qthelp project"
33 | @echo " devhelp to make HTML files and a Devhelp project"
34 | @echo " epub to make an epub"
35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
36 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
38 | @echo " text to make text files"
39 | @echo " man to make manual pages"
40 | @echo " texinfo to make Texinfo files"
41 | @echo " info to make Texinfo files and run them through makeinfo"
42 | @echo " gettext to make PO message catalogs"
43 | @echo " changes to make an overview of all changed/added/deprecated items"
44 | @echo " xml to make Docutils-native XML files"
45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes"
46 | @echo " linkcheck to check all external links for integrity"
47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
48 |
49 | clean:
50 | rm -rf $(BUILDDIR)/*
51 |
52 | html:
53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
54 | @echo
55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
56 |
57 | dirhtml:
58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
59 | @echo
60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
61 |
62 | singlehtml:
63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
64 | @echo
65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
66 |
67 | pickle:
68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
69 | @echo
70 | @echo "Build finished; now you can process the pickle files."
71 |
72 | json:
73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
74 | @echo
75 | @echo "Build finished; now you can process the JSON files."
76 |
77 | htmlhelp:
78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
79 | @echo
80 | @echo "Build finished; now you can run HTML Help Workshop with the" \
81 | ".hhp project file in $(BUILDDIR)/htmlhelp."
82 |
83 | qthelp:
84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
85 | @echo
86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django_search_model.qhcp"
89 | @echo "To view the help file:"
90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django_search_model.qhc"
91 |
92 | devhelp:
93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
94 | @echo
95 | @echo "Build finished."
96 | @echo "To view the help file:"
97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/django_search_model"
98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django_search_model"
99 | @echo "# devhelp"
100 |
101 | epub:
102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
103 | @echo
104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
105 |
106 | latex:
107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
108 | @echo
109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
111 | "(use \`make latexpdf' here to do that automatically)."
112 |
113 | latexpdf:
114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
115 | @echo "Running LaTeX files through pdflatex..."
116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
118 |
119 | latexpdfja:
120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
121 | @echo "Running LaTeX files through platex and dvipdfmx..."
122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
124 |
125 | text:
126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
127 | @echo
128 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
129 |
130 | man:
131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
132 | @echo
133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
134 |
135 | texinfo:
136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
137 | @echo
138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
139 | @echo "Run \`make' in that directory to run these through makeinfo" \
140 | "(use \`make info' here to do that automatically)."
141 |
142 | info:
143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
144 | @echo "Running Texinfo files through makeinfo..."
145 | make -C $(BUILDDIR)/texinfo info
146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
147 |
148 | gettext:
149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
150 | @echo
151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
152 |
153 | changes:
154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
155 | @echo
156 | @echo "The overview file is in $(BUILDDIR)/changes."
157 |
158 | linkcheck:
159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
160 | @echo
161 | @echo "Link check complete; look for any errors in the above output " \
162 | "or in $(BUILDDIR)/linkcheck/output.txt."
163 |
164 | doctest:
165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
166 | @echo "Testing of doctests in the sources finished, look at the " \
167 | "results in $(BUILDDIR)/doctest/output.txt."
168 |
169 | xml:
170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
171 | @echo
172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
173 |
174 | pseudoxml:
175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
176 | @echo
177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
178 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # django_search_model documentation build configuration file, created by
4 | # sphinx-quickstart on Mon Aug 25 18:11:49 2014.
5 | #
6 | # This file is execfile()d with the current directory set to its
7 | # containing dir.
8 | #
9 | # Note that not all possible configuration values are present in this
10 | # autogenerated file.
11 | #
12 | # All configuration values have a default; values that are commented out
13 | # serve to show the default.
14 |
15 | from datetime import date
16 | import sys
17 | import os
18 |
19 | # If extensions (or modules to document with autodoc) are in another directory,
20 | # add these directories to sys.path here. If the directory is relative to the
21 | # documentation root, use os.path.abspath to make it absolute, like shown here.
22 | #sys.path.insert(0, os.path.abspath('.'))
23 |
24 | # -- General configuration ------------------------------------------------
25 |
26 | # If your documentation needs a minimal Sphinx version, state it here.
27 | #needs_sphinx = '1.0'
28 |
29 | # Add any Sphinx extension module names here, as strings. They can be
30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
31 | # ones.
32 | extensions = [
33 | 'sphinx.ext.autodoc',
34 | 'sphinx.ext.doctest',
35 | ]
36 |
37 | # Add any paths that contain templates here, relative to this directory.
38 | templates_path = ['_templates']
39 |
40 | # The suffix of source filenames.
41 | source_suffix = '.rst'
42 |
43 | # The encoding of source files.
44 | #source_encoding = 'utf-8-sig'
45 |
46 | # The master toctree document.
47 | master_doc = 'index'
48 |
49 | # General information about the project.
50 | project = u'django_search_model'
51 | copyright = u'%s, Direction Informatique' % date.today().strftime("%Y")
52 |
53 | # The version info for the project you're documenting, acts as replacement for
54 | # |version| and |release|, also used in various other places throughout the
55 | # built documents.
56 | #
57 | # The short X.Y version.
58 | version = '0.1'
59 | # The full version, including alpha/beta/rc tags.
60 | release = '0.1'
61 |
62 | # The language for content autogenerated by Sphinx. Refer to documentation
63 | # for a list of supported languages.
64 | #language = None
65 |
66 | # There are two options for replacing |today|: either, you set today to some
67 | # non-false value, then it is used:
68 | #today = ''
69 | # Else, today_fmt is used as the format for a strftime call.
70 | #today_fmt = '%B %d, %Y'
71 |
72 | # List of patterns, relative to source directory, that match files and
73 | # directories to ignore when looking for source files.
74 | exclude_patterns = ['_build']
75 |
76 | # The reST default role (used for this markup: `text`) to use for all
77 | # documents.
78 | #default_role = None
79 |
80 | # If true, '()' will be appended to :func: etc. cross-reference text.
81 | #add_function_parentheses = True
82 |
83 | # If true, the current module name will be prepended to all description
84 | # unit titles (such as .. function::).
85 | #add_module_names = True
86 |
87 | # If true, sectionauthor and moduleauthor directives will be shown in the
88 | # output. They are ignored by default.
89 | #show_authors = False
90 |
91 | # The name of the Pygments (syntax highlighting) style to use.
92 | pygments_style = 'sphinx'
93 |
94 | # A list of ignored prefixes for module index sorting.
95 | #modindex_common_prefix = []
96 |
97 | # If true, keep warnings as "system message" paragraphs in the built documents.
98 | #keep_warnings = False
99 |
100 |
101 | # -- Options for HTML output ----------------------------------------------
102 |
103 | # The theme to use for HTML and HTML Help pages. See the documentation for
104 | # a list of builtin themes.
105 | html_theme = 'default'
106 |
107 | # Theme options are theme-specific and customize the look and feel of a theme
108 | # further. For a list of options available for each theme, see the
109 | # documentation.
110 | #html_theme_options = {}
111 |
112 | # Add any paths that contain custom themes here, relative to this directory.
113 | #html_theme_path = []
114 |
115 | # The name for this set of Sphinx documents. If None, it defaults to
116 | # " v documentation".
117 | #html_title = None
118 |
119 | # A shorter title for the navigation bar. Default is the same as html_title.
120 | #html_short_title = None
121 |
122 | # The name of an image file (relative to this directory) to place at the top
123 | # of the sidebar.
124 | #html_logo = None
125 |
126 | # The name of an image file (within the static path) to use as favicon of the
127 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
128 | # pixels large.
129 | #html_favicon = None
130 |
131 | # Add any paths that contain custom static files (such as style sheets) here,
132 | # relative to this directory. They are copied after the builtin static files,
133 | # so a file named "default.css" will overwrite the builtin "default.css".
134 | html_static_path = ['_static']
135 |
136 | # Add any extra paths that contain custom files (such as robots.txt or
137 | # .htaccess) here, relative to this directory. These files are copied
138 | # directly to the root of the documentation.
139 | #html_extra_path = []
140 |
141 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
142 | # using the given strftime format.
143 | #html_last_updated_fmt = '%b %d, %Y'
144 |
145 | # If true, SmartyPants will be used to convert quotes and dashes to
146 | # typographically correct entities.
147 | #html_use_smartypants = True
148 |
149 | # Custom sidebar templates, maps document names to template names.
150 | #html_sidebars = {}
151 |
152 | # Additional templates that should be rendered to pages, maps page names to
153 | # template names.
154 | #html_additional_pages = {}
155 |
156 | # If false, no module index is generated.
157 | #html_domain_indices = True
158 |
159 | # If false, no index is generated.
160 | #html_use_index = True
161 |
162 | # If true, the index is split into individual pages for each letter.
163 | #html_split_index = False
164 |
165 | # If true, links to the reST sources are added to the pages.
166 | #html_show_sourcelink = True
167 |
168 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
169 | #html_show_sphinx = True
170 |
171 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
172 | #html_show_copyright = True
173 |
174 | # If true, an OpenSearch description file will be output, and all pages will
175 | # contain a tag referring to it. The value of this option must be the
176 | # base URL from which the finished HTML is served.
177 | #html_use_opensearch = ''
178 |
179 | # This is the file name suffix for HTML files (e.g. ".xhtml").
180 | #html_file_suffix = None
181 |
182 | # Output file base name for HTML help builder.
183 | htmlhelp_basename = 'django_search_modeldoc'
184 |
185 |
186 | # -- Options for LaTeX output ---------------------------------------------
187 |
188 | latex_elements = {
189 | # The paper size ('letterpaper' or 'a4paper').
190 | #'papersize': 'letterpaper',
191 |
192 | # The font size ('10pt', '11pt' or '12pt').
193 | #'pointsize': '10pt',
194 |
195 | # Additional stuff for the LaTeX preamble.
196 | #'preamble': '',
197 | }
198 |
199 | # Grouping the document tree into LaTeX files. List of tuples
200 | # (source start file, target name, title,
201 | # author, documentclass [howto, manual, or own class]).
202 | latex_documents = [
203 | ('index', 'django_search_model.tex', u'django_search_model Documentation',
204 | u'Direction Informatique', 'manual'),
205 | ]
206 |
207 | # The name of an image file (relative to this directory) to place at the top of
208 | # the title page.
209 | #latex_logo = None
210 |
211 | # For "manual" documents, if this is true, then toplevel headings are parts,
212 | # not chapters.
213 | #latex_use_parts = False
214 |
215 | # If true, show page references after internal links.
216 | #latex_show_pagerefs = False
217 |
218 | # If true, show URL addresses after external links.
219 | #latex_show_urls = False
220 |
221 | # Documents to append as an appendix to all manuals.
222 | #latex_appendices = []
223 |
224 | # If false, no module index is generated.
225 | #latex_domain_indices = True
226 |
227 |
228 | # -- Options for manual page output ---------------------------------------
229 |
230 | # One entry per manual page. List of tuples
231 | # (source start file, name, description, authors, manual section).
232 | man_pages = [
233 | ('index', 'django_search_model', u'django_search_model Documentation',
234 | [u'Direction Informatique'], 1)
235 | ]
236 |
237 | # If true, show URL addresses after external links.
238 | #man_show_urls = False
239 |
240 |
241 | # -- Options for Texinfo output -------------------------------------------
242 |
243 | # Grouping the document tree into Texinfo files. List of tuples
244 | # (source start file, target name, title, author,
245 | # dir menu entry, description, category)
246 | texinfo_documents = [
247 | ('index', 'django_search_model', u'django_search_model Documentation',
248 | u'Direction Informatique', 'django_search_model', 'One line description of project.',
249 | 'Miscellaneous'),
250 | ]
251 |
252 | # Documents to append as an appendix to all manuals.
253 | #texinfo_appendices = []
254 |
255 | # If false, no module index is generated.
256 | #texinfo_domain_indices = True
257 |
258 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
259 | #texinfo_show_urls = 'footnote'
260 |
261 | # If true, do not generate a @detailmenu in the "Top" node's menu.
262 | #texinfo_no_detailmenu = False
263 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. django_search_model documentation master file, created by
2 | sphinx-quickstart on Mon Aug 25 18:11:49 2014.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to django_search_model's documentation!
7 | ==================================
8 |
9 | Contents:
10 |
11 | .. toctree::
12 | :maxdepth: 2
13 |
14 |
15 |
16 | Indices and tables
17 | ==================
18 |
19 | * :ref:`genindex`
20 | * :ref:`modindex`
21 | * :ref:`search`
22 |
23 |
--------------------------------------------------------------------------------
/docs/search_box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SchroterQuentin/django-search-listview/8b027a6908dc30c6ebc613bb4fde6b1ba40124a3/docs/search_box.png
--------------------------------------------------------------------------------
/fabfile.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """
4 | """
5 |
6 | from fabric.api import (env, roles, execute, task)
7 | from os.path import join
8 |
9 | import pydiploy
10 |
11 | # edit config here !
12 |
13 | env.remote_owner = 'django' # remote server user
14 | env.remote_group = 'di' # remote server group
15 |
16 | env.application_name = 'django_search_model' # name of webapp
17 | env.root_package_name = 'django_search_model' # name of app in webapp
18 |
19 | env.remote_home = '/home/django' # remote home root
20 | env.remote_python_version = '' # python version
21 | env.remote_virtualenv_root = join(env.remote_home, '.virtualenvs') # venv root
22 | env.remote_virtualenv_dir = join(env.remote_virtualenv_root,
23 | env.application_name) # venv for webapp dir
24 | # git repository url
25 | env.remote_repo_url = 'git@git.net:django_search_model.git'
26 | env.local_tmp_dir = '/tmp' # tmp dir
27 | env.remote_static_root = '/var/www/static/' # root of static files
28 | env.locale = 'fr_FR.UTF-8' # locale to use on remote
29 | env.timezone = 'Europe/Paris' # timezone for remote
30 | env.keep_releases = 2 # number of old releases to keep before cleaning
31 | env.extra_goals = ['preprod'] # add extra goal(s) to defaults (test,dev,prod)
32 | env.dipstrap_version = 'latest'
33 | env.verbose_output = False # True for verbose output
34 |
35 | # optional parameters
36 |
37 | # env.dest_path = '' # if not set using env_local_tmp_dir
38 | # env.excluded_files = ['pron.jpg'] # file(s) that rsync should exclude when deploying app
39 | # env.extra_ppa_to_install = ['ppa:vincent-c/ponysay'] # extra ppa source(s) to use
40 | # env.extra_pkg_to_install = ['ponysay'] # extra debian/ubuntu package(s) to install on remote
41 | # env.cfg_shared_files = ['config','/app/path/to/config/config_file'] # config files to be placed in shared config dir
42 | # env.extra_symlink_dirs = ['mydir','/app/mydir'] # dirs to be symlinked in shared directory
43 | # env.verbose = True # verbose display for pydiploy default value = True
44 | # env.req_pydiploy_version = "0.9" # required pydiploy version for this fabfile
45 | # env.no_config_test = False # avoid config checker if True
46 | # env.maintenance_text = "" # add a customize maintenance text for maintenance page
47 | # env.maintenance_title = "" # add a customize title for maintenance page
48 | # env.oracle_client_version = '11.2'
49 | # env.oracle_download_url = 'http://librepo.net/lib/oracle/'
50 | # env.oracle_remote_dir = 'oracle_client'
51 | # env.oracle_packages = ['instantclient-basic-linux-x86-64-11.2.0.2.0.zip',
52 | # 'instantclient-sdk-linux-x86-64-11.2.0.2.0.zip',
53 | # 'instantclient-sqlplus-linux-x86-64-11.2.0.2.0.zip']
54 | #
55 | # env.circus_package_name = 'https://github.com/morganbohn/circus/archive/master.zip'
56 | # env.no_circus_web = True
57 | # env.circus_backend = 'gevent' # name of circus backend to use
58 |
59 | env.chaussette_backend = 'waitress' # name of chaussette backend to use. You need to add this backend in the app requirement file.
60 |
61 |
62 | # env.nginx_location_extra_directives = ['proxy_read_timeout 120'] # add directive(s) to nginx config file in location part
63 | # env.nginx_start_confirmation = True # if True when nginx is not started
64 | # needs confirmation to start it.
65 |
66 |
67 | @task
68 | def dev():
69 | """Define dev stage"""
70 | env.roledefs = {
71 | 'web': ['192.168.1.2'],
72 | 'lb': ['192.168.1.2'],
73 | }
74 | env.user = 'vagrant'
75 | env.backends = env.roledefs['web']
76 | env.server_name = 'django_search_model-dev.net'
77 | env.short_server_name = 'django_search_model-dev'
78 | env.static_folder = '/site_media/'
79 | env.server_ip = '192.168.1.2'
80 | env.no_shared_sessions = False
81 | env.server_ssl_on = False
82 | env.goal = 'dev'
83 | env.socket_port = '8001'
84 | env.map_settings = {}
85 | execute(build_env)
86 |
87 |
88 | @task
89 | def test():
90 | """Define test stage"""
91 | env.roledefs = {
92 | 'web': ['django_search_model-test.net'],
93 | 'lb': ['lb.django_search_model-test.net'],
94 | }
95 | # env.user = 'root' # user for ssh
96 | env.backends = ['127.0.0.1']
97 | env.server_name = 'django_search_model-test.net'
98 | env.short_server_name = 'django_search_model-test'
99 | env.static_folder = '/site_media/'
100 | env.server_ip = ''
101 | env.no_shared_sessions = False
102 | env.server_ssl_on = True
103 | env.path_to_cert = '/etc/ssl/certs/django_search_model.net.pem'
104 | env.path_to_cert_key = '/etc/ssl/private/django_search_model.net.key'
105 | env.goal = 'test'
106 | env.socket_port = ''
107 | env.socket_host = '127.0.0.1'
108 | env.map_settings = {}
109 | execute(build_env)
110 |
111 |
112 | @task
113 | def preprod():
114 | """Define preprod stage"""
115 | env.roledefs = {
116 | 'web': ['django_search_model-pprd.net'],
117 | 'lb': ['lb.django_search_model-pprd.net'],
118 | }
119 | # env.user = 'root' # user for ssh
120 | env.backends = env.roledefs['web']
121 | env.server_name = 'django_search_model-pprd.net'
122 | env.short_server_name = 'django_search_model-pprd'
123 | env.static_folder = '/site_media/'
124 | env.server_ip = ''
125 | env.no_shared_sessions = False
126 | env.server_ssl_on = True
127 | env.path_to_cert = '/etc/ssl/certs/django_search_model.net.pem'
128 | env.path_to_cert_key = '/etc/ssl/private/django_search_model.net.key'
129 | env.goal = 'preprod'
130 | env.socket_port = ''
131 | env.map_settings = {
132 | 'default_db_host': "DATABASES['default']['HOST']",
133 | 'default_db_user': "DATABASES['default']['USER']",
134 | 'default_db_password': "DATABASES['default']['PASSWORD']",
135 | 'default_db_name': "DATABASES['default']['NAME']",
136 | 'secret_key': "SECRET_KEY",
137 | }
138 | execute(build_env)
139 |
140 |
141 | @task
142 | def prod():
143 | """Define prod stage"""
144 | env.roledefs = {
145 | 'web': ['django_search_model.net'],
146 | 'lb': ['lb.django_search_model.net']
147 | }
148 | # env.user = 'root' # user for ssh
149 | env.backends = env.roledefs['web']
150 | env.server_name = 'django_search_model.net'
151 | env.short_server_name = 'django_search_model'
152 | env.static_folder = '/site_media/'
153 | env.server_ip = ''
154 | env.no_shared_sessions = False
155 | env.server_ssl_on = True
156 | env.path_to_cert = '/etc/ssl/certs/django_search_model.net.pem'
157 | env.path_to_cert_key = '/etc/ssl/private/django_search_model.net.key'
158 | env.goal = 'prod'
159 | env.socket_port = ''
160 | env.map_settings = {
161 | 'default_db_host': "DATABASES['default']['HOST']",
162 | 'default_db_user': "DATABASES['default']['USER']",
163 | 'default_db_password': "DATABASES['default']['PASSWORD']",
164 | 'default_db_name': "DATABASES['default']['NAME']",
165 | 'secret_key': "SECRET_KEY",
166 | }
167 | execute(build_env)
168 |
169 | # dont touch after that point if you don't know what you are doing !
170 |
171 |
172 | @task
173 | def tag(version_number):
174 | """ Set the version to deploy to `version_number`. """
175 | execute(pydiploy.prepare.tag, version=version_number)
176 |
177 |
178 | @roles(['web', 'lb'])
179 | def build_env():
180 | execute(pydiploy.prepare.build_env)
181 |
182 |
183 | @task
184 | def pre_install():
185 | """Pre install of backend & frontend"""
186 | execute(pre_install_backend)
187 | execute(pre_install_frontend)
188 |
189 |
190 | @roles('web')
191 | @task
192 | def pre_install_backend():
193 | """Setup server for backend"""
194 | execute(pydiploy.django.pre_install_backend, commands='/usr/bin/rsync')
195 |
196 |
197 | @roles('lb')
198 | @task
199 | def pre_install_frontend():
200 | """Setup server for frontend"""
201 | execute(pydiploy.django.pre_install_frontend)
202 |
203 |
204 | @roles('web')
205 | @task
206 | def deploy(update_pkg=False):
207 | """Deploy code on server"""
208 | execute(deploy_backend, update_pkg)
209 | execute(deploy_frontend)
210 |
211 |
212 | @roles('web')
213 | @task
214 | def deploy_backend(update_pkg=False):
215 | """Deploy code on server"""
216 | execute(pydiploy.django.deploy_backend, update_pkg)
217 |
218 |
219 | @roles('lb')
220 | @task
221 | def deploy_frontend():
222 | """Deploy static files on load balancer"""
223 | execute(pydiploy.django.deploy_frontend)
224 |
225 |
226 | @roles('web')
227 | @task
228 | def rollback():
229 | """Rollback code (current-1 release)"""
230 | execute(pydiploy.django.rollback)
231 |
232 |
233 | @task
234 | def post_install():
235 | """post install for backend & frontend"""
236 | execute(post_install_backend)
237 | execute(post_install_frontend)
238 |
239 |
240 | @roles('web')
241 | @task
242 | def post_install_backend():
243 | """Post installation of backend"""
244 | execute(pydiploy.django.post_install_backend)
245 |
246 |
247 | @roles('lb')
248 | @task
249 | def post_install_frontend():
250 | """Post installation of frontend"""
251 | execute(pydiploy.django.post_install_frontend)
252 |
253 |
254 | @roles('web')
255 | @task
256 | def install_postgres(user=None, dbname=None, password=None):
257 | """Install Postgres on remote"""
258 | execute(pydiploy.django.install_postgres_server,
259 | user=user, dbname=dbname, password=password)
260 |
261 |
262 | @task
263 | def reload():
264 | """Reload backend & frontend"""
265 | execute(reload_frontend)
266 | execute(reload_backend)
267 |
268 |
269 | @roles('lb')
270 | @task
271 | def reload_frontend():
272 | execute(pydiploy.django.reload_frontend)
273 |
274 |
275 | @roles('web')
276 | @task
277 | def reload_backend():
278 | execute(pydiploy.django.reload_backend)
279 |
280 |
281 | @roles('lb')
282 | @task
283 | def set_down():
284 | """ Set app to maintenance mode """
285 | execute(pydiploy.django.set_app_down)
286 |
287 |
288 | @roles('lb')
289 | @task
290 | def set_up():
291 | """ Set app to up mode """
292 | execute(pydiploy.django.set_app_up)
293 |
294 |
295 | @roles('web')
296 | @task
297 | def custom_manage_cmd(cmd):
298 | """ Execute custom command in manage.py """
299 | execute(pydiploy.django.custom_manage_command, cmd)
300 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "search_listview.settings.dev")
7 |
8 | from django.core.management import execute_from_command_line
9 |
10 | execute_from_command_line(sys.argv)
11 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | -r requirements/common.txt
2 |
--------------------------------------------------------------------------------
/requirements/common.txt:
--------------------------------------------------------------------------------
1 | Django>1.8,<1.9
2 |
--------------------------------------------------------------------------------
/requirements/dev.txt:
--------------------------------------------------------------------------------
1 | -r common.txt
2 | coverage
3 | pylint
4 | django-debug-toolbar
5 | django-extensions
6 | tox
--------------------------------------------------------------------------------
/requirements/preprod.txt:
--------------------------------------------------------------------------------
1 | -r common.txt
2 | psycopg2
3 | chaussette
4 | waitress
5 |
--------------------------------------------------------------------------------
/requirements/prod.txt:
--------------------------------------------------------------------------------
1 | -r common.txt
2 | psycopg2
3 | chaussette
4 | waitress
5 |
--------------------------------------------------------------------------------
/requirements/test.txt:
--------------------------------------------------------------------------------
1 | -r common.txt
2 | chaussette
3 | waitress
4 |
--------------------------------------------------------------------------------
/search_listview/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SchroterQuentin/django-search-listview/8b027a6908dc30c6ebc613bb4fde6b1ba40124a3/search_listview/__init__.py
--------------------------------------------------------------------------------
/search_listview/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 |
3 | class PageForm(forms.Form):
4 | page = forms.IntegerField(
5 | widget=forms.HiddenInput()
6 | )
7 |
--------------------------------------------------------------------------------
/search_listview/list.py:
--------------------------------------------------------------------------------
1 | from copy import deepcopy
2 | from math import floor
3 |
4 | from django.views.generic.list import ListView
5 |
6 | from django.db.models.base import Q
7 | from django.db.models.constants import LOOKUP_SEP
8 |
9 | from django.forms import Form, MultipleChoiceField, ChoiceField
10 |
11 | from .forms import PageForm
12 |
13 | EMPTY_DICT = {'empty' : True}
14 |
15 | class SearchableListView(ListView):
16 | """
17 | ListView which can be searchable, paginate and which don't lose
18 | query parameter and page
19 | """
20 | searchable_fields = []
21 | specifications = {}
22 | nb_form_per_line = 4
23 | css_class = "form-control"
24 | disable_search_button = False
25 |
26 | def get_q_object(self):
27 | """
28 | Build Q object to filter the queryset
29 | """
30 | q_object = Q()
31 | for field in self.searchable_fields:
32 | value = self.request.GET.getlist(alias_field(self.model, field), None)
33 | mini_q = Q()
34 | for val in value:
35 | attr = "{0}{1}".format(field, self.specifications.get(field, ''))
36 | if val:
37 | dic_tmp = {
38 | attr: val
39 | }
40 | mini_q |= Q(**dic_tmp)
41 | q_object &= mini_q
42 | return q_object
43 |
44 | def get_search_form(self):
45 | """
46 | Return list of form based on model
47 | """
48 | magic_dico_form = self.get_dict_for_forms()
49 | forms = []
50 | initial = list(self.request.GET.lists())
51 |
52 | for key, value in magic_dico_form.items():
53 | form = Form()
54 | model = value["model"]
55 | if not value["fields"]:
56 | continue
57 | for field in value["fields"]:
58 | formfield = get_formfield(model, field)
59 | formfield.widget.attrs.update({'class': self.css_class})
60 | form.fields.update({
61 | field : formfield
62 | })
63 |
64 | initial_tmp = {}
65 | for k, vals in initial:
66 | tmp_list = k.split(model.__name__ + "-")
67 | if len(tmp_list) == 2:
68 | list_val_tmp = vals[0] if len(vals) == 1 else [val for val in vals if val != '']
69 | initial_tmp[tmp_list[-1]] = list_val_tmp
70 |
71 | form.initial = initial_tmp
72 | form.prefix = model.__name__
73 | forms.append(form)
74 | return sorted(forms, key=lambda form: form.prefix)
75 |
76 | def get_page_input(self, num_page):
77 | """
78 | Return hidden input which contains the page number
79 | """
80 | return PageForm(
81 | initial={
82 | "page": num_page
83 | }
84 | )
85 |
86 | def get_context_data(self, **kwargs):
87 | context = super(SearchableListView, self).get_context_data(**kwargs)
88 |
89 | forms = self.get_search_form()
90 |
91 | if context["page_obj"] is not None:
92 | page_number_form = self.get_page_input(context["page_obj"].number)
93 | else:
94 | page_number_form = None
95 |
96 | context.update({
97 | "search_box_form": forms,
98 | "search_size": max(
99 | floor(12/len(forms)),
100 | floor(12/self.nb_form_per_line)
101 | ) if len(forms) else 0,
102 | "search_page": page_number_form,
103 | "disable_search_button": self.disable_search_button
104 | })
105 | return context
106 |
107 | def get_queryset(self):
108 | self.queryset = super(SearchableListView, self).get_queryset()
109 | return self.queryset.filter(self.get_q_object()).distinct()
110 |
111 | def get_dict_for_forms(self):
112 | """
113 | Build a dictionnary where searchable_fields are
114 | next to their model to be use in modelform_factory
115 |
116 | dico = {
117 | "str(model)" : {
118 | "model" : Model,
119 | "fields" = [] #searchable_fields which are attribute of Model
120 | }
121 | }
122 | """
123 | magic_dico = field_to_dict(self.searchable_fields)
124 | dico = {}
125 |
126 | def dict_from_fields_r(mini_dict, dico, model):
127 | """
128 | Create the dico recursively from the magic_dico
129 | """
130 |
131 | dico[str(model)] = {}
132 | dico[str(model)]["model"] = model
133 | dico[str(model)]["fields"] = []
134 |
135 | for key, value in mini_dict.items():
136 | if isinstance(value, bool):
137 | continue
138 | if value == EMPTY_DICT:
139 | dico[str(model)]["fields"].append(key)
140 | elif EMPTY_DICT.items() <= value.items():
141 | dico[str(model)]["fields"].append(key)
142 | model_tmp = associate_model(model, key)
143 | dict_from_fields_r(value, dico, model_tmp)
144 | else:
145 | model_tmp = associate_model(model, key)
146 | dict_from_fields_r(value, dico, model_tmp)
147 |
148 | if magic_dico:
149 | dict_from_fields_r(magic_dico, dico, self.model)
150 | return dico
151 |
152 |
153 | def field_to_dict(fields):
154 | """
155 | Build dictionnary which dependancy for each field related to "root"
156 |
157 | fields = ["toto", "toto__tata", "titi__tutu"]
158 | dico = {
159 | "toto": {
160 | EMPTY_DICT,
161 | "tata": EMPTY_DICT
162 | },
163 | "titi" : {
164 | "tutu": EMPTY_DICT
165 | }
166 | }
167 |
168 | EMPTY_DICT is useful because we don't lose field
169 | without it dico["toto"] would only contains "tata"
170 |
171 | inspired from django.db.models.sql.add_select_related
172 | """
173 | field_dict = {}
174 | for field in fields:
175 | d_tmp = field_dict
176 | for part in field.split(LOOKUP_SEP)[:-1]:
177 | d_tmp = d_tmp.setdefault(part, {})
178 | d_tmp = d_tmp.setdefault(
179 | field.split(LOOKUP_SEP)[-1],
180 | deepcopy(EMPTY_DICT)
181 | ).update(deepcopy(EMPTY_DICT))
182 | return field_dict
183 |
184 | def alias_field(model, field):
185 | """
186 | Return the prefix name of a field
187 | """
188 | for part in field.split(LOOKUP_SEP)[:-1]:
189 | model = associate_model(model,part)
190 | return model.__name__ + "-" + field.split(LOOKUP_SEP)[-1]
191 |
192 | def associate_model(model, field):
193 | """
194 | Return the model associate to the ForeignKey or ManyToMany
195 | relation
196 | """
197 | class_field = model._meta.get_field(field)
198 | if hasattr(class_field, "field"):
199 | return class_field.field.related.related_model
200 | else:
201 | return class_field.related_model
202 |
203 | def get_formfield(model, field):
204 | """
205 | Return the formfied associate to the field of the model
206 | """
207 | class_field = model._meta.get_field(field)
208 |
209 | if hasattr(class_field, "field"):
210 | formfield = class_field.field.formfield()
211 | else:
212 | formfield = class_field.formfield()
213 |
214 | # Otherwise the formfield contain the reverse relation
215 | if isinstance(formfield, ChoiceField):
216 | formfield.choices = class_field.get_choices()
217 |
218 | return formfield
219 |
--------------------------------------------------------------------------------
/search_listview/settings/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SchroterQuentin/django-search-listview/8b027a6908dc30c6ebc613bb4fde6b1ba40124a3/search_listview/settings/__init__.py
--------------------------------------------------------------------------------
/search_listview/settings/base.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from os.path import abspath, basename, dirname, join, normpath
4 |
5 |
6 | ######################
7 | # Path configuration #
8 | ######################
9 |
10 | DJANGO_ROOT = dirname(dirname(abspath(__file__)))
11 | SITE_ROOT = dirname(DJANGO_ROOT)
12 | SITE_NAME = basename(DJANGO_ROOT)
13 |
14 |
15 | #######################
16 | # Debug configuration #
17 | #######################
18 |
19 | DEBUG = False
20 | TEMPLATE_DEBUG = DEBUG
21 |
22 |
23 | ##########################
24 | # Manager configurations #
25 | ##########################
26 |
27 | ADMINS = (
28 | # ('Your Name', 'your_email@example.com'),
29 | )
30 |
31 | MANAGERS = ADMINS
32 |
33 |
34 | ##########################
35 | # Database configuration #
36 | ##########################
37 |
38 | # In your virtualenv, edit the file $VIRTUAL_ENV/bin/postactivate and set
39 | # properly the environnement variable defined in this file (ie: os.environ[KEY]
40 | # ex: export LDAP_DB_USER='uid=toto,ou=uds,ou=people,o=annuaire
41 |
42 | # Default values for default database are :
43 | # engine : sqlite3
44 | # name : PROJECT_ROOT_DIR/django_search_model.db
45 |
46 | # defaut db connection
47 | DATABASES = {
48 | 'default': {
49 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
50 | 'NAME': 'django_search_model', # Or path to database file if using sqlite3.
51 | 'USER': '',
52 | 'PASSWORD': '',
53 | 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
54 | 'PORT': '5432', # Set to empty string for default.
55 | }
56 | }
57 |
58 |
59 | ######################
60 | # Site configuration #
61 | ######################
62 |
63 | # Hosts/domain names that are valid for this site; required if DEBUG is False
64 | # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
65 | ALLOWED_HOSTS = []
66 |
67 |
68 | #########################
69 | # General configuration #
70 | #########################
71 |
72 | # Local time zone for this installation. Choices can be found here:
73 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
74 | # although not all choices may be available on all operating systems.
75 | # In a Windows environment this must be set to your system time zone.
76 | TIME_ZONE = 'Europe/Paris'
77 |
78 | # Language code for this installation. All choices can be found here:
79 | # http://www.i18nguy.com/unicode/language-identifiers.html
80 | LANGUAGE_CODE = 'fr-FR'
81 |
82 | SITE_ID = 1
83 |
84 | # If you set this to False, Django will make some optimizations so as not
85 | # to load the internationalization machinery.
86 | USE_I18N = True
87 |
88 | # If you set this to False, Django will not format dates, numbers and
89 | # calendars according to the current locale.
90 | USE_L10N = True
91 |
92 | # If you set this to False, Django will not use timezone-aware datetimes.
93 | USE_TZ = True
94 |
95 |
96 | #######################
97 | # locale configuration #
98 | #######################
99 |
100 | LOCALE_PATHS = (normpath(join(DJANGO_ROOT, 'locale')),)
101 |
102 |
103 | #######################
104 | # Media configuration #
105 | #######################
106 |
107 | # Absolute filesystem path to the directory that will hold user-uploaded files.
108 | # Example: "/var/www/example.com/media/"
109 | MEDIA_ROOT = normpath(join(DJANGO_ROOT, 'media'))
110 |
111 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a
112 | # trailing slash.
113 | # Examples: "http://example.com/media/", "http://media.example.com/"
114 | MEDIA_URL = '/media/'
115 |
116 |
117 | ##############################
118 | # Static files configuration #
119 | ##############################
120 |
121 | # Absolute path to the directory static files should be collected to.
122 | # Don't put anything in this directory yourself; store your static files
123 | # in apps' "static/" subdirectories and in STATICFILES_DIRS.
124 | # Example: "/var/www/example.com/static/"
125 | STATIC_ROOT = normpath(join(SITE_ROOT, 'assets'))
126 |
127 | # URL prefix for static files.
128 | # Example: "http://example.com/static/", "http://static.example.com/"
129 | STATIC_URL = '/site_media/'
130 |
131 | # Additional locations of static files
132 | STATICFILES_DIRS = (
133 | normpath(join(DJANGO_ROOT, 'static')),
134 | )
135 |
136 | # List of finder classes that know how to find static files in
137 | # various locations.
138 | STATICFILES_FINDERS = (
139 | 'django.contrib.staticfiles.finders.FileSystemFinder',
140 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
141 | )
142 |
143 |
144 | ############
145 | # Dipstrap #
146 | ############
147 |
148 | DIPSTRAP_STATIC_URL = '//django-static.u-strasbg.fr/dipstrap/'
149 |
150 |
151 | ##############
152 | # Secret key #
153 | ##############
154 |
155 | # Make this unique, and don't share it with anybody.
156 | # Only for dev and test environnement. Should be redefined for production
157 | # environnement
158 | SECRET_KEY = 'ma8r116)33!-#pty4!sht8tsa(1bfe%(+!&9xfack+2e9alah!'
159 |
160 |
161 | ##########################
162 | # Template configuration #
163 | ##########################
164 |
165 | TEMPLATES = [
166 | {
167 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
168 | 'DIRS': [],
169 | 'APP_DIRS': True,
170 | 'OPTIONS': {
171 | 'context_processors': [
172 | 'django.contrib.auth.context_processors.auth',
173 | 'django.template.context_processors.debug',
174 | 'django.template.context_processors.i18n',
175 | 'django.template.context_processors.media',
176 | 'django.template.context_processors.static',
177 | 'django.template.context_processors.tz',
178 | 'django.contrib.messages.context_processors.messages',
179 | 'django.template.context_processors.request',
180 | ],
181 | },
182 | },
183 | ]
184 |
185 |
186 | ############################
187 | # Middleware configuration #
188 | ############################
189 |
190 | MIDDLEWARE_CLASSES = (
191 | 'django.contrib.sessions.middleware.SessionMiddleware',
192 | 'django.middleware.common.CommonMiddleware',
193 | 'django.middleware.csrf.CsrfViewMiddleware',
194 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
195 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
196 | 'django.contrib.messages.middleware.MessageMiddleware',
197 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
198 | 'django.middleware.security.SecurityMiddleware',
199 | )
200 |
201 |
202 | #####################
203 | # Url configuration #
204 | #####################
205 |
206 | ROOT_URLCONF = '%s.urls' % SITE_NAME
207 |
208 |
209 | ######################
210 | # WSGI configuration #
211 | ######################
212 |
213 | # Python dotted path to the WSGI application used by Django's runserver.
214 | WSGI_APPLICATION = '%s.wsgi.application' % SITE_NAME
215 |
216 |
217 | #############################
218 | # Application configuration #
219 | #############################
220 |
221 | DJANGO_APPS = (
222 | 'django.contrib.auth',
223 | 'django.contrib.contenttypes',
224 | 'django.contrib.sessions',
225 | 'django.contrib.sites',
226 | 'django.contrib.messages',
227 | 'django.contrib.staticfiles',
228 | # Uncomment the next line to enable the admin:
229 | 'django.contrib.admin',
230 | # 'django.contrib.admindocs',
231 | 'search_listview.tests',
232 | )
233 |
234 | THIRD_PARTY_APPS = ()
235 |
236 | LOCAL_APPS = (
237 | 'search_listview',
238 | )
239 |
240 | INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
241 |
242 |
243 | #########################
244 | # Session configuration #
245 | #########################
246 |
247 | SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'
248 |
249 | #####################
250 | # Log configuration #
251 | #####################
252 |
253 | # LOGGING = {
254 | # 'version': 1,
255 | # 'disable_existing_loggers': False,
256 | # 'formatters': {
257 | # 'default': {
258 | # 'format': '%(levelname)s %(asctime)s %(name)s:%(lineno)s %(message)s'
259 | # }
260 | # },
261 | # 'filters': {
262 | # 'require_debug_false': {
263 | # '()': 'django.utils.log.RequireDebugFalse'
264 | # }
265 | # },
266 | # 'handlers': {
267 | # 'null': {
268 | # 'level': 'DEBUG',
269 | # 'class': 'django.utils.log.NullHandler'
270 | # },
271 | # 'mail_admins': {
272 | # 'level': 'ERROR',
273 | # 'filters': ['require_debug_false'],
274 | # 'class': 'django.utils.log.AdminEmailHandler'
275 | # },
276 | # 'file': {
277 | # 'level': 'INFO',
278 | # 'class': 'logging.handlers.RotatingFileHandler',
279 | # 'filename': '',
280 | # 'maxBytes': 209715200,
281 | # 'backupCount': 3,
282 | # 'formatter': 'default'
283 | # }
284 | # },
285 | # 'loggers': {
286 | # 'django': {
287 | # 'handlers': ['null'],
288 | # 'propagate': True,
289 | # 'level': 'INFO'
290 | # },
291 | # 'django.request': {
292 | # 'handlers': ['mail_admins', 'file'],
293 | # 'level': 'ERROR',
294 | # 'propagate': True,
295 | # },
296 | # 'django_search_model': {
297 | # 'handlers': ['mail_admins', 'file'],
298 | # 'level': 'ERROR',
299 | # 'propagate': True
300 | # }
301 | # }
302 | # }
303 |
--------------------------------------------------------------------------------
/search_listview/settings/dev.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from os import environ
4 | from os.path import normpath
5 | from .base import *
6 |
7 | #######################
8 | # Debug configuration #
9 | #######################
10 |
11 | DEBUG = True
12 |
13 |
14 | ##########################
15 | # Database configuration #
16 | ##########################
17 |
18 | # In your virtualenv, edit the file $VIRTUAL_ENV/bin/postactivate and set
19 | # properly the environnement variable defined in this file (ie: os.environ[KEY])
20 | # ex: export DEFAULT_DB_NAME='project_name'
21 |
22 | # Default values for default database are :
23 | # engine : sqlite3
24 | # name : PROJECT_ROOT_DIR/default.db
25 |
26 |
27 | DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'
28 | DATABASES['default']['NAME'] = 'django_search_model.db'
29 |
30 |
31 | #####################
32 | # Log configuration #
33 | #####################
34 |
35 | # LOGGING['handlers']['file']['filename'] = environ.get('LOG_DIR',
36 | # normpath(join('/tmp', '%s.log' % SITE_NAME)))
37 | # LOGGING['handlers']['file']['level'] = 'DEBUG'
38 |
39 | # for logger in LOGGING['loggers']:
40 | # LOGGING['loggers'][logger]['level'] = 'DEBUG'
41 |
42 |
43 | ###########################
44 | # Unit test configuration #
45 | ###########################
46 |
47 | INSTALLED_APPS += (
48 | 'coverage',
49 | 'debug_toolbar',
50 | 'django_extensions'
51 | )
52 | TEST_RUNNER = 'django_coverage.coverage_runner.CoverageRunner'
53 |
54 | ############
55 | # Dipstrap #
56 | ############
57 |
58 | DIPSTRAP_VERSION = environ.get('DIPSTRAP_VERSION', 'latest')
59 | DIPSTRAP_STATIC_URL += '%s/' % DIPSTRAP_VERSION
60 |
61 | #################
62 | # Debug toolbar #
63 | #################
64 |
65 | DEBUG_TOOLBAR_PATCH_SETTINGS = False
66 | MIDDLEWARE_CLASSES += (
67 | 'debug_toolbar.middleware.DebugToolbarMiddleware',
68 | )
69 | INTERNAL_IPS = ('127.0.0.1', '0.0.0.0')
70 |
--------------------------------------------------------------------------------
/search_listview/settings/preprod.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from os import environ
4 | from os.path import normpath
5 | from .base import *
6 |
7 |
8 | ##########################
9 | # Database configuration #
10 | ##########################
11 |
12 | DATABASES['default']['HOST'] = '{{ default_db_host }}'
13 | DATABASES['default']['USER'] = '{{ default_db_user }}'
14 | DATABASES['default']['PASSWORD'] = '{{ default_db_password }}'
15 | DATABASES['default']['NAME'] = '{{ default_db_name }}'
16 |
17 |
18 | ############################
19 | # Allowed hosts & Security #
20 | ############################
21 |
22 | ALLOWED_HOSTS = [
23 | '.u-strasbg.fr',
24 | '.unistra.fr',
25 | ]
26 |
27 | SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'ssl')
28 |
29 |
30 | #####################
31 | # Log configuration #
32 | #####################
33 |
34 | LOGGING['handlers']['file']['filename'] = '{{ remote_current_path }}/log/app.log'
35 |
36 | ##############
37 | # Secret key #
38 | ##############
39 |
40 | SECRET_KEY = '{{ secret_key }}'
41 |
42 |
43 | ############
44 | # Dipstrap #
45 | ############
46 |
47 | DIPSTRAP_VERSION = '{{ dipstrap_version }}'
48 | DIPSTRAP_STATIC_URL += '%s/' % DIPSTRAP_VERSION
49 |
--------------------------------------------------------------------------------
/search_listview/settings/prod.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from os import environ
4 | from os.path import normpath
5 |
6 | from .base import *
7 |
8 |
9 | ##########################
10 | # Database configuration #
11 | ##########################
12 |
13 | DATABASES['default']['HOST'] = '{{ default_db_host }}'
14 | DATABASES['default']['USER'] = '{{ default_db_user }}'
15 | DATABASES['default']['PASSWORD'] = '{{ default_db_password }}'
16 | DATABASES['default']['NAME'] = '{{ default_db_name }}'
17 |
18 |
19 | ############################
20 | # Allowed hosts & Security #
21 | ############################
22 |
23 | ALLOWED_HOSTS = [
24 | '.u-strasbg.fr',
25 | '.unistra.fr',
26 | ]
27 |
28 | SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'ssl')
29 |
30 |
31 | #####################
32 | # Log configuration #
33 | #####################
34 |
35 | LOGGING['handlers']['file']['filename'] = '{{ remote_current_path }}/log/app.log'
36 |
37 | ##############
38 | # Secret key #
39 | ##############
40 |
41 | SECRET_KEY = '{{ secret_key }}'
42 |
43 |
44 | ############
45 | # Dipstrap #
46 | ############
47 |
48 | DIPSTRAP_VERSION = '{{ dipstrap_version }}'
49 | DIPSTRAP_STATIC_URL += '%s/' % DIPSTRAP_VERSION
50 |
--------------------------------------------------------------------------------
/search_listview/settings/test.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from os import environ
4 | from os.path import normpath
5 | from .base import *
6 |
7 | #######################
8 | # Debug configuration #
9 | #######################
10 |
11 | DEBUG = True
12 |
13 |
14 | ##########################
15 | # Database configuration #
16 | ##########################
17 |
18 | DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'
19 | DATABASES['default']['NAME'] = normpath(join(dirname(dirname(SITE_ROOT)), 'shared/default.db'))
20 |
21 |
22 | #####################
23 | # Log configuration #
24 | #####################
25 |
26 | # LOGGING['handlers']['file']['filename'] = '{{ remote_current_path }}/log/app.log'
27 |
28 | # for logger in LOGGING['loggers']:
29 | # LOGGING['loggers'][logger]['level'] = 'DEBUG'
30 |
31 |
32 | ############
33 | # Dipstrap #
34 | ############
35 |
36 | DIPSTRAP_VERSION = '{{ dipstrap_version }}'
37 | DIPSTRAP_STATIC_URL += '%s/' % DIPSTRAP_VERSION
38 |
--------------------------------------------------------------------------------
/search_listview/settings/unittest.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from os import environ
4 | from os.path import normpath
5 | from .base import *
6 |
7 | #######################
8 | # Debug configuration #
9 | #######################
10 |
11 | DEBUG = True
12 |
13 |
14 | ##########################
15 | # Database configuration #
16 | ##########################
17 |
18 | DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'
19 | DATABASES['default']['NAME'] = environ.get('DEFAULT_DB_NAME', 'django_search_model.db')
20 |
21 |
22 | #####################
23 | # Log configuration #
24 | #####################
25 |
26 | # LOGGING['handlers']['file']['filename'] = environ.get('LOG_DIR',
27 | # normpath(join('/tmp', 'test_%s.log' % SITE_NAME)))
28 | # LOGGING['handlers']['file']['level'] = 'DEBUG'
29 |
30 | # for logger in LOGGING['loggers']:
31 | # LOGGING['loggers'][logger]['level'] = 'DEBUG'
32 |
33 | TEST_RUNNER = 'django.test.runner.DiscoverRunner'
34 |
--------------------------------------------------------------------------------
/search_listview/static/search_listview/js/search_listview.js:
--------------------------------------------------------------------------------
1 | function change_page(i)
2 | {
3 | var page = document.getElementById("id_page")
4 | page.value = i
5 | document.getElementById("form_page").submit()
6 | }
7 |
8 | function toggle_search_box()
9 | {
10 | $("#search_box").toggle('blind')
11 | }
12 |
13 | function start_search(){
14 | if(!window.jQuery)
15 | {
16 | console.log("Please install jQuery")
17 | return
18 | }
19 | save_form()
20 | // NoWrap()
21 | // window.onresize = NoWrap
22 | }
23 |
24 | var form_page_tmp
25 |
26 | function save_form(){
27 | form_page_tmp = $("#form_page").find("input[name!='page'], select, textarea").serialize()
28 | }
29 |
30 | function check_change(){
31 | form_str = $("#form_page").find("input[name!='page'], select, textarea").serialize()
32 | if(form_page_tmp != form_str)
33 | {
34 | $("input[name='page']").val(1)
35 | }
36 | }
37 |
38 | function NoWrap()
39 | {
40 | $("#paginator li").each(function(){
41 | var node = $(this).find("a")
42 | $(node).text($(node).attr("rel"))
43 | $(this).show()
44 | })
45 | active_page = Math.floor($("#paginator li[class='active'] a").attr("rel"))
46 | last_page = Math.floor($("#paginator ul li").length)
47 | height = Math.floor($("#paginator ul").height())
48 | i_bottom = Math.floor((active_page - 1) /2)
49 | i_top = Math.floor(active_page + (last_page - active_page) /2 )
50 |
51 | width_paginator = Math.floor($("#paginator").width())
52 | width_list = Math.floor($("#paginator ul").width())
53 |
54 | width = width_list / width_paginator
55 |
56 | var seuil = 1
57 |
58 | count_left = $("ul.pagination li:first").nextUntil(".active").length
59 | if(count_left == last_page - 1)
60 | {
61 | count_left = 0
62 | }
63 | count_right = $("ul.pagination li.active").nextAll().length
64 |
65 | if(height > 40 || width > 0.9)
66 | {
67 | if(i_bottom > 4)
68 | {
69 | var replace = $("#paginator li").get(i_bottom)
70 | $(replace).find("a").text("...")
71 | }
72 | if(i_top < last_page - 4)
73 | {
74 | var replace = $("#paginator li").get(i_top)
75 | $(replace).find("a").text("...")
76 | }
77 | j_left = 1
78 | j_right = 1
79 | while(height > 40 || width > 0.9)
80 | {
81 | if(count_left > count_right)
82 | {
83 | if(i_bottom - j_left > seuil)
84 | {
85 | $("#paginator li")[i_bottom - j_left].style.display = "none"
86 | count_left --
87 | }
88 | if(i_bottom + j_left < active_page - seuil)
89 | {
90 | $("#paginator li")[i_bottom + j_left].style.display = "none"
91 | count_left --
92 | }
93 | j_left ++
94 | }
95 | else{
96 | if(i_top - j_right > active_page + seuil)
97 | {
98 | $("#paginator li")[i_top - j_right].style.display = "none"
99 | count_right --
100 | }
101 | if(i_top + j_right < last_page - seuil)
102 | {
103 | $("#paginator li")[i_top + j_right].style.display = "none"
104 | count_right --
105 | }
106 | j_right ++
107 | }
108 |
109 | height = $("#paginator ul").height()
110 | width_paginator = Math.floor($("#paginator").width())
111 | width_list = Math.floor($("#paginator ul").width())
112 | width = width_list / width_paginator
113 |
114 | if(j_left + j_right > last_page)
115 | {
116 | return false
117 | }
118 | }
119 | }
120 | }
--------------------------------------------------------------------------------
/search_listview/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 | {% load staticfiles %}
3 |
4 |
5 |
6 | {% block title %}search_listview{% endblock %}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
15 |
16 | {% block head-javascript %}{% endblock %}
17 |
18 |
19 |
20 |
41 |
42 | {% block content %} Test View search_listview
Need jQuery{% endblock %}
43 |
44 |
45 |
46 | {% block foot-javascript %}{% endblock %}
47 |
48 |
49 |
--------------------------------------------------------------------------------
/search_listview/templates/search_listview/pagination.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 | {% if search_size and not disable_search_button %}
13 |
16 | {% endif %}
17 |
18 | {# hidden input to keep the page number #}
19 | {{ search_page }}
20 |
21 |
22 |
--------------------------------------------------------------------------------
/search_listview/templates/search_listview/search_and_page.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/search_listview/templates/search_listview/search_box.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 |
14 |
--------------------------------------------------------------------------------
/search_listview/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SchroterQuentin/django-search-listview/8b027a6908dc30c6ebc613bb4fde6b1ba40124a3/search_listview/tests/__init__.py
--------------------------------------------------------------------------------
/search_listview/tests/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from .models import Provider, Brand, ModelDevice, Device
4 |
5 | admin.site.register(Provider)
6 | admin.site.register(Brand)
7 | admin.site.register(ModelDevice)
8 | admin.site.register(Device)
--------------------------------------------------------------------------------
/search_listview/tests/fixture.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "model": "tests.provider",
4 | "pk": 1,
5 | "fields": {
6 | "name": "Provider0"
7 | }
8 | },
9 | {
10 | "model": "tests.provider",
11 | "pk": 2,
12 | "fields": {
13 | "name": "Provider1"
14 | }
15 | },
16 | {
17 | "model": "tests.provider",
18 | "pk": 3,
19 | "fields": {
20 | "name": "Provider2"
21 | }
22 | },
23 | {
24 | "model": "tests.provider",
25 | "pk": 4,
26 | "fields": {
27 | "name": "provider3"
28 | }
29 | },
30 | {
31 | "model": "tests.provider",
32 | "pk": 5,
33 | "fields": {
34 | "name": "ProviderApple"
35 | }
36 | },
37 | {
38 | "model": "tests.brand",
39 | "pk": 1,
40 | "fields": {
41 | "provider": [
42 | 1,
43 | 2
44 | ],
45 | "name": "HTC"
46 | }
47 | },
48 | {
49 | "model": "tests.brand",
50 | "pk": 2,
51 | "fields": {
52 | "provider": [
53 | 2,
54 | 3,
55 | 4
56 | ],
57 | "name": "Samsung"
58 | }
59 | },
60 | {
61 | "model": "tests.brand",
62 | "pk": 3,
63 | "fields": {
64 | "provider": [
65 | 5
66 | ],
67 | "name": "Apple"
68 | }
69 | },
70 | {
71 | "model": "tests.modeldevice",
72 | "pk": 1,
73 | "fields": {
74 | "brand": 1,
75 | "name": "M9"
76 | }
77 | },
78 | {
79 | "model": "tests.modeldevice",
80 | "pk": 2,
81 | "fields": {
82 | "brand": 1,
83 | "name": "A9"
84 | }
85 | },
86 | {
87 | "model": "tests.modeldevice",
88 | "pk": 3,
89 | "fields": {
90 | "brand": 3,
91 | "name": "Iphone6s"
92 | }
93 | },
94 | {
95 | "model": "tests.modeldevice",
96 | "pk": 4,
97 | "fields": {
98 | "brand": 3,
99 | "name": "Iphone7"
100 | }
101 | },
102 | {
103 | "model": "tests.modeldevice",
104 | "pk": 5,
105 | "fields": {
106 | "brand": 2,
107 | "name": "Galaxy"
108 | }
109 | },
110 | {
111 | "model": "tests.device",
112 | "pk": 1,
113 | "fields": {
114 | "model_device": 1,
115 | "inventory_number": 1
116 | }
117 | },
118 | {
119 | "model": "tests.device",
120 | "pk": 2,
121 | "fields": {
122 | "model_device": 1,
123 | "inventory_number": 2
124 | }
125 | },
126 | {
127 | "model": "tests.device",
128 | "pk": 3,
129 | "fields": {
130 | "model_device": 1,
131 | "inventory_number": 3
132 | }
133 | },
134 | {
135 | "model": "tests.device",
136 | "pk": 4,
137 | "fields": {
138 | "model_device": 1,
139 | "inventory_number": 4
140 | }
141 | },
142 | {
143 | "model": "tests.device",
144 | "pk": 5,
145 | "fields": {
146 | "model_device": 1,
147 | "inventory_number": 5
148 | }
149 | },
150 | {
151 | "model": "tests.device",
152 | "pk": 6,
153 | "fields": {
154 | "model_device": 2,
155 | "inventory_number": 10
156 | }
157 | },
158 | {
159 | "model": "tests.device",
160 | "pk": 7,
161 | "fields": {
162 | "model_device": 2,
163 | "inventory_number": 11
164 | }
165 | },
166 | {
167 | "model": "tests.device",
168 | "pk": 8,
169 | "fields": {
170 | "model_device": 2,
171 | "inventory_number": 12
172 | }
173 | },
174 | {
175 | "model": "tests.device",
176 | "pk": 9,
177 | "fields": {
178 | "model_device": 2,
179 | "inventory_number": 13
180 | }
181 | },
182 | {
183 | "model": "tests.device",
184 | "pk": 10,
185 | "fields": {
186 | "model_device": 2,
187 | "inventory_number": 14
188 | }
189 | },
190 | {
191 | "model": "tests.device",
192 | "pk": 11,
193 | "fields": {
194 | "model_device": 3,
195 | "inventory_number": 20
196 | }
197 | },
198 | {
199 | "model": "tests.device",
200 | "pk": 12,
201 | "fields": {
202 | "model_device": 3,
203 | "inventory_number": 21
204 | }
205 | },
206 | {
207 | "model": "tests.device",
208 | "pk": 13,
209 | "fields": {
210 | "model_device": 3,
211 | "inventory_number": 22
212 | }
213 | },
214 | {
215 | "model": "tests.device",
216 | "pk": 14,
217 | "fields": {
218 | "model_device": 3,
219 | "inventory_number": 23
220 | }
221 | },
222 | {
223 | "model": "tests.device",
224 | "pk": 15,
225 | "fields": {
226 | "model_device": 3,
227 | "inventory_number": 24
228 | }
229 | },
230 | {
231 | "model": "tests.device",
232 | "pk": 16,
233 | "fields": {
234 | "model_device": 3,
235 | "inventory_number": 25
236 | }
237 | },
238 | {
239 | "model": "tests.device",
240 | "pk": 17,
241 | "fields": {
242 | "model_device": 3,
243 | "inventory_number": 26
244 | }
245 | },
246 | {
247 | "model": "tests.device",
248 | "pk": 18,
249 | "fields": {
250 | "model_device": 4,
251 | "inventory_number": 27
252 | }
253 | },
254 | {
255 | "model": "tests.device",
256 | "pk": 19,
257 | "fields": {
258 | "model_device": 4,
259 | "inventory_number": 28
260 | }
261 | },
262 | {
263 | "model": "tests.device",
264 | "pk": 20,
265 | "fields": {
266 | "model_device": 4,
267 | "inventory_number": 29
268 | }
269 | },
270 | {
271 | "model": "tests.device",
272 | "pk": 21,
273 | "fields": {
274 | "model_device": 4,
275 | "inventory_number": 30
276 | }
277 | },
278 | {
279 | "model": "tests.device",
280 | "pk": 22,
281 | "fields": {
282 | "model_device": 4,
283 | "inventory_number": 31
284 | }
285 | },
286 | {
287 | "model": "tests.device",
288 | "pk": 23,
289 | "fields": {
290 | "model_device": 4,
291 | "inventory_number": 32
292 | }
293 | },
294 | {
295 | "model": "tests.device",
296 | "pk": 24,
297 | "fields": {
298 | "model_device": 5,
299 | "inventory_number": 100
300 | }
301 | },
302 | {
303 | "model": "tests.device",
304 | "pk": 25,
305 | "fields": {
306 | "model_device": 5,
307 | "inventory_number": 101
308 | }
309 | },
310 | {
311 | "model": "tests.device",
312 | "pk": 26,
313 | "fields": {
314 | "model_device": 5,
315 | "inventory_number": 102
316 | }
317 | },
318 | {
319 | "model": "tests.device",
320 | "pk": 27,
321 | "fields": {
322 | "model_device": 5,
323 | "inventory_number": 103
324 | }
325 | },
326 | {
327 | "model": "tests.device",
328 | "pk": 28,
329 | "fields": {
330 | "model_device": 5,
331 | "inventory_number": 104
332 | }
333 | },
334 | {
335 | "model": "tests.device",
336 | "pk": 29,
337 | "fields": {
338 | "model_device": 5,
339 | "inventory_number": 105
340 | }
341 | },
342 | {
343 | "model": "tests.device",
344 | "pk": 30,
345 | "fields": {
346 | "model_device": 5,
347 | "inventory_number": 106
348 | }
349 | },
350 | {
351 | "model": "tests.device",
352 | "pk": 31,
353 | "fields": {
354 | "model_device": 5,
355 | "inventory_number": 107
356 | }
357 | },
358 | {
359 | "model": "tests.device",
360 | "pk": 32,
361 | "fields": {
362 | "model_device": 5,
363 | "inventory_number": 108
364 | }
365 | },
366 | {
367 | "model": "tests.device",
368 | "pk": 33,
369 | "fields": {
370 | "model_device": 5,
371 | "inventory_number": 109
372 | }
373 | },
374 | {
375 | "model": "tests.device",
376 | "pk": 34,
377 | "fields": {
378 | "model_device": 5,
379 | "inventory_number": 110
380 | }
381 | },
382 | {
383 | "model": "tests.device",
384 | "pk": 35,
385 | "fields": {
386 | "model_device": 5,
387 | "inventory_number": 111
388 | }
389 | },
390 | {
391 | "model": "tests.device",
392 | "pk": 36,
393 | "fields": {
394 | "model_device": 5,
395 | "inventory_number": 112
396 | }
397 | },
398 | {
399 | "model": "tests.device",
400 | "pk": 37,
401 | "fields": {
402 | "model_device": 5,
403 | "inventory_number": 113
404 | }
405 | },
406 | {
407 | "model": "tests.device",
408 | "pk": 38,
409 | "fields": {
410 | "model_device": 5,
411 | "inventory_number": 114
412 | }
413 | },
414 | {
415 | "model": "tests.device",
416 | "pk": 39,
417 | "fields": {
418 | "model_device": 5,
419 | "inventory_number": 115
420 | }
421 | },
422 | {
423 | "model": "tests.device",
424 | "pk": 41,
425 | "fields": {
426 | "model_device": 1,
427 | "inventory_number": 211
428 | }
429 | },
430 | {
431 | "model": "tests.device",
432 | "pk": 42,
433 | "fields": {
434 | "model_device": 1,
435 | "inventory_number": 212
436 | }
437 | },
438 | {
439 | "model": "tests.device",
440 | "pk": 43,
441 | "fields": {
442 | "model_device": 1,
443 | "inventory_number": 213
444 | }
445 | },
446 | {
447 | "model": "tests.device",
448 | "pk": 44,
449 | "fields": {
450 | "model_device": 1,
451 | "inventory_number": 214
452 | }
453 | },
454 | {
455 | "model": "tests.device",
456 | "pk": 45,
457 | "fields": {
458 | "model_device": 1,
459 | "inventory_number": 215
460 | }
461 | },
462 | {
463 | "model": "tests.device",
464 | "pk": 46,
465 | "fields": {
466 | "model_device": 2,
467 | "inventory_number": 2110
468 | }
469 | },
470 | {
471 | "model": "tests.device",
472 | "pk": 47,
473 | "fields": {
474 | "model_device": 2,
475 | "inventory_number": 2111
476 | }
477 | },
478 | {
479 | "model": "tests.device",
480 | "pk": 48,
481 | "fields": {
482 | "model_device": 2,
483 | "inventory_number": 2112
484 | }
485 | },
486 | {
487 | "model": "tests.device",
488 | "pk": 49,
489 | "fields": {
490 | "model_device": 2,
491 | "inventory_number": 2113
492 | }
493 | },
494 | {
495 | "model": "tests.device",
496 | "pk": 410,
497 | "fields": {
498 | "model_device": 2,
499 | "inventory_number": 2114
500 | }
501 | },
502 | {
503 | "model": "tests.device",
504 | "pk": 411,
505 | "fields": {
506 | "model_device": 3,
507 | "inventory_number": 2120
508 | }
509 | },
510 | {
511 | "model": "tests.device",
512 | "pk": 412,
513 | "fields": {
514 | "model_device": 3,
515 | "inventory_number": 2121
516 | }
517 | },
518 | {
519 | "model": "tests.device",
520 | "pk": 413,
521 | "fields": {
522 | "model_device": 3,
523 | "inventory_number": 2122
524 | }
525 | },
526 | {
527 | "model": "tests.device",
528 | "pk": 414,
529 | "fields": {
530 | "model_device": 3,
531 | "inventory_number": 2123
532 | }
533 | },
534 | {
535 | "model": "tests.device",
536 | "pk": 415,
537 | "fields": {
538 | "model_device": 3,
539 | "inventory_number": 2124
540 | }
541 | },
542 | {
543 | "model": "tests.device",
544 | "pk": 416,
545 | "fields": {
546 | "model_device": 3,
547 | "inventory_number": 2125
548 | }
549 | },
550 | {
551 | "model": "tests.device",
552 | "pk": 417,
553 | "fields": {
554 | "model_device": 3,
555 | "inventory_number": 2126
556 | }
557 | },
558 | {
559 | "model": "tests.device",
560 | "pk": 418,
561 | "fields": {
562 | "model_device": 4,
563 | "inventory_number": 2127
564 | }
565 | },
566 | {
567 | "model": "tests.device",
568 | "pk": 419,
569 | "fields": {
570 | "model_device": 4,
571 | "inventory_number": 2128
572 | }
573 | },
574 | {
575 | "model": "tests.device",
576 | "pk": 420,
577 | "fields": {
578 | "model_device": 4,
579 | "inventory_number": 2129
580 | }
581 | },
582 | {
583 | "model": "tests.device",
584 | "pk": 421,
585 | "fields": {
586 | "model_device": 4,
587 | "inventory_number": 2130
588 | }
589 | },
590 | {
591 | "model": "tests.device",
592 | "pk": 422,
593 | "fields": {
594 | "model_device": 4,
595 | "inventory_number": 2131
596 | }
597 | },
598 | {
599 | "model": "tests.device",
600 | "pk": 423,
601 | "fields": {
602 | "model_device": 4,
603 | "inventory_number": 2132
604 | }
605 | },
606 | {
607 | "model": "tests.device",
608 | "pk": 424,
609 | "fields": {
610 | "model_device": 5,
611 | "inventory_number": 21100
612 | }
613 | },
614 | {
615 | "model": "tests.device",
616 | "pk": 425,
617 | "fields": {
618 | "model_device": 5,
619 | "inventory_number": 21101
620 | }
621 | },
622 | {
623 | "model": "tests.device",
624 | "pk": 426,
625 | "fields": {
626 | "model_device": 5,
627 | "inventory_number": 21102
628 | }
629 | },
630 | {
631 | "model": "tests.device",
632 | "pk": 427,
633 | "fields": {
634 | "model_device": 5,
635 | "inventory_number": 21103
636 | }
637 | },
638 | {
639 | "model": "tests.device",
640 | "pk": 428,
641 | "fields": {
642 | "model_device": 5,
643 | "inventory_number": 21104
644 | }
645 | },
646 | {
647 | "model": "tests.device",
648 | "pk": 429,
649 | "fields": {
650 | "model_device": 5,
651 | "inventory_number": 21105
652 | }
653 | },
654 | {
655 | "model": "tests.device",
656 | "pk": 430,
657 | "fields": {
658 | "model_device": 5,
659 | "inventory_number": 21106
660 | }
661 | },
662 | {
663 | "model": "tests.device",
664 | "pk": 431,
665 | "fields": {
666 | "model_device": 5,
667 | "inventory_number": 21107
668 | }
669 | },
670 | {
671 | "model": "tests.device",
672 | "pk": 432,
673 | "fields": {
674 | "model_device": 5,
675 | "inventory_number": 21108
676 | }
677 | },
678 | {
679 | "model": "tests.device",
680 | "pk": 433,
681 | "fields": {
682 | "model_device": 5,
683 | "inventory_number": 21109
684 | }
685 | },
686 | {
687 | "model": "tests.device",
688 | "pk": 434,
689 | "fields": {
690 | "model_device": 5,
691 | "inventory_number": 21110
692 | }
693 | },
694 | {
695 | "model": "tests.device",
696 | "pk": 435,
697 | "fields": {
698 | "model_device": 5,
699 | "inventory_number": 21111
700 | }
701 | },
702 | {
703 | "model": "tests.device",
704 | "pk": 436,
705 | "fields": {
706 | "model_device": 5,
707 | "inventory_number": 21112
708 | }
709 | },
710 | {
711 | "model": "tests.device",
712 | "pk": 437,
713 | "fields": {
714 | "model_device": 5,
715 | "inventory_number": 21113
716 | }
717 | },
718 | {
719 | "model": "tests.device",
720 | "pk": 438,
721 | "fields": {
722 | "model_device": 5,
723 | "inventory_number": 21114
724 | }
725 | },
726 | {
727 | "model": "tests.device",
728 | "pk": 439,
729 | "fields": {
730 | "model_device": 5,
731 | "inventory_number": 21115
732 | }
733 | },
734 | {
735 | "model": "tests.device",
736 | "pk": 91,
737 | "fields": {
738 | "model_device": 1,
739 | "inventory_number": 901
740 | }
741 | },
742 | {
743 | "model": "tests.device",
744 | "pk": 92,
745 | "fields": {
746 | "model_device": 1,
747 | "inventory_number": 902
748 | }
749 | },
750 | {
751 | "model": "tests.device",
752 | "pk": 93,
753 | "fields": {
754 | "model_device": 1,
755 | "inventory_number": 903
756 | }
757 | },
758 | {
759 | "model": "tests.device",
760 | "pk": 94,
761 | "fields": {
762 | "model_device": 1,
763 | "inventory_number": 904
764 | }
765 | },
766 | {
767 | "model": "tests.device",
768 | "pk": 95,
769 | "fields": {
770 | "model_device": 1,
771 | "inventory_number": 905
772 | }
773 | },
774 | {
775 | "model": "tests.device",
776 | "pk": 96,
777 | "fields": {
778 | "model_device": 2,
779 | "inventory_number": 9010
780 | }
781 | },
782 | {
783 | "model": "tests.device",
784 | "pk": 97,
785 | "fields": {
786 | "model_device": 2,
787 | "inventory_number": 9011
788 | }
789 | },
790 | {
791 | "model": "tests.device",
792 | "pk": 98,
793 | "fields": {
794 | "model_device": 2,
795 | "inventory_number": 9012
796 | }
797 | },
798 | {
799 | "model": "tests.device",
800 | "pk": 99,
801 | "fields": {
802 | "model_device": 2,
803 | "inventory_number": 9013
804 | }
805 | },
806 | {
807 | "model": "tests.device",
808 | "pk": 910,
809 | "fields": {
810 | "model_device": 2,
811 | "inventory_number": 9014
812 | }
813 | },
814 | {
815 | "model": "tests.device",
816 | "pk": 911,
817 | "fields": {
818 | "model_device": 3,
819 | "inventory_number": 9020
820 | }
821 | },
822 | {
823 | "model": "tests.device",
824 | "pk": 912,
825 | "fields": {
826 | "model_device": 3,
827 | "inventory_number": 9021
828 | }
829 | },
830 | {
831 | "model": "tests.device",
832 | "pk": 913,
833 | "fields": {
834 | "model_device": 3,
835 | "inventory_number": 9022
836 | }
837 | },
838 | {
839 | "model": "tests.device",
840 | "pk": 914,
841 | "fields": {
842 | "model_device": 3,
843 | "inventory_number": 9023
844 | }
845 | },
846 | {
847 | "model": "tests.device",
848 | "pk": 915,
849 | "fields": {
850 | "model_device": 3,
851 | "inventory_number": 9024
852 | }
853 | },
854 | {
855 | "model": "tests.device",
856 | "pk": 916,
857 | "fields": {
858 | "model_device": 3,
859 | "inventory_number": 9025
860 | }
861 | },
862 | {
863 | "model": "tests.device",
864 | "pk": 917,
865 | "fields": {
866 | "model_device": 3,
867 | "inventory_number": 9026
868 | }
869 | },
870 | {
871 | "model": "tests.device",
872 | "pk": 918,
873 | "fields": {
874 | "model_device": 4,
875 | "inventory_number": 9027
876 | }
877 | },
878 | {
879 | "model": "tests.device",
880 | "pk": 919,
881 | "fields": {
882 | "model_device": 4,
883 | "inventory_number": 9028
884 | }
885 | },
886 | {
887 | "model": "tests.device",
888 | "pk": 920,
889 | "fields": {
890 | "model_device": 4,
891 | "inventory_number": 9029
892 | }
893 | },
894 | {
895 | "model": "tests.device",
896 | "pk": 921,
897 | "fields": {
898 | "model_device": 4,
899 | "inventory_number": 9030
900 | }
901 | },
902 | {
903 | "model": "tests.device",
904 | "pk": 922,
905 | "fields": {
906 | "model_device": 4,
907 | "inventory_number": 9031
908 | }
909 | },
910 | {
911 | "model": "tests.device",
912 | "pk": 923,
913 | "fields": {
914 | "model_device": 4,
915 | "inventory_number": 9032
916 | }
917 | },
918 | {
919 | "model": "tests.device",
920 | "pk": 924,
921 | "fields": {
922 | "model_device": 5,
923 | "inventory_number": 90100
924 | }
925 | },
926 | {
927 | "model": "tests.device",
928 | "pk": 925,
929 | "fields": {
930 | "model_device": 5,
931 | "inventory_number": 90101
932 | }
933 | },
934 | {
935 | "model": "tests.device",
936 | "pk": 926,
937 | "fields": {
938 | "model_device": 5,
939 | "inventory_number": 90102
940 | }
941 | },
942 | {
943 | "model": "tests.device",
944 | "pk": 927,
945 | "fields": {
946 | "model_device": 5,
947 | "inventory_number": 90103
948 | }
949 | },
950 | {
951 | "model": "tests.device",
952 | "pk": 928,
953 | "fields": {
954 | "model_device": 5,
955 | "inventory_number": 90104
956 | }
957 | },
958 | {
959 | "model": "tests.device",
960 | "pk": 929,
961 | "fields": {
962 | "model_device": 5,
963 | "inventory_number": 90105
964 | }
965 | },
966 | {
967 | "model": "tests.device",
968 | "pk": 930,
969 | "fields": {
970 | "model_device": 5,
971 | "inventory_number": 90106
972 | }
973 | },
974 | {
975 | "model": "tests.device",
976 | "pk": 931,
977 | "fields": {
978 | "model_device": 5,
979 | "inventory_number": 90107
980 | }
981 | },
982 | {
983 | "model": "tests.device",
984 | "pk": 932,
985 | "fields": {
986 | "model_device": 5,
987 | "inventory_number": 90108
988 | }
989 | },
990 | {
991 | "model": "tests.device",
992 | "pk": 933,
993 | "fields": {
994 | "model_device": 5,
995 | "inventory_number": 90109
996 | }
997 | },
998 | {
999 | "model": "tests.device",
1000 | "pk": 934,
1001 | "fields": {
1002 | "model_device": 5,
1003 | "inventory_number": 90110
1004 | }
1005 | },
1006 | {
1007 | "model": "tests.device",
1008 | "pk": 935,
1009 | "fields": {
1010 | "model_device": 5,
1011 | "inventory_number": 90111
1012 | }
1013 | },
1014 | {
1015 | "model": "tests.device",
1016 | "pk": 936,
1017 | "fields": {
1018 | "model_device": 5,
1019 | "inventory_number": 90112
1020 | }
1021 | },
1022 | {
1023 | "model": "tests.device",
1024 | "pk": 937,
1025 | "fields": {
1026 | "model_device": 5,
1027 | "inventory_number": 90113
1028 | }
1029 | },
1030 | {
1031 | "model": "tests.device",
1032 | "pk": 938,
1033 | "fields": {
1034 | "model_device": 5,
1035 | "inventory_number": 90114
1036 | }
1037 | },
1038 | {
1039 | "model": "tests.device",
1040 | "pk": 939,
1041 | "fields": {
1042 | "model_device": 5,
1043 | "inventory_number": 90115
1044 | }
1045 | },
1046 | {
1047 | "model": "tests.device",
1048 | "pk": 941,
1049 | "fields": {
1050 | "model_device": 1,
1051 | "inventory_number": 90211
1052 | }
1053 | },
1054 | {
1055 | "model": "tests.device",
1056 | "pk": 942,
1057 | "fields": {
1058 | "model_device": 1,
1059 | "inventory_number": 90212
1060 | }
1061 | },
1062 | {
1063 | "model": "tests.device",
1064 | "pk": 943,
1065 | "fields": {
1066 | "model_device": 1,
1067 | "inventory_number": 90213
1068 | }
1069 | },
1070 | {
1071 | "model": "tests.device",
1072 | "pk": 944,
1073 | "fields": {
1074 | "model_device": 1,
1075 | "inventory_number": 90214
1076 | }
1077 | },
1078 | {
1079 | "model": "tests.device",
1080 | "pk": 945,
1081 | "fields": {
1082 | "model_device": 1,
1083 | "inventory_number": 90215
1084 | }
1085 | },
1086 | {
1087 | "model": "tests.device",
1088 | "pk": 946,
1089 | "fields": {
1090 | "model_device": 2,
1091 | "inventory_number": 902110
1092 | }
1093 | },
1094 | {
1095 | "model": "tests.device",
1096 | "pk": 947,
1097 | "fields": {
1098 | "model_device": 2,
1099 | "inventory_number": 902111
1100 | }
1101 | },
1102 | {
1103 | "model": "tests.device",
1104 | "pk": 948,
1105 | "fields": {
1106 | "model_device": 2,
1107 | "inventory_number": 902112
1108 | }
1109 | },
1110 | {
1111 | "model": "tests.device",
1112 | "pk": 949,
1113 | "fields": {
1114 | "model_device": 2,
1115 | "inventory_number": 902113
1116 | }
1117 | },
1118 | {
1119 | "model": "tests.device",
1120 | "pk": 9410,
1121 | "fields": {
1122 | "model_device": 2,
1123 | "inventory_number": 902114
1124 | }
1125 | },
1126 | {
1127 | "model": "tests.device",
1128 | "pk": 9411,
1129 | "fields": {
1130 | "model_device": 3,
1131 | "inventory_number": 902120
1132 | }
1133 | },
1134 | {
1135 | "model": "tests.device",
1136 | "pk": 9412,
1137 | "fields": {
1138 | "model_device": 3,
1139 | "inventory_number": 902121
1140 | }
1141 | },
1142 | {
1143 | "model": "tests.device",
1144 | "pk": 9413,
1145 | "fields": {
1146 | "model_device": 3,
1147 | "inventory_number": 902122
1148 | }
1149 | },
1150 | {
1151 | "model": "tests.device",
1152 | "pk": 9414,
1153 | "fields": {
1154 | "model_device": 3,
1155 | "inventory_number": 902123
1156 | }
1157 | },
1158 | {
1159 | "model": "tests.device",
1160 | "pk": 9415,
1161 | "fields": {
1162 | "model_device": 3,
1163 | "inventory_number": 902124
1164 | }
1165 | },
1166 | {
1167 | "model": "tests.device",
1168 | "pk": 9416,
1169 | "fields": {
1170 | "model_device": 3,
1171 | "inventory_number": 902125
1172 | }
1173 | },
1174 | {
1175 | "model": "tests.device",
1176 | "pk": 9417,
1177 | "fields": {
1178 | "model_device": 3,
1179 | "inventory_number": 902126
1180 | }
1181 | },
1182 | {
1183 | "model": "tests.device",
1184 | "pk": 9418,
1185 | "fields": {
1186 | "model_device": 4,
1187 | "inventory_number": 902127
1188 | }
1189 | },
1190 | {
1191 | "model": "tests.device",
1192 | "pk": 9419,
1193 | "fields": {
1194 | "model_device": 4,
1195 | "inventory_number": 902128
1196 | }
1197 | },
1198 | {
1199 | "model": "tests.device",
1200 | "pk": 9420,
1201 | "fields": {
1202 | "model_device": 4,
1203 | "inventory_number": 902129
1204 | }
1205 | },
1206 | {
1207 | "model": "tests.device",
1208 | "pk": 9421,
1209 | "fields": {
1210 | "model_device": 4,
1211 | "inventory_number": 902130
1212 | }
1213 | },
1214 | {
1215 | "model": "tests.device",
1216 | "pk": 9422,
1217 | "fields": {
1218 | "model_device": 4,
1219 | "inventory_number": 902131
1220 | }
1221 | },
1222 | {
1223 | "model": "tests.device",
1224 | "pk": 9423,
1225 | "fields": {
1226 | "model_device": 4,
1227 | "inventory_number": 902132
1228 | }
1229 | },
1230 | {
1231 | "model": "tests.device",
1232 | "pk": 9424,
1233 | "fields": {
1234 | "model_device": 5,
1235 | "inventory_number": 9021100
1236 | }
1237 | },
1238 | {
1239 | "model": "tests.device",
1240 | "pk": 9425,
1241 | "fields": {
1242 | "model_device": 5,
1243 | "inventory_number": 9021101
1244 | }
1245 | },
1246 | {
1247 | "model": "tests.device",
1248 | "pk": 9426,
1249 | "fields": {
1250 | "model_device": 5,
1251 | "inventory_number": 9021102
1252 | }
1253 | },
1254 | {
1255 | "model": "tests.device",
1256 | "pk": 9427,
1257 | "fields": {
1258 | "model_device": 5,
1259 | "inventory_number": 9021103
1260 | }
1261 | },
1262 | {
1263 | "model": "tests.device",
1264 | "pk": 9428,
1265 | "fields": {
1266 | "model_device": 5,
1267 | "inventory_number": 9021104
1268 | }
1269 | },
1270 | {
1271 | "model": "tests.device",
1272 | "pk": 9429,
1273 | "fields": {
1274 | "model_device": 5,
1275 | "inventory_number": 9021105
1276 | }
1277 | },
1278 | {
1279 | "model": "tests.device",
1280 | "pk": 9430,
1281 | "fields": {
1282 | "model_device": 5,
1283 | "inventory_number": 9021106
1284 | }
1285 | },
1286 | {
1287 | "model": "tests.device",
1288 | "pk": 9431,
1289 | "fields": {
1290 | "model_device": 5,
1291 | "inventory_number": 9021107
1292 | }
1293 | },
1294 | {
1295 | "model": "tests.device",
1296 | "pk": 9432,
1297 | "fields": {
1298 | "model_device": 5,
1299 | "inventory_number": 9021108
1300 | }
1301 | },
1302 | {
1303 | "model": "tests.device",
1304 | "pk": 9433,
1305 | "fields": {
1306 | "model_device": 5,
1307 | "inventory_number": 9021109
1308 | }
1309 | },
1310 | {
1311 | "model": "tests.device",
1312 | "pk": 9434,
1313 | "fields": {
1314 | "model_device": 5,
1315 | "inventory_number": 9021110
1316 | }
1317 | },
1318 | {
1319 | "model": "tests.device",
1320 | "pk": 9435,
1321 | "fields": {
1322 | "model_device": 5,
1323 | "inventory_number": 9021111
1324 | }
1325 | },
1326 | {
1327 | "model": "tests.device",
1328 | "pk": 9436,
1329 | "fields": {
1330 | "model_device": 5,
1331 | "inventory_number": 9021112
1332 | }
1333 | },
1334 | {
1335 | "model": "tests.device",
1336 | "pk": 9437,
1337 | "fields": {
1338 | "model_device": 5,
1339 | "inventory_number": 9021113
1340 | }
1341 | },
1342 | {
1343 | "model": "tests.device",
1344 | "pk": 9438,
1345 | "fields": {
1346 | "model_device": 5,
1347 | "inventory_number": 9021114
1348 | }
1349 | },
1350 | {
1351 | "model": "tests.device",
1352 | "pk": 9439,
1353 | "fields": {
1354 | "model_device": 5,
1355 | "inventory_number": 9021115
1356 | }
1357 | }
1358 | ]
--------------------------------------------------------------------------------
/search_listview/tests/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ]
11 |
12 | operations = [
13 | migrations.CreateModel(
14 | name='Brand',
15 | fields=[
16 | ('id', models.AutoField(primary_key=True, auto_created=True, verbose_name='ID', serialize=False)),
17 | ('name', models.CharField(max_length=100)),
18 | ],
19 | ),
20 | migrations.CreateModel(
21 | name='Device',
22 | fields=[
23 | ('id', models.AutoField(primary_key=True, auto_created=True, verbose_name='ID', serialize=False)),
24 | ('inventory_number', models.PositiveIntegerField()),
25 | ],
26 | ),
27 | migrations.CreateModel(
28 | name='ModelDevice',
29 | fields=[
30 | ('id', models.AutoField(primary_key=True, auto_created=True, verbose_name='ID', serialize=False)),
31 | ('name', models.CharField(max_length=100)),
32 | ('brand', models.ForeignKey(to='tests.Brand')),
33 | ],
34 | ),
35 | migrations.CreateModel(
36 | name='Provider',
37 | fields=[
38 | ('id', models.AutoField(primary_key=True, auto_created=True, verbose_name='ID', serialize=False)),
39 | ('name', models.CharField(max_length=100)),
40 | ],
41 | ),
42 | migrations.AddField(
43 | model_name='device',
44 | name='model_device',
45 | field=models.ForeignKey(to='tests.ModelDevice'),
46 | ),
47 | migrations.AddField(
48 | model_name='brand',
49 | name='provider',
50 | field=models.ManyToManyField(to='tests.Provider'),
51 | ),
52 | ]
53 |
--------------------------------------------------------------------------------
/search_listview/tests/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SchroterQuentin/django-search-listview/8b027a6908dc30c6ebc613bb4fde6b1ba40124a3/search_listview/tests/migrations/__init__.py
--------------------------------------------------------------------------------
/search_listview/tests/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | class Provider(models.Model):
4 | name = models.CharField(max_length=100, verbose_name="Provider's name")
5 |
6 | def __str__(self):
7 | return self.name
8 |
9 | class Brand(models.Model):
10 | name = models.CharField(max_length=100, verbose_name="Brand's name")
11 |
12 | provider = models.ManyToManyField(Provider, verbose_name="Brand's provider")
13 |
14 | def __str__(self):
15 | return self.name
16 |
17 | class ModelDevice(models.Model):
18 | name = models.CharField(max_length=100, verbose_name="Model's name")
19 |
20 | brand = models.ForeignKey(Brand, verbose_name="Model's brand")
21 |
22 | def __str__(self):
23 | return self.name
24 |
25 | class Device(models.Model):
26 | inventory_number = models.PositiveIntegerField()
27 |
28 | model_device = models.ForeignKey(ModelDevice, verbose_name="Device's model'")
29 |
30 | def __str__(self):
31 | return str(self.inventory_number)
32 |
33 |
34 |
--------------------------------------------------------------------------------
/search_listview/tests/templates/tests/list.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 |
4 |
5 |
6 | {% block content %}
7 |
8 |
9 | {% include "search_listview/search_and_page.html" %}
10 |
11 |
12 |
13 |
14 |
15 | Inventory Number |
16 | Model |
17 | Brand |
18 | Provider |
19 |
20 |
21 | {% for object in object_list %}
22 |
23 |
24 | {{ object.inventory_number }}
25 | |
26 |
27 | {{ object.model_device.name }}
28 | |
29 |
30 | {{ object.model_device.brand }}
31 | |
32 |
33 | {% for provider in object.model_device.brand.provider.all %}
34 | {{ provider }},
35 | {% endfor %}
36 | |
37 |
38 | {% endfor %}
39 |
40 |
41 |
42 | {% endblock %}
43 |
44 | {% block foot-javascript %}
45 |
46 |
49 |
50 | {% endblock %}
51 |
52 |
53 |
--------------------------------------------------------------------------------
/search_listview/tests/templates/tests/list_reverse.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 |
4 |
5 |
6 | {% block content %}
7 |
8 |
9 | {% include "search_listview/search_and_page.html" %}
10 |
11 |
12 |
13 |
14 |
15 | Provider |
16 | Brand |
17 | Model |
18 | Inventory Number |
19 |
20 |
21 | {% for object in object_list %}
22 |
23 |
24 | {{ object.name }}
25 | |
26 |
27 | {% for brand in object.brand_set.all %}
28 | {{ brand }},
29 | {% endfor %}
30 | |
31 |
32 | {% for brand in object.brand_set.all %}
33 | {% for model in brand.modeldevice_set.all %}
34 | {{ model }},
35 | {% endfor %}
36 | {% endfor %}
37 | |
38 |
39 | {% for brand in object.brand_set.all %}
40 | {% for model in brand.modeldevice_set.all %}
41 | {% for device in model.device_set.all %}
42 | {{ device }},
43 | {% endfor %}
44 | {% endfor %}
45 | {% endfor %}
46 | |
47 |
48 | {% endfor %}
49 |
50 |
51 |
52 | {% endblock %}
53 |
54 | {% block foot-javascript %}
55 |
56 |
59 |
60 | {% endblock %}
61 |
62 |
63 |
--------------------------------------------------------------------------------
/search_listview/tests/templates/tests/list_reverse_brand.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 |
4 |
5 |
6 | {% block content %}
7 |
8 |
9 | {% include "search_listview/search_and_page.html" %}
10 |
11 |
12 |
13 |
14 |
15 | Brand |
16 | Model |
17 | Inventory Number |
18 | Provider |
19 |
20 |
21 | {% for object in object_list %}
22 |
23 |
24 | {{ object.name }}
25 | |
26 |
27 | {% for model in object.modeldevice_set.all %}
28 | {{ model }},
29 | {% endfor %}
30 | |
31 |
32 | {% for model in object.modeldevice_set.all %}
33 | {% for device in model.device_set.all %}
34 | {{ device }},
35 | {% endfor %}
36 | {% endfor %}
37 | |
38 |
39 | {% for provider in object.provider.all %}
40 | {{ provider.name }},
41 | {% endfor %}
42 | |
43 |
44 | {% endfor %}
45 |
46 |
47 |
48 | {% endblock %}
49 |
50 | {% block foot-javascript %}
51 |
52 |
55 |
56 | {% endblock %}
57 |
58 |
59 |
--------------------------------------------------------------------------------
/search_listview/tests/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 | from django.test import Client
3 |
4 | class SearchTest(TestCase):
5 |
6 | fixtures = ['base.json']
7 |
8 | def setUp(self):
9 | self.client = Client()
10 |
11 | def test_home_page(self):
12 | """
13 | Only pagination
14 | """
15 | response = self.client.get('/list/devices')
16 | self.assertEqual(response.status_code, 200)
17 | self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
18 | self.assertContains(response, """
1""")
19 |
20 | response = self.client.get('/list/devices?page=2')
21 | self.assertEqual(response.status_code, 200)
22 | self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
23 | self.assertContains(response, """
2""")
24 |
25 | response = self.client.get('/list/devices?page=16')
26 | self.assertEqual(response.status_code, 200)
27 | self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
28 | self.assertContains(response, """
16""")
29 |
30 | def test_search_page(self):
31 | response = self.client.get('/list/devices/search')
32 | self.assertEqual(response.status_code, 200)
33 | self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
34 | self.assertContains(response, """
1""")
35 | self.assertContains(response,"""
""")
36 |
37 | response = self.client.get('/list/devices/search', data={
38 | "page": 2,
39 | "Brand-provider": 2,
40 | "Brand-name" : "HTC"
41 | })
42 | self.assertEqual(response.status_code, 200)
43 | self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
44 | self.assertContains(response, "211")
45 | self.assertContains(response, """""")
46 | self.assertContains(response,"""""")
47 |
48 | def test_out_of_range(self):
49 | response = self.client.get('/list/devices/search', data={
50 | "page": 5,
51 | "Brand-provider": 2,
52 | "Brand-name" : "HTC"
53 | })
54 | self.assertEqual(response.status_code, 404)
55 |
56 | def test_result(self):
57 | response = self.client.get('/list/devices/search', data={
58 | "page": 2,
59 | "Brand-provider": 2,
60 | "Brand-name" : "HTC",
61 | "Device-model_device": 2
62 | })
63 | self.assertEqual(response.status_code, 200)
64 | self.assertContains(response, "902114")
65 |
66 | response = self.client.get('/list/devices/search', data={
67 | "page": 2,
68 | "Brand-provider": 2,
69 | "Brand-name" : "H",
70 | "Device-model_device": 2
71 | })
72 | self.assertEqual(response.status_code, 200)
73 | self.assertContains(response, "902114")
74 |
75 | response = self.client.get('/list/devices/search', data={
76 | "page": 3,
77 | "Brand-provider": 2,
78 | "Brand-name" : "H",
79 | "Device-model_device": 2
80 | })
81 | self.assertEqual(response.status_code, 404)
82 |
83 | def test_number_input(self):
84 | response = self.client.get('/list/devices/search', data={
85 | "page": 2,
86 | "Brand-provider": 2,
87 | "Brand-name" : "HTC",
88 | "Device-model_device": 2
89 | })
90 | self.assertContains(response, "