Skip to content

Commit

Permalink
Merge branch 'release/3.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
marteinn committed Apr 1, 2017
2 parents cfd551b + fe3b454 commit cf573c4
Show file tree
Hide file tree
Showing 12 changed files with 394 additions and 20 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ docs/_build
venv*

.idea

example/wagtailgeowidget
138 changes: 131 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

# Wagtail-Geo-Widget

A Google Maps widget for the GeoDjango PointField field in Wagtail.
A Google Maps widget for Wagtail that supports both GeoDjango PointField, StreamField and the standard CharField.

![Screen1](https://raw.githubusercontent.com/frojd/wagtail-geo-widget/develop/img/screen1.png)


## Requirements

- Python 2.7 / Python 3.5
- Wagtail 1.7+ and Django (with GeoDjango)
- Wagtail 1.7+ and Django


## Installation
Expand Down Expand Up @@ -41,9 +41,134 @@ This should be enough to get started.

## Usage

### Without address field
- [Standard CharField](https://github.com/Frojd/wagtail-geo-widget/blob/develop/README.md#standard-charfield)
- [StreamField](https://github.com/Frojd/wagtail-geo-widget/blob/develop/README.md#streamfield)
- [GeoDjango/PointField](https://github.com/Frojd/wagtail-geo-widget/blob/develop/README.md#geodjango-pointfield)

First make sure you have a location field defined in your model, then add a GeoPanel among your content_panels.

## Standard CharField

Define a CharField representing your location, then add a GeoPanel.

```python
from django.db import models
from wagtailgeowidget.edit_handlers import GeoPanel


class MyPage(Page):
location = models.CharField(max_length=250, blank=True, null=True)

content_panels = Page.content_panels + [
GeoPanel('location'),
]
```

The data is stored as a `GEOSGeometry` string (Example: `SRID=4326;POINT(17.35448867187506 59.929179873751934)`. To use the data, we recommend that you add helper methods to your model.

```python
from django.contrib.gis.geos import GEOSGeometry

class MyPage(Page):
# ...

@property
def point(self):
return GEOSGeometry(self.location)

@property
def lat(self):
return self.point.y

@property
def lng(self):
return self.point.x
```

NOTE: While this implementation is quick and easy to setup, the drawback is that it will prevent you from making spatial queries, if that is what you need, use the GeoDjango/Pointer field implementation instead.


### With address field

The panel accepts a `address_field` if you want to the map in coordiation with a geo-lookup (like the screenshot on top).

```python
from django.db import models
from wagtailgeowidget.edit_handlers import GeoPanel


class MyPageWithAddressField(Page):
address = models.CharField(max_length=250, blank=True, null=True)
location = models.CharField(max_length=250, blank=True, null=True)

content_panels = Page.content_panels + [
GeoPanel('location', address_field='address'),
]
```

For more examples, look at the [example](https://github.com/Frojd/wagtail-geo-widget/blob/develop/example/geopage/models.py#L82).


## StreamField

To add a map in a StreamField, import and use the GeoBlock.

```python
from wagtail.wagtailcore.models import Page
from wagtail.wagtailcore.fields import StreamField
from wagtailgeowidget.blocks import GeoBlock

class GeoStreamPage(Page):
body = StreamField([
('map', GeoBlock()),
])

content_panels = Page.content_panels + [
StreamFieldPanel('body'),
]
```

The data is stored as a json struct and you can access it by using value.lat / value.lng

```html
<article>
{% for map_block in page.stream_field %}
<hr />
{{ map_block.value }}
<p>Latitude: {{ map_block.value.lat}}</p>
<p>Longitude: {{ map_block.value.lng }}</p>
{% endfor %}
</article>
```

### With a address field

Make sure you define a field representing the address at the same level as your GeoBlock, either in the StreamField or in a StructBlock.

```python
from wagtail.wagtailadmin.edit_handlers import StreamFieldPanel
from wagtailgeowidget.blocks import GeoBlock


class GeoStreamPage(Page):
body = StreamField([
('map_struct', blocks.StructBlock([
('address', blocks.CharBlock(required=True)),
('map', GeoBlock(address_field='address')),
]))

])

content_panels = Page.content_panels + [
StreamFieldPanel('body'),
]
```

For more examples, look at the [example](https://github.com/Frojd/wagtail-geo-widget/blob/develop/example/geopage/models.py#L64).


## GeoDjango (PointField)

First make sure you have [GeoDjango](https://docs.djangoproject.com/en/1.10/ref/contrib/gis/) correctly setup and a PointField field defined in your model, then add a GeoPanel among your content_panels.

```python
from django.contrib.gis.db import models
Expand All @@ -63,7 +188,6 @@ class MyPage(Page):

The panel accepts a `address_field` if you want to the map in coordiation with a geo-lookup (like the screenshot on top).


```python
from django.contrib.gis.db import models
from wagtailgeowidget.edit_handlers import GeoPanel
Expand All @@ -78,6 +202,7 @@ class MyPageWithAddressField(Page):
]
```

For more examples, look at the [example](https://github.com/Frojd/wagtail-geo-widget/blob/develop/example/geopage/models.py#L35).

## Settings

Expand All @@ -90,7 +215,7 @@ class MyPageWithAddressField(Page):

- [x] Editable map widget for GeoDjango PointerField
- [x] Global default map location
- [ ] Streamfield map widget
- [x] Streamfield map widget


## Contributing
Expand All @@ -101,4 +226,3 @@ Want to contribute? Awesome. Just send a pull request.
## License

Wagtail-Geo-Widget is released under the [MIT License](http://www.opensource.org/licenses/MIT).

29 changes: 29 additions & 0 deletions example/geopage/migrations/0006_geostreampage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.6 on 2017-03-30 18:30
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion
import wagtail.wagtailcore.fields


class Migration(migrations.Migration):

dependencies = [
('wagtailcore', '0032_add_bulk_delete_page_permission'),
('geopage', '0005_auto_20170327_1919'),
]

operations = [
migrations.CreateModel(
name='GeoStreamPage',
fields=[
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
('body', wagtail.wagtailcore.fields.StreamField([])),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
]
37 changes: 37 additions & 0 deletions example/geopage/migrations/0007_auto_20170401_1648.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.6 on 2017-04-01 16:48
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion
import wagtail.wagtailcore.blocks
import wagtail.wagtailcore.fields
import wagtailgeowidget.blocks


class Migration(migrations.Migration):

dependencies = [
('wagtailcore', '0032_add_bulk_delete_page_permission'),
('geopage', '0006_geostreampage'),
]

operations = [
migrations.CreateModel(
name='ClassicGeoPage',
fields=[
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
('address', models.CharField(blank=True, max_length=250, null=True)),
('location', models.CharField(blank=True, max_length=250, null=True)),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
migrations.AlterField(
model_name='geostreampage',
name='body',
field=wagtail.wagtailcore.fields.StreamField([('map', wagtailgeowidget.blocks.GeoBlock()), ('map_struct', wagtail.wagtailcore.blocks.StructBlock([('address', wagtail.wagtailcore.blocks.CharBlock(required=True)), ('map', wagtailgeowidget.blocks.GeoBlock(address_field='address'))], icon='user'))]),
),
]
78 changes: 75 additions & 3 deletions example/geopage/models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
from __future__ import absolute_import, unicode_literals

from django.contrib.gis.db import models
from django.contrib.gis.geos import GEOSGeometry
from wagtail.wagtailcore.models import Orderable, Page
from wagtail.wagtailadmin.edit_handlers import FieldPanel, InlinePanel
from wagtail.wagtailadmin.edit_handlers import (
FieldPanel,
InlinePanel,
MultiFieldPanel,
ObjectList,
TabbedInterface,
)

from wagtail.wagtailcore import blocks
from modelcluster.fields import ParentalKey
from wagtailgeowidget.edit_handlers import GeoPanel

Expand All @@ -14,7 +23,8 @@ class GeoLocation(models.Model):

panels = [
FieldPanel('title'),
GeoPanel('location'),
FieldPanel('address'),
GeoPanel('location', address_field='address')
]


Expand All @@ -27,6 +37,68 @@ class GeoPage(Page):
location = models.PointField(srid=4326, null=True, blank=True)

content_panels = Page.content_panels + [
GeoPanel('location'),
InlinePanel('related_locations', label="Related locations"),
]

location_panels = [
MultiFieldPanel([
FieldPanel('address'),
GeoPanel('location', address_field='address'),
], heading='Location')
]

edit_handler = TabbedInterface([
ObjectList(content_panels, heading='Content'),
ObjectList(location_panels, heading='Location'),
ObjectList(Page.settings_panels, heading='Settings',
classname="settings"),
])


from wagtail.wagtailcore.fields import StreamField
from wagtail.wagtailadmin.edit_handlers import StreamFieldPanel

from wagtailgeowidget.blocks import GeoBlock


class GeoStreamPage(Page):
body = StreamField([
('map', GeoBlock()),
('map_struct', blocks.StructBlock([
('address', blocks.CharBlock(required=True)),
('map', GeoBlock(address_field='address')),
], icon='user'))
])

content_panels = Page.content_panels + [
StreamFieldPanel('body'),
]

def get_context(self, request):
data = super(GeoStreamPage, self).get_context(request)
return data


class ClassicGeoPage(Page):
address = models.CharField(max_length=250, blank=True, null=True)
location = models.CharField(max_length=250, blank=True, null=True)

content_panels = Page.content_panels + [
GeoPanel('location', address_field='address'),
]

def get_context(self, request):
data = super(ClassicGeoPage, self).get_context(request)
return data

@property
def point(self):
return GEOSGeometry(self.location)

@property
def lat(self):
return self.point.y

@property
def lng(self):
return self.point.x
18 changes: 18 additions & 0 deletions example/geopage/templates/geopage/classic_geo_page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{% extends "base.html" %}
{% load wagtailcore_tags %}

{% block content %}
<h1>{{ page.title }}</h1>

<ul>
<li>
Point: {{ page.point }}
</li>
<li>
Lat: {{ page.lat }}
</li>
<li>
Lng: {{ page.lng }}
</li>
</ul>
{% endblock %}
14 changes: 14 additions & 0 deletions example/geopage/templates/geopage/geo_stream_page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% extends "base.html" %}
{% load wagtailcore_tags %}


{% block content %}
<article>
{% for block in page.body %}
<hr />
{{ block.value }}
<p>Latitude: {{ block.value.lat}}</p>
<p>Longitude: {{ block.value.lng }}</p>
{% endfor %}
</article>
{% endblock %}
Loading

0 comments on commit cf573c4

Please sign in to comment.