diff --git a/LICENSE b/LICENSE index 116e98c..4b0eb18 100644 --- a/LICENSE +++ b/LICENSE @@ -1,12 +1,10 @@ -Copyright (c) 2016, Oscar Cortez -All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +MIT License -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Copyright (c) 2017, Oscar Cortez -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -* Neither the name of dj-places nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in index 57f02f3..6232472 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,4 +2,5 @@ include AUTHORS.md include CHANGELOG.md include LICENSE include README.md -recursive-include djplaces *.html *js *.css *py +recursive-include places/templates *.html +recursive-include places/static *.js *.css diff --git a/Makefile b/Makefile index 9f32ae3..e452622 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ help: @echo "test-all - run tests on every Python version with tox" @echo "coverage - check code coverage quickly with the default Python" @echo "docs - generate Sphinx HTML documentation, including API docs" + @echo "demo - run the demo project" @echo "release - package and upload a release" @echo "sdist - package" @@ -46,6 +47,9 @@ docs: $(MAKE) -C docs html open docs/_build/html/index.html +run: + python example/manage.py runserver + release: clean python setup.py sdist upload python setup.py bdist_wheel upload diff --git a/README.md b/README.md index b25d5b1..3e5975d 100644 --- a/README.md +++ b/README.md @@ -20,32 +20,29 @@ Install dj-places and add it to your installed apps: INSTALLED_APPS = ( ... - 'djplaces', + 'places', ... ) Add your maps api key in your settings ( [read more here](https://developers.google.com/maps/documentation/javascript/3.exp/reference) ): - MAPS_API_KEY='YourAwesomeUltraSecretKey' + PLACES_MAPS_API_KEY='YourAwesomeUltraSecretKey' Then use it in a project: - from djplaces.fields import LocationField - place = models.CharField(max_length=250) - location = LocationField(base_field='place') + from places.fields import PlacesField + location = PlacesField() Demo ------ - + TODO-LIST -------- * [ ] Write some test ASAP! * [ ] Support Inline Admin -* [ ] Set custom zoom map value -* [ ] Custom property for lat and lng values Running Tests -------------- @@ -59,8 +56,6 @@ Does the code actually work? Credits --------- -Special thanks to [Helmy Giacoman](https://github.com/eos87) for motivating me to make this package. - Tools used in rendering this package: * [Cookiecutter](https://github.com/audreyr/cookiecutter) @@ -71,4 +66,4 @@ Similar Projects ------------ * [Django Location Field](https://github.com/caioariede/django-location-field) -* [Django Geoposition](https://github.com/philippbosch/django-geoposition) +* [Django GeoPosition](https://github.com/philippbosch/django-geoposition) diff --git a/djplaces/__init__.py b/djplaces/__init__.py deleted file mode 100644 index 858de17..0000000 --- a/djplaces/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = '1.0.5' diff --git a/djplaces/fields.py b/djplaces/fields.py deleted file mode 100644 index 11cec6a..0000000 --- a/djplaces/fields.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- - -from django.db.models import CharField -from django.core.exceptions import ImproperlyConfigured -from django.utils.translation import ugettext_lazy as _ - -from .widgets import LocationWidget - - -class LocationField(CharField): - description = _("A geoposition field (latitude and longitude)") - - def __init__(self, verbose_name=None, name=None, - base_field=None, *args, **kwargs): - self.verbose_name = verbose_name - self.name = name - self.base_field = base_field - kwargs['max_length'] = 63 - super(LocationField, self).__init__( - verbose_name, name, *args, **kwargs) - - def deconstruct(self): - name, path, args, kwargs = super(LocationField, self).deconstruct() - del kwargs["max_length"] - - if self.base_field == '': - raise ImproperlyConfigured() - return name, path, args, kwargs - - def formfield(self, **kwargs): - kwargs['widget'] = LocationWidget - return super(LocationField, self).formfield(**kwargs) diff --git a/djplaces/static/css/djplaces.css b/djplaces/static/css/djplaces.css deleted file mode 100644 index 80ee0e5..0000000 --- a/djplaces/static/css/djplaces.css +++ /dev/null @@ -1,7 +0,0 @@ -.djplaces { - height: 500px; - width: 500px; - border: 1px solid #CACACA; - margin-top: 10px; -} - diff --git a/djplaces/static/js/djplaces.js b/djplaces/static/js/djplaces.js deleted file mode 100644 index c324eda..0000000 --- a/djplaces/static/js/djplaces.js +++ /dev/null @@ -1,32 +0,0 @@ -var dj = jQuery.noConflict(); - -dj(function() { - - var options = { - map: "#map_location", - mapOptions: { zoom: 10 }, - markerOptions: { draggable: true }, - types: ["geocode", "establishment"], - }, - geocomplete = dj("#id_place"); - - if ( dj('#id_location').val() ) { - options.location = dj('#id_location').val() - } - - geocomplete - .geocomplete(options) - .bind("geocode:result", function(event, result) { - dj('#id_location').val(result.geometry.location.lat() + ',' + result.geometry.location.lng()); - }) - .bind("geocode:error", function(event, status){ - console.log("ERROR: " + status); - }) - .bind("geocode:multiple", function(event, results){ - console.log("Multiple: " + results.length + " results found"); - }) - .bind("geocode:dragged", function(event, latLng){ - dj('#id_location').val(latLng.lat() + ',' + latLng.lng()); - }); - -}); diff --git a/djplaces/templates/djplaces/map_widget.html b/djplaces/templates/djplaces/map_widget.html deleted file mode 100644 index 5ef867b..0000000 --- a/djplaces/templates/djplaces/map_widget.html +++ /dev/null @@ -1,5 +0,0 @@ - -{{ field_input }} - -
- diff --git a/djplaces/widgets.py b/djplaces/widgets.py deleted file mode 100644 index 4b5dc6c..0000000 --- a/djplaces/widgets.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- - -from django import forms -from django.forms import widgets -from django.conf import settings -from django.template.loader import render_to_string -from django.utils.safestring import mark_safe - - -class LocationWidget(widgets.TextInput): - - def render(self, name, value, attrs=None): - text_input = super(LocationWidget, self).render(name, value, attrs) - - return render_to_string('djplaces/map_widget.html', { - 'field_name': name, - 'field_input': mark_safe(text_input) - }) - - def _media(self): - return forms.Media( - css={'all': ('css/djplaces.css',)}, - js=( - '//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js', # NOQA - '//maps.googleapis.com/maps/api/js?key='+ settings.MAPS_API_KEY +'&libraries=places', # NOQA - '//cdnjs.cloudflare.com/ajax/libs/geocomplete/1.7.0/jquery.geocomplete.js', # NOQA - 'js/djplaces.js', - ) - ) - media = property(_media) diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..1431ae5 --- /dev/null +++ b/example/README.md @@ -0,0 +1,24 @@ +##Example Project for django-places + +This example is provided as a convenience feature to allow potential users to try the app straight from the app repo without having to create a django project. + +It can also be used to develop the app in place. + +To run this example, follow these instructions: + +1. Navigate to the `example` directory +2. Install the requirements for the package: + + pip install -r requirements.txt + +3. Make and apply migrations + + python manage.py makemigrations + + python manage.py migrate + +4. Run the server + + python manage.py runserver + +5. Access from the browser at `http://127.0.0.1:8000` diff --git a/example/example/__init__.py b/example/example/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/example/example/settings.py b/example/example/settings.py new file mode 100644 index 0000000..05337c7 --- /dev/null +++ b/example/example/settings.py @@ -0,0 +1,116 @@ +""" +Django settings for example project. + +Generated by Cookiecutter Django Package + +For more information on this file, see +https://docs.djangoproject.com/en/1.9/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.9/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '%b&p!s^@301dc=@y^*x92ff*hzelqm0)m0vy29-dwexs=e1w+t' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + + 'places', + 'geoposition', + 'points', +] + +MIDDLEWARE_CLASSES = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'example.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates'), ], + 'OPTIONS': { + 'debug': True, + 'loaders': [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ], + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + 'django.template.context_processors.tz', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'example.wsgi.application' + +# Database +# https://docs.djangoproject.com/en/1.9/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + +# Password validation +# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [] + +# Internationalization +# https://docs.djangoproject.com/en/1.9/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.9/howto/static-files/ + +STATIC_URL = '/static/' + +PLACES_MAPS_API_KEY = 'AIzaSyBS2jGczsTKS9oMjcr_OS4BV3nRcp8EgHw' diff --git a/example/example/urls.py b/example/example/urls.py new file mode 100644 index 0000000..6446991 --- /dev/null +++ b/example/example/urls.py @@ -0,0 +1,22 @@ +"""example URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/1.9/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.conf.urls import url, include + 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) +""" +from django.conf.urls import url, include +from django.contrib import admin + + +urlpatterns = [ + url(r'^admin/', admin.site.urls), +] diff --git a/example/example/wsgi.py b/example/example/wsgi.py new file mode 100644 index 0000000..fd6d782 --- /dev/null +++ b/example/example/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for example project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") + +application = get_wsgi_application() diff --git a/example/manage.py b/example/manage.py new file mode 100644 index 0000000..2605e37 --- /dev/null +++ b/example/manage.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/example/points/__init__.py b/example/points/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/example/points/admin.py b/example/points/admin.py new file mode 100644 index 0000000..3d4d4de --- /dev/null +++ b/example/points/admin.py @@ -0,0 +1,22 @@ +from django.conf import settings +from django.contrib import admin + +from .models import Place + +class PlaceAdmin(admin.ModelAdmin): + list_display = ('position_map', 'location') + + def position_map(self, instance): + if instance.location is not None: + return 'Use this document as a way to quick start any new project.
+The current template is loaded from
+ django-places/example/templates/base.html
.
Whenever you overwrite the contents of django-places/djplaces/urls.py
with your
+ own content, you should see it here.