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$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="leaflet" level="application" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||
|
|
|
@ -14,8 +14,9 @@ Including another URLconf
|
|||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
from django.urls import path, include
|
||||
|
||||
urlpatterns = [
|
||||
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.admin import register
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from .models import Friend
|
||||
from .models import Friend, FriendLocation
|
||||
|
||||
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.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):
|
||||
pass
|
||||
|
||||
|
||||
# class Location(models.Model):
|
||||
# latitude = models.
|
||||
class FriendLocation(BaseModel):
|
||||
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.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