{ "info": { "author": "Pivotal Energy Solutions", "author_email": "tvalenta@pivotalenergysolutions.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "# django-appsearch\n\nFramework and generic app for cross-model searches on a single page\n\nMajor sections:\n\n* [Usage](#usage)\n* [API](#api)\n\n## Authors\n\n* Tim Valenta\n* Gaurav Kapoor\n* Steven Klass\n\n## Usage\n\nAppsearch integration is composed of a few separate parts. In the simplest default setup, you must at least do the following:\n\n* Register models with appsearch\n* Call `appsearch.autodiscover()` (probably somewhere in your project's urls, like the similar admin function)\n* Create your main view where the search page should appear\n* Create a simple template where the search form can be rendered\n\nThere are ways to customize the templates, modify the search queryset, etc, which is covered after the basic introduction.\n\n### Model registration\n\n\nPatterned after `django.contrib.admin` interface, appsearch includes a `registry` submodule, which contains a `ModelSearch` class (along the lines of the admin's `ModelAdmin`), and a default registry object called `search`.\n\n`ModelSearch` has a few basic options, the most important of which are `search_fields` and `display_fields`.\n\nWe'll use this example base model for registration, which reaches out to a couple of other fake models for the sake of demonstration:\n\n```python\n# car/models.py\n\nclass Car(models.Model):\n year = models.PositiveIntegerField()\n make = models.ForeignKey(CarMake)\n model = models.ForeignKey(CarModel)\n\n owners = models.ManyToManyField(User)\n\n nickname = models.CharField(max_length=50)\n adoption_story = models.TextField()\n```\n\n##### `search_fields`\n\nTo register this model, place a `search.py` submodule in your app's directory and include at least this basic registration code. We'll leave out the majority of `Car`'s fields for clarity:\n\n```python\n# car/search.py\n\nfrom appsearch.registry import ModelSearch, search\nfrom project.car.models import Car\n\nclass CarSearch(ModelSearch):\n search_fields = (\n 'year',\n 'nickname',\n 'adoption_story',\n )\n\nsearch.register(Car, CarSearch)\n```\n\n`search_fields` is an iterable whose items describe searchable fields. The order that the fields are listed here will be respected in the appsearch UI. An item in the list can be a string if it directly describes a model field name. The field will be looked up and its `verbose_name` stored for use in the UI. To explicitly declare a \"verbose name\" for use within the appsearch UI, you can make the string a 2-tuple of the verbose name and the field name:\n\n```python\nsearch_fields = (\n 'year',\n (\"Name\", 'nickname'),\n 'adoption_story',\n)\n```\n\nTo pull related fields into the mix, an item can instead be a single-entry dictionary, mapping the attribute to a nested structure following the same format:\n\n```python\nsearch_fields = (\n 'year',\n (\"Name\", 'nickname'),\n 'adoption_story',\n {'make': (\n 'name',\n )},\n {'model': (\n 'name',\n )},\n {'owners': (\n 'username',\n 'first_name',\n 'last_name',\n )},\n)\n```\n\nThis syntax reduces potentially repetitive query language such as `\"owners__username\"`, `\"owners__first_name\"`, and `\"owners__last_name\"`.\n\nAny related field that doesn't supply its own verbose name here in the search configuration will be displayed with the related model's `verbose_name` in front of it. In other words, to prevent the search UI from presenting an owner's `\"first_name\"` field as if it were the car's first name, the UI will prefix the field's name with the `User` model's verbose_name. In this example, `first_name` would be shown as \"User first name\".\n\nTo prevent the automatic prefix, you can supply your own verbose name as previously shown:\n\n```python\nsearch_fields = (\n # ...\n {'owners': (\n (\"Username\", 'username'), # would have been \"User username\"\n (\"User's First name\", \"first_name\"), # would have been \"User first name\"\n (\"User's Last name\", \"last_name\"), # would have been \"User last name\"\n )},\n)\n```\n\nRelated fields can be nested:\n\n```python\nsearch_fields = (\n # ...\n {'owners': (\n 'username', # displayed as \"User username\"\n {'groups': (\n 'name', # displayed as \"Group name\"\n )},\n )},\n)\n```\n\nAnother way to specify a related field is to use the related model class itself as the dictionary key. Using this method, the field name will automatically be retrieved by inspecting the relationships between the two models:\n\n```python\n search_fields = (\n # ...\n {User: ( # validated to the string \"owner\", as in the previous example\n 'username', # displayed as \"User username\"\n {'groups': (\n 'name', # displayed as \"Group name\"\n )},\n )}\n )\n```\n\nEventually this syntax will be the supported method for accessing generic foreign keys, although such relationships are not yet implemented.\n\n**NOTE**: Generic models that are referenced by a [GenericRelation](https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#reverse-generic-relations) field (e.g., a Car object with a GenericRelation field called \"comments\" to a generic Comment model) are considered valid and are digested by the appsearch framework:\n\n```python\nsearch_fields = (\n # ...\n {'comments': ( # Car.comments as a GenericRelation field to Comment model\n 'title',\n 'content',\n )},\n)\n```\n\n##### `display_fields`\n\nBy default, the results table shown by appsearch will include all local fields on the model. To explicitly declare the field list, your configuration can include another attribute `display_fields`, which follows a similar format to `search_fields`:\n\n```python\nclass CarSearch(ModelSearch):\n display_fields = (\n 'nickname',\n 'year',\n (\"Make\", 'make__name'),\n (\"Model\", 'model__name'),\n (\"Owners\", 'get_owners_list'), # attribute on the Car model\n )\n\n search_fields = (\n # ...\n )\n```\n\n`display_fields` is an iterable of items, either strings or 2-tuples of (verbosename, fieldname). As with `search_fields`, fields will have their `verbose_name` automatically retrieved, unless it is supplied explicitly in the configuration.\n\nA field isn't necessarily required to be a database field; in the example above, we've placed an \"Owners\" column in the table headers, and the field is actually a method name. This is convenient, but be careful not generate too many queries outside of appsearch's control!\n\nThe first item in this list will be converted into a link, wrapping the value with a simple snippet of HTML: `{{ value }}`\n\nappsearch will examine `display_fields` to discover how to best issue a `select_related()` call to the search results queryset, which helps keep the automatic query count low.\n\n### `appsearch.autodiscover()`\n\nAs with the built-in admin, appsearch can crawl your apps to discover a `search.py` module in each one. `autodiscover()` doesn't do anything but import those configurations and cause them to execute, so if you're using custom or multiple registries, this function will let those registries set themselves up.\n\nAs with the admin, a nice place to call `autodiscover()` is in your urls module, either at the root of your project or in a local \"search\" app where you are going to set up the view anyway. See the example in the next section.\n\n### The main view\n\nYou need to declare your own starting point for the client to initially visit and configure a search.\n\n`BaseSearchView` is a simple `TemplateView` subclass that also inherits from `appsearch.views.SearchMixin`. For a completely vanilla behavior, you could include the `BaseSearchView` directly:\n\n```python\n# project/mysearchapp/urls.py\n\nfrom django.conf.urls.defaults import patterns, url\nfrom appsearch.views import BaseSearchView\nimport appsearch.autodiscover\n\nappsearch.autodiscover()\n\nurlpatterns = patterns('',\n url(r'^search/$', BaseSearchView.as_view(template_name=\"search.html\")),\n)\n```\n\nRemember, because `BaseSearchView` is pretty much just a `TemplateView`, you need to give it a `template_name` value. Don't worry though, since the view inherits machinery for making the search form trivial to render into your custom template.\n\nAlternately, you can of course go and actually subclass `BaseSearchView` and gain access to extra flexibility:\n\n```python\n# project/mysearchapp/views.py\n\nfrom appsearch.views import BaseSearchView\n\nclass SearchView(BaseSearchView):\n template_name = \"search.html\"\n```\n\n#### search.html\n\nYou're free to make whatever template you want for the search to exist on. By default, all you need to do is render the ``search`` context variable into your template. Just make sure that jQuery and the appsearch plugin are loaded:\n\n```html\n{# search.html #}\n\n{% block javascript %}\n \n \n{% endblock %}\n\n{% block content %}\n {{ search }}\n{% endblock %}\n```\n\nThere are plenty of ways to customize how the form is rendered and how the Javascript behaves, but this is enough to get a fully functioning search implementation.\n\n### That's it!\n\nWith the ajax urls mounted, your instance of `BaseSearchView` in play, and your model configurations registered, and your template dumping out the generated form, you're finished.\n\n## API\n\n* [ModelSearch](#modelsearch)\n* [SearchRegistry](#searchregistry)\n\n### `ModelSearch`\n**`appsearch.registry.ModelSearch`**\n\nThe base configuration class used to register a model for search discovery.\n\n#### `verbose_name`\nIf provided, the model that is registered with this ModelSearch instance will take on this verbose name, hiding the model's own `verbose_name` option.\n\n**Default**: The registered model's `verbose_name`\n\n#### `verbose_name_plural`\nIf provided, the model that is registered with this ModelSearch instance will take on this plural verbose name, hiding the model's own `verbose_name` option.\n\n**Default**: The plural of the configuration's `verbose_name`, if available, or else the model class's `verbose_name_plural`.\n\n#### `display_fields`\nAn iterable of column description items.\n\nEach \"item\" can be a string:\n\n```python\n'field_name'\n```\n\nor a 2-tuple where the verbose name is explicitly supplied:\n\n```python\n(\"My field name\", 'field_name')\n```\n\nIn either case, the field name can refer to a local field (including a method name), or a queryset-style lookup path. In the latter case, an explicit verbose name should be supplied:\n\n```python\n(\"Related field name\", 'relationship__field_name')\n```\n\nAny cross-model lookups will be automatically detected and the appropriate `.select_related()` statement will be issued.\n\n**Default**: All local fields\n\n#### `search_fields`\n\nAn iterable of field description items.\n\nEach \"item\" can be a string describing a local database field:\n\n```python\n'field_name'\n```\n\nor a 2-tuple where the verbose name is explicitly supplied:\n\n```python\n(\"My field name\", 'field_name')\n```\n\nor a single-item dictionary mapping a related accessor to a new iterable of related field description items following the same format rules:\n\n```python\n{'users': (\n # strings, 2-tuples, or more nested single-item dictionaries\n)}\n```\n\nThe order in which `search_fields` are declared will be respected by the search form UI.\n\nFor related fields inside of a dictionary item, verbose names will be prefixed with the field's model's `verbose_name`:\n\n```python\n{'users': (\n 'username', # displays User's verbose name + User.username's verbose name: \"User username\"\n)}\n```\n\nThe prefix will not be added if the field already explicitly declares a verbose name:\n\n```python\n{'users': (\n (\"Username\", 'username'), # displays \"Username\" only\n)}\n```\n\n#### `get_queryset(user)`\n\nReturns the base queryset that searches on this model will use to apply the generated query. By default the model's default manager is used to return an unfiltered queryset. An appropriate use of this hook would be to use a different manager, or to limit the queryset based on a permission mechanism.\n\n`user` is the user issuing the request.\n\n#### `get_object_data(obj)`\nGiven a search result object `obj`, return a list of data fields for the frontend table. The length of the list should match the number of display columns.\n\nThe default implementation will automatically read the attributes specified in the configuration's `display_fields` and build this list. If a value is callable, it will be called with no arguments and the return value used in its place, allowing `display_fields` to specify instance attributes and methods, along with concrete database-backed fields.\n\nThe work done by the default search mechanism will attempt to call `select_related()` on the source queryset before this method is called on each result object, but be careful not to generate excessive queries per object. If additional related fields need to be selected to avoid high query counts, you can supply your own subclass of [`Searcher`](#searcher) and either:\n\n1. Override `Searcher.build_queryset()` method, calling super() and performing extra `select_related()` calls on the return value.\n2. Override `get_select_related_fields()` directly and adding to the list.\n\n### `SearchRegistry`\n**`appsearch.registry.SearchRegistry`**\n\nThe registry container where configurations are stored for use in the search form.\n\nThe default registry is made available in the module variable called `search`.\n\n#### `__iter__()`\nYields the registration keys, which are strings in the form `\"applabel.modelname\"`.\n\n#### `__getitem__(k)`\nIf `k` is a model class, the registration key is generated (`\"applabel.modelname\"`) in its place. Otherwise, `k` is directly used to look up a model configuration in the registry.\n\n#### `__contains__(k)`\nIf `k` is a model class, the registration key is generated (`\"applabel.modelname\"`) in its place. Otherwise, `k` is directly used to test membership in the registry.\n\n#### `register(model, configuration)`\nRegisters a model class `model` with the given `configuration` class.\n\n#### `get_configuration(model)`\nReturns the configuration instance associated with `model`.\n\n#### `get_configurations([user[, permission]])`\nReturns the configurations in sorted order.\n\nIf `user` is specified, configurations will be included only if the user has the built-in `\"applabel.change_modelname\"` permission on the associated model class.\n\nIf `permission` is also supplied, it should be a string with two string-formatting positions for the applabel and the modelname, such as `\"{}.add_{}\"` or `{}.manage_{}`.\n\n#### `set_sort_function(f)`\n`f` should be a function that accepts a parameter `configurations` and returns the configurations in the desired order. The default sort function arranges the configurations based on their `verbose_name` attributes.\n\n### `Searcher`\n**`appsearch.utils.Searcher`**\n\nThe object wrapping all data necessary to render the search UI and execute the search itself. The current instance is sent to the form template context, by default with the name `\"search\"`.\n\nThe `Searcher` class can be specified by the instance of the `BaseSearchView` producing the main search page.\n\n#### `form_template_name`\n**Default**: `\"appsearch/default_form.html\"`\n\nNormally the view that builds the `Searcher` instance will supply its own template name, but in the event that the view's value is explicitly set to `None`, or the `Searcher` is being custom constructed, this value will be used.\n\n#### `search_form_template_name`\n**Default**: `\"appsearch/search_form.html\"`\n\nSame as `form_template_name`.\n\n#### `results_list_template_name`\n**Default**: `\"appsearch/results_list.html\"`\n\nSame as `form_template_name`.\n\n#### `__unicode__()`\n\nRenders the template name at `self.form_template_name`.\n\nThis default template automatically calls `render_search_form()` and `render_results_list()`, making it the simplest way to generate the appsearch UI.\n\n#### `render_search_form()`\n\nRenders the template name at `self.search_form_template_name`.\n\nThis generates the HTML for the forms, not including the results list.\n\n#### `render_results_list()`\n\nRenders the template name at `self.results_list_template_name`.\n\nThis generates the HTML for the results list, not including the forms. This result is empty if the search was not executed during the current request.\n\n#### `model_selection_form`\nAn instance of `appsearch.forms.ModelSelectionForm`.\n\n#### `constraint_formset`\nAn instance of `appsearch.forms.ConstraintFormset`, containing `appsearch.forms.ConstraintForm` instances.\n\n#### `field_data_url`\nThe URL the appsearch Javascript should use to fetch the list of searchable fields for a given model once a selection has been made on `model_selection_form`. The URL is derived at construction time by reversing the default URL name `\"appsearch:constraint-fields\"`, optionally including the prefix designated at construction time, sent in by the view building the Searcher out of the keyword arguments returned by `BaseSearchView.get_searcher_kwargs()`.\n\n#### `operator_data_url`\nLike `field_data_url`, the URL the appsearch Javascript should use to fetch the list of valid operators for the model and field combination selected on the UI.\n\n#### `ready`\nA read-only flag for determining if a search can be performed. `ready` is only True if both the model selection form and the constraint formset pass the normal `is_valid()` checks.\n\n#### `model`\nOnly available after `ready` is checked and `model_selection_form` can have its selected model determined. The model class that the search will operator on.\n\n#### `model_config`\nOnly available after `ready` is checked, like `model`. The configuration `ModelSearch` instance associated with the selected model class.\n\n#### `results`\nA dictionary of result data available after `ready` is True and the view had consequently generated the final search query and executed it. The `results` dictionary is used exclusively in the templates to render the UI table with the column headers and row data.\n\n##### `results['count']`\nThe length of the result queryset.\n\n##### `results['list']`\nThe iterable list of data rows. Each \"row\" is represented by a list of column data for the UI table. The results list is made up of the return values of `ModelSearch.get_object_data()`.\n\n##### `results['fields']`\nThe list of verbose names to represent the fields designated by the model's `ModelSearch.display_fields` list.\n\n##### `results['natural_string']`\nA string built using the constraint formset options, built with a prefix string \"where\" and joining each constraint form with a comma. The result is a string in the format:\n\n \"where {verbosename1} {operator1} {value1}, {verbosename2} {operator2} {value2}\"\n\n#### `build_queryset(model, query[, queryset=None])`\nWhen the forms are valid and the search will be performed, this method applies the `query` object (a combination of `django.db.models.query.Q` instances) to the `model` class. This method takes care to also select the necessary related fields that the model configuration will show via `ModelSearch.display_fields`.\n\nThis can serve as a hook for the Searcher object to make final modifications to the query, regardless of the model class. Most queryset modifications should take place in each `ModelSearch.get_queryset()` method, since each model can control its base queryset in a clearer context.\n\nBy default, the machinery in appsearch will not pass a `queryset` argument directly to this method, but if you subclass `Searcher` and override this method, you may call `super()` to send this default implementation a base queryset to use in place of the model's default manager queryset. This is appropriate when all searchable models use a common query interface, such as sharing a project-level object manager or permission system.\n\nThe return value of this method is the queryset resulting from the model queryset filtered by `query`.\n\n#### `get_select_related_fields(model, config)`\nReturns the list of queryset names that will be sent to an eventual call to the model's queryset `select_related()`. The default list is generated by examining `config`'s `display_fields`.\n\n### `SearchMixin`\n**`appsearch.views.SearchMixin`**\n\nMachinery for building a `Searcher` instance and inserting it into the template context.\n\n#### `searcher_class`\n**Default**: `Searcher`\n\n#### `context_object_name`\n**Default**: `\"search\"`\n\nThe name that the `Searcher` instance will be given in the template context.\n\n#### `model_selection_form_class`\n**Default**: `appsearch.forms.ModelSelectionForm`\n\nThe form that is responsible for the initial model dropdown in the search UI. The default form provides an automatic verification against the registry, provides a ContentType id obfuscation, and defines a couple of methods to retrieve a validated instance's selected model class and associated `ModelSearch` configuration.\n\nTo provide a modified form, make sure it either subclasses `ModelSelectionForm` or provides the identical API methods `get_selected_model()` and `get_selected_model_configuration()`.\n\n#### `constraint_form_class`\n**Default**: `appsearch.forms.ConstraintForm`\n\nAn instance of this form class represents a row in the constraint builder UI, composed of fields that describe the constraint: the core AND/OR, the field to inspect, the operator, and the term or terms that describe the constraint.\n\nBy default, the `field` and `operator` fields have an empty choices list, since the choices depend on a valid selection in the model selection form. The frontend Javascript queries the core appsearch AJAX views to look up the appropriate choices from the registry. Consequently, the form's field-cleaning methods verify a valid selection.\n\nAll of the constraint form's fields are cleaned and database-ready values are returned. For example, the field `type`, which describes if the constraint is an AND or OR operation is cleaned to `operator.and_` or `operator.or_`, respectively. Accordingly, the `operator` field is cleaned to the actual queryset language path(s), such as `\"related__lookup__path\"`.\n\n#### `constraint_formset_class`\n**Default**: `appsearch.forms.ConstraintFormset`\n\nThe formset class used as the basis of `formset_factory()` creation. The default form overrides an internal method to ensure that the model selection form's corresponding configuration is sent to the constructor of the constraint forms within. It contains no other logic or overrides.\n\n#### `get_model_selection_form_class()`\nReturns `self.model_selection_form_class`\n\n#### `get_constraint_form_class()`\nReturns `self.constraint_form_class`\n\n#### `get_constraint_formset_class()`\nReturns `self.constraint_formset_class`\n\n#### `form_template_name`\n**Default**: `\"appsearch/default_form.html\"`\n\nThis default template includes the contents of the default templates at `search_form_template_name` and `results_list_template_name`.\n\n#### `search_form_template_name`\n**Default**: `\"appsearch/search_form.html\"`\n\nRenders the search forms, not including the search results.\n\n#### `results_list_template_name`\n**Default**: `\"appsearch/results_list.html\"`\n\nRenders the results list, not including the search forms. The output of the template is blank if no search was executed on the current request.\n\n#### `get_form_template_name()`\nReturns `self.form_template_name`\n\n#### `get_search_form_template_name()`\nReturns `self.search_form_template_name`\n\n#### `get_results_list_template_name()`\nReturns `self.results_list_template_name`\n\n#### `get_searcher_class()`\nReturns `self.searcher_class`\n\n#### `get_searcher_kwargs()`\nReturns a dictionary of keyword arguments to be passed to the searcher constructor. The default kwargs are the template names specified by the view.\n\n#### `get_searcher()`\nReturns an instantiated searcher, using the class provided by `get_searcher_class()` and the keyword arguments given by `get_searcher_kwargs()`.\n\n#### `get_context_object_name()`\nReturns `self.context_object_name`.\n\n#### `get_context_data(**kwargs)`\nAdds the `Searcher` instance to the context via the name given by `get_context_object_name()`\n\nIf the searcher instance reports that it is fully valid, the search will be executed during this method.\n\n### `BaseSearchView`\n**`appsearch.views.BaseSearchView`**\n\nInherits from `SearchMixin` and the built-in `TemplateView`.\n\n### Build Process:\n1. Update the `__version_info__` inside of the application. Commit and push.\n2. Tag the release with the version. `git tag -m \"Release\"; git push --tags`\n3. Build the release `rm -rf dist build *egg-info; python setup.py sdist bdist_wheel`\n4. Upload the data `twine upload dist/*`\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "https://github.com/pivotal-energy-solutions/django-appsearch/archive/1.1.5.tar.gz", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/pivotal-energy-solutions/django-appsearch", "keywords": "django search", "license": "", "maintainer": "", "maintainer_email": "", "name": "django-appsearch", "package_url": "https://pypi.org/project/django-appsearch/", "platform": "", "project_url": "https://pypi.org/project/django-appsearch/", "project_urls": { "Bug Reports": "https://github.com/pivotal-energy-solutions/django-appsearch/issues", "Download": "https://github.com/pivotal-energy-solutions/django-appsearch/archive/1.1.5.tar.gz", "Homepage": "https://github.com/pivotal-energy-solutions/django-appsearch", "Say Thanks!": "http://saythanks.io/to/rh0dium", "Source": "https://github.com/pivotal-energy-solutions/django-appsearch" }, "release_url": "https://pypi.org/project/django-appsearch/1.1.5/", "requires_dist": [ "django (<2.0,>=1.11)" ], "requires_python": "", "summary": "Framework and generic app for cross-model searches on a single page", "version": "1.1.5" }, "last_serial": 5636769, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "1156042dc32853ab6ddbe429a63eba15", "sha256": "a687d3225406bf56478358cf3b5ac284b6cc056835b0df26c1217bdbf789e09c" }, "downloads": -1, "filename": "django_appsearch-1.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "1156042dc32853ab6ddbe429a63eba15", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 34869, "upload_time": "2018-04-24T20:07:18", "url": "https://files.pythonhosted.org/packages/78/86/92b96742d9bb918639706863ee228c5775f51d941b42d26df1241be6a34f/django_appsearch-1.0.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "25bf5943bb8dbc02da6879f99515a852", "sha256": "3f365cb5ad60eabb09c195620cb7cf46554f092e62a37bfcf0daf8fc173a3835" }, "downloads": -1, "filename": "django-appsearch-1.0.0.tar.gz", "has_sig": false, "md5_digest": "25bf5943bb8dbc02da6879f99515a852", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40280, "upload_time": "2018-04-24T20:07:20", "url": "https://files.pythonhosted.org/packages/b7/d4/abb8c0e682000fbb1a4bdb8d679c7afbe85ccd4fbffd693557ac4fe9f9fc/django-appsearch-1.0.0.tar.gz" } ], "1.0.0rc1": [ { "comment_text": "", "digests": { "md5": "8675ab76374fe847eec736f99ceaeb1c", "sha256": "7c24221e205c2a4176bc0051a70b86d69a71c6b7fdae9d726ed61376adebc260" }, "downloads": -1, "filename": "django_appsearch-1.0.0rc1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8675ab76374fe847eec736f99ceaeb1c", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 34915, "upload_time": "2018-04-24T19:58:09", "url": "https://files.pythonhosted.org/packages/05/f1/dd282cd126576e6351553ffccb4fef9ef4ed13b7c131289a73a3f3f7db06/django_appsearch-1.0.0rc1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8b5442f5c81813bc6b3398f25029c159", "sha256": "97cf2ca13c547a3160498202c922979199d3a14546c3aa9b703b1ce690f0d482" }, "downloads": -1, "filename": "django-appsearch-1.0.0rc1.tar.gz", "has_sig": false, "md5_digest": "8b5442f5c81813bc6b3398f25029c159", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40286, "upload_time": "2018-04-24T19:58:10", "url": "https://files.pythonhosted.org/packages/da/59/b12c1b1e7a0175664c7d354e05ce336e84055348f97d2ba6452269ad7845/django-appsearch-1.0.0rc1.tar.gz" } ], "1.0.0rc2": [ { "comment_text": "", "digests": { "md5": "df666432f6690a43f553d559b1ee52d0", "sha256": "b60067545805d57b87149dbd3a772e2b299554268d020579b641958ddcbd3c98" }, "downloads": -1, "filename": "django_appsearch-1.0.0rc2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "df666432f6690a43f553d559b1ee52d0", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 34909, "upload_time": "2018-04-24T20:05:01", "url": "https://files.pythonhosted.org/packages/ff/6e/b4419ba1acaf51b2b0c7fe5d74830fed48034540db52b29b87b059c822fb/django_appsearch-1.0.0rc2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7843f26f679400c2ab05edcb85109f93", "sha256": "6b21372287a17e25a4d9700e4b42c47d83463b676261f2827c5218b9be9c6390" }, "downloads": -1, "filename": "django-appsearch-1.0.0rc2.tar.gz", "has_sig": false, "md5_digest": "7843f26f679400c2ab05edcb85109f93", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40286, "upload_time": "2018-04-24T20:05:02", "url": "https://files.pythonhosted.org/packages/0e/40/ed40f39ac30cc33c03356f3a8cd0e4d7f059fe39f56284bc85f2c0c11066/django-appsearch-1.0.0rc2.tar.gz" } ], "1.1.0rc0": [ { "comment_text": "", "digests": { "md5": "6490fbe6c91cf3015ffa97c5ea2c09e1", "sha256": "29f9040a44531086f27d8a11f4fd5b4133ef2ba5ee5ed9739e35e7c7dda88fb9" }, "downloads": -1, "filename": "django_appsearch-1.1.0rc0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "6490fbe6c91cf3015ffa97c5ea2c09e1", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 34934, "upload_time": "2018-10-03T01:32:57", "url": "https://files.pythonhosted.org/packages/92/b1/293b0c579a71031b8df61eeeda337275281c3f20bebfd1f017df1ab38a09/django_appsearch-1.1.0rc0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5fc5fe7a39956548491568539c77fe2f", "sha256": "74455701739524c49d2d8b95bdb3534fe9e85dfd07963e199c411743454093c1" }, "downloads": -1, "filename": "django-appsearch-1.1.0rc0.tar.gz", "has_sig": false, "md5_digest": "5fc5fe7a39956548491568539c77fe2f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40306, "upload_time": "2018-10-03T01:32:59", "url": "https://files.pythonhosted.org/packages/c2/e8/132bcf4352f6c14ebe5359a482d1ef53e017d252fc0185d5dd6ab4f47cd2/django-appsearch-1.1.0rc0.tar.gz" } ], "1.1.2": [ { "comment_text": "", "digests": { "md5": "e75c603006e351aaafdb8234aa9c05d4", "sha256": "ed65e0886e716fafe8daf45c285680e2a06e36a80aa4481316e25f9c4ffdf776" }, "downloads": -1, "filename": "django_appsearch-1.1.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e75c603006e351aaafdb8234aa9c05d4", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 34519, "upload_time": "2018-10-03T19:39:45", "url": "https://files.pythonhosted.org/packages/36/a0/91f4143d3352ea3caafcc42304d82a2d56c905c22d2cf7ff532356fbc315/django_appsearch-1.1.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "71a420a8069016176240b62364608e55", "sha256": "5a031f4f301d178264dc07b81e81a8fc433c3382d07acd4dc82ac48799c03f8e" }, "downloads": -1, "filename": "django-appsearch-1.1.2.tar.gz", "has_sig": false, "md5_digest": "71a420a8069016176240b62364608e55", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 39984, "upload_time": "2018-10-03T19:39:47", "url": "https://files.pythonhosted.org/packages/0c/62/e240d0615eb3e54dd6d55f503cb9ef99936ee87042ec14462a75c63248a3/django-appsearch-1.1.2.tar.gz" } ], "1.1.3": [ { "comment_text": "", "digests": { "md5": "f548234759380eea305249b776b4ad15", "sha256": "8478358e8a142c33ba30e69e3fccc4d6fade05e1ac6d5549cea279bdd92fda8e" }, "downloads": -1, "filename": "django_appsearch-1.1.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "f548234759380eea305249b776b4ad15", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 34536, "upload_time": "2018-11-01T23:07:42", "url": "https://files.pythonhosted.org/packages/77/e1/829b811295b7bbfea103d47b207f255cae3958fd780673405cc013a0fd78/django_appsearch-1.1.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "99db7e6d83b7defc5b5161c940746888", "sha256": "ed872aed197c9921e2cb4588efc18c0b600d9c66d6443c6aac337673779694a6" }, "downloads": -1, "filename": "django-appsearch-1.1.3.tar.gz", "has_sig": false, "md5_digest": "99db7e6d83b7defc5b5161c940746888", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40001, "upload_time": "2018-11-01T23:07:43", "url": "https://files.pythonhosted.org/packages/98/9a/1f191fa95b58452874a73ac0b4303291fb514f5e35c88043272427e0d6b1/django-appsearch-1.1.3.tar.gz" } ], "1.1.4": [ { "comment_text": "", "digests": { "md5": "774ebb3896aca0e5afac1ed2e412d4bb", "sha256": "5866d0ab98477e0d9d2fa883def46672cf0fd1db56483cd5bab6f969b89a9037" }, "downloads": -1, "filename": "django_appsearch-1.1.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "774ebb3896aca0e5afac1ed2e412d4bb", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 34613, "upload_time": "2019-08-05T22:22:47", "url": "https://files.pythonhosted.org/packages/16/3f/31e2124d4e2ada555c49fe9dde133cdc467fd91b2f1e00b37c4dbf559500/django_appsearch-1.1.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "81dca59c4b575e1638007239e7536932", "sha256": "13ceedd86fd9e1e7305b1155b90e95f3efdb15e7486f540e67c49af2cd637939" }, "downloads": -1, "filename": "django-appsearch-1.1.4.tar.gz", "has_sig": false, "md5_digest": "81dca59c4b575e1638007239e7536932", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40077, "upload_time": "2019-08-05T22:22:49", "url": "https://files.pythonhosted.org/packages/45/7b/b506ab48ad3bd34366d7afbfd4a1b9f07e97c472232431b93ac439b349ee/django-appsearch-1.1.4.tar.gz" } ], "1.1.5": [ { "comment_text": "", "digests": { "md5": "21270895d8340c2ce244df14d80f1603", "sha256": "7fbad846601ae374cb2c12f400768e1ede86b41f66876c67f833fa6cebdc93ed" }, "downloads": -1, "filename": "django_appsearch-1.1.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "21270895d8340c2ce244df14d80f1603", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 34639, "upload_time": "2019-08-05T22:44:19", "url": "https://files.pythonhosted.org/packages/d2/07/53a1b9f0a9758c28445930d3dd52bce15438638bd068303edfd27f92cb9f/django_appsearch-1.1.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9b7ef34a9dffe6d13e46f3bcc7ef2a90", "sha256": "15dd4e8bdde5f814940f6f38793cfaa37bf657e814dc3417e3d4a839291c4a3d" }, "downloads": -1, "filename": "django-appsearch-1.1.5.tar.gz", "has_sig": false, "md5_digest": "9b7ef34a9dffe6d13e46f3bcc7ef2a90", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40095, "upload_time": "2019-08-05T22:44:21", "url": "https://files.pythonhosted.org/packages/cd/ef/1f8f379229f939f9a706f2b425d7a237af3f165beb8737a5301bcf2d45b3/django-appsearch-1.1.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "21270895d8340c2ce244df14d80f1603", "sha256": "7fbad846601ae374cb2c12f400768e1ede86b41f66876c67f833fa6cebdc93ed" }, "downloads": -1, "filename": "django_appsearch-1.1.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "21270895d8340c2ce244df14d80f1603", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 34639, "upload_time": "2019-08-05T22:44:19", "url": "https://files.pythonhosted.org/packages/d2/07/53a1b9f0a9758c28445930d3dd52bce15438638bd068303edfd27f92cb9f/django_appsearch-1.1.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9b7ef34a9dffe6d13e46f3bcc7ef2a90", "sha256": "15dd4e8bdde5f814940f6f38793cfaa37bf657e814dc3417e3d4a839291c4a3d" }, "downloads": -1, "filename": "django-appsearch-1.1.5.tar.gz", "has_sig": false, "md5_digest": "9b7ef34a9dffe6d13e46f3bcc7ef2a90", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40095, "upload_time": "2019-08-05T22:44:21", "url": "https://files.pythonhosted.org/packages/cd/ef/1f8f379229f939f9a706f2b425d7a237af3f165beb8737a5301bcf2d45b3/django-appsearch-1.1.5.tar.gz" } ] }