├── .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 | [![Build Status](https://travis-ci.org/SchroterQuentin/django-search-listview.svg?branch=master)](https://travis-ci.org/SchroterQuentin/django-search-listview) 5 | [![Coverage Status](https://coveralls.io/repos/github/SchroterQuentin/Django-SearchableListView/badge.svg)](https://coveralls.io/github/SchroterQuentin/Django-SearchableListView) 6 | [![Code Health](https://landscape.io/github/SchroterQuentin/django-search-listview/master/landscape.svg?style=flat)](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 | ![Alt tag](/docs/search_box.png?raw=true "Search box") 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 |
    4 | {% for i in paginator.page_range %} 5 | {% if i == page_obj.number %} 6 |
  • {{ i }}
  • 7 | {% else %} 8 |
  • {{ i }}
  • 9 | {% endif %} 10 | {% endfor %} 11 |
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 |
2 | {%if paginator %} 3 | {% include "search_listview/pagination.html" %} 4 | {% endif %} 5 | {% include "search_listview/search_box.html" %} 6 |
-------------------------------------------------------------------------------- /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 | 16 | 17 | 18 | 19 | 20 | 21 | {% for object in object_list %} 22 | 23 | 26 | 29 | 32 | 37 | 38 | {% endfor %} 39 | 40 |
Inventory NumberModelBrandProvider
24 | {{ object.inventory_number }} 25 | 27 | {{ object.model_device.name }} 28 | 30 | {{ object.model_device.brand }} 31 | 33 | {% for provider in object.model_device.brand.provider.all %} 34 | {{ provider }}, 35 | {% endfor %} 36 |
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 | 16 | 17 | 18 | 19 | 20 | 21 | {% for object in object_list %} 22 | 23 | 26 | 31 | 38 | 47 | 48 | {% endfor %} 49 | 50 |
ProviderBrandModelInventory Number
24 | {{ object.name }} 25 | 27 | {% for brand in object.brand_set.all %} 28 | {{ brand }}, 29 | {% endfor %} 30 | 32 | {% for brand in object.brand_set.all %} 33 | {% for model in brand.modeldevice_set.all %} 34 | {{ model }}, 35 | {% endfor %} 36 | {% endfor %} 37 | 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 |
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 | 16 | 17 | 18 | 19 | 20 | 21 | {% for object in object_list %} 22 | 23 | 26 | 31 | 38 | 43 | 44 | {% endfor %} 45 | 46 |
BrandModelInventory NumberProvider
24 | {{ object.name }} 25 | 27 | {% for model in object.modeldevice_set.all %} 28 | {{ model }}, 29 | {% endfor %} 30 | 32 | {% for model in object.modeldevice_set.all %} 33 | {% for device in model.device_set.all %} 34 | {{ device }}, 35 | {% endfor %} 36 | {% endfor %} 37 | 39 | {% for provider in object.provider.all %} 40 | {{ provider.name }}, 41 | {% endfor %} 42 |
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,"""