Display friends on map
This commit is contained in:
parent
02cb38219c
commit
940cb1e413
12 changed files with 234 additions and 5 deletions
|
@ -16,6 +16,7 @@
|
||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$" />
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="leaflet" level="application" />
|
||||||
</component>
|
</component>
|
||||||
<component name="TemplatesService">
|
<component name="TemplatesService">
|
||||||
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||||
|
|
|
@ -14,8 +14,9 @@ Including another URLconf
|
||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import path
|
from django.urls import path, include
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
|
path('', include('map.urls')),
|
||||||
]
|
]
|
||||||
|
|
12
map/admin.py
12
map/admin.py
|
@ -1,5 +1,15 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.contrib.admin import register
|
||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
from .models import Friend
|
from .models import Friend, FriendLocation
|
||||||
|
|
||||||
admin.site.register(Friend, UserAdmin)
|
admin.site.register(Friend, UserAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
@register(FriendLocation)
|
||||||
|
class FriendLocationAdmin(admin.ModelAdmin):
|
||||||
|
fieldsets = [
|
||||||
|
(None, {'fields': ('friend',)}),
|
||||||
|
('Place', {'fields': ('latitude', 'longitude')}),
|
||||||
|
('Dates', {'fields': ('start_date', 'end_date')}),
|
||||||
|
]
|
||||||
|
|
11
map/fields.py
Normal file
11
map/fields.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class CoordinateField(models.DecimalField):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs['max_digits'] = 11
|
||||||
|
kwargs['decimal_places'] = 8
|
||||||
|
kwargs['help_text'] = ('Format : xxx,xxxxxxxx<br>'
|
||||||
|
'(max 8 décimales, max 3 chiffres avant la virgule, séparateur : virgule)')
|
||||||
|
|
||||||
|
super().__init__(*args, **kwargs)
|
29
map/migrations/0002_friendlocation.py
Normal file
29
map/migrations/0002_friendlocation.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Generated by Django 2.1.7 on 2019-03-02 11:13
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import map.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('map', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='FriendLocation',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
('latitude', map.fields.CoordinateField(decimal_places=8, help_text='Format : xxx,xxxxxxxx<br>(max 8 décimales, max 3 chiffres avant la virgule, séparateur : virgule)', max_digits=11)),
|
||||||
|
('longitude', map.fields.CoordinateField(decimal_places=8, help_text='Format : xxx,xxxxxxxx<br>(max 8 décimales, max 3 chiffres avant la virgule, séparateur : virgule)', max_digits=11)),
|
||||||
|
('start_date', models.DateField(blank=True, null=True, verbose_name='from')),
|
||||||
|
('end_date', models.DateField(blank=True, null=True, verbose_name='until')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
21
map/migrations/0003_friendlocation_friend.py
Normal file
21
map/migrations/0003_friendlocation_friend.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Generated by Django 2.1.7 on 2019-03-02 11:17
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('map', '0002_friendlocation'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='friendlocation',
|
||||||
|
name='friend',
|
||||||
|
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,10 +1,36 @@
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
from map.fields import CoordinateField
|
||||||
|
|
||||||
|
|
||||||
|
class BaseModel(models.Model):
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
|
||||||
class Friend(AbstractUser):
|
class Friend(AbstractUser):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# class Location(models.Model):
|
class FriendLocation(BaseModel):
|
||||||
# latitude = models.
|
latitude = CoordinateField()
|
||||||
|
longitude = CoordinateField()
|
||||||
|
start_date = models.DateField('from', blank=True, null=True)
|
||||||
|
end_date = models.DateField('until', blank=True, null=True)
|
||||||
|
friend = models.ForeignKey(Friend, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def latitude_str(self):
|
||||||
|
return str(self.latitude)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def longitude_str(self):
|
||||||
|
return str(self.longitude)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.friend.get_full_name()} from {self.start_date} to {self.end_date}'
|
||||||
|
|
||||||
|
|
4
map/static/map/style.css
Normal file
4
map/static/map/style.css
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#map {
|
||||||
|
height: 70vh;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
82
map/templates/map/base.html
Normal file
82
map/templates/map/base.html
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||||
|
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||||
|
|
||||||
|
<!-- Fontawesome CSS -->
|
||||||
|
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css"
|
||||||
|
integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="{% static 'map/style.css' %}">
|
||||||
|
|
||||||
|
{% block add-head %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
<title>{{ app.site.name }} · {% block title %}Home{% endblock %}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{#{% include 'map/navbar.html' %}#}
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-dismissible alert-{{ message.tags }} fade show" role="alert">
|
||||||
|
{{ message|safe }}
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>{% block h1 %}{% endblock %}</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% block quick_actions %}
|
||||||
|
{% if quick_actions %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 d-none d-md-block"> {# Visible only on large screens #}
|
||||||
|
{% for qa in quick_actions %}
|
||||||
|
<a href="{{ qa.url }}" class="btn btn-{{ qa.category }}">
|
||||||
|
{% if qa.icon %}<i class="{{ qa.icon }}"></i>{% endif %}
|
||||||
|
{{ qa.display }}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="col-12 d-md-none"> {# Visible only on small screens #}
|
||||||
|
{% for qa in quick_actions %}
|
||||||
|
<a href="{{ qa.url }}" class="btn btn-{{ qa.category }} btn-block">
|
||||||
|
{% if qa.icon %}<i class="{{ qa.icon }}"></i>{% endif %}
|
||||||
|
{{ qa.display }}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bootstrap JS -->
|
||||||
|
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
||||||
|
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
|
||||||
|
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
|
||||||
|
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
32
map/templates/map/map.html
Normal file
32
map/templates/map/map.html
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{% extends 'map/base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}Carte autour de {{ place }}{% endblock %}
|
||||||
|
{% block h1 %}Carte autour de {{ place }}{% endblock %}
|
||||||
|
|
||||||
|
{% block add-head %}
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.4.0/dist/leaflet.css"
|
||||||
|
integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA=="
|
||||||
|
crossorigin=""/>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="map"></div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
<script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"
|
||||||
|
integrity="sha512-QVftwZFqvtRNi0ZyCtsznlKSWOStnDORoefr1enyq5mVL4tmKB3S/EnC3rRJcxCPavG10IcrVGSmPh6Qw5lwrg=="
|
||||||
|
crossorigin=""></script>
|
||||||
|
|
||||||
|
<script type="application/javascript">
|
||||||
|
let map = L.map('map').setView([45.805, 2.67], 5);
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
}).addTo(map);
|
||||||
|
{% for location in locations %}
|
||||||
|
let marker = L.marker([{{ location.latitude_str }}, {{ location.longitude_str }}]).addTo(map);
|
||||||
|
marker.bindPopup("<strong>{{ location.friend.get_full_name }}</strong> from {{ location.start_date }} until {{ location.end_date }}").openPopup();
|
||||||
|
{% endfor %}
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
6
map/urls.py
Normal file
6
map/urls.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.urls import path
|
||||||
|
from map import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('map/', views.MapView.as_view()),
|
||||||
|
]
|
|
@ -1,3 +1,9 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from django.views.generic import ListView
|
||||||
|
from map import models
|
||||||
|
|
||||||
# Create your views here.
|
|
||||||
|
class MapView(ListView):
|
||||||
|
model = models.FriendLocation
|
||||||
|
context_object_name = 'locations'
|
||||||
|
template_name = 'map/map.html'
|
||||||
|
|
Loading…
Reference in a new issue