Базовая карта

This commit is contained in:
2022-04-21 15:28:52 +03:00
parent 3f44f8fc2f
commit 8cd72996cb
63 changed files with 175 additions and 5 deletions

View File

@@ -9,12 +9,16 @@ defusedxml==0.7.1
Django==4.0.3
django-allauth==0.50.0
django-crispy-forms==1.14.0
django-filter==21.1
djangorestframework==3.13.1
djangorestframework-gis==0.18
idna==3.3
oauthlib==3.2.0
psycopg2==2.9.3
pycparser==2.21
PyJWT==2.3.0
python3-openid==3.2.0
pytz==2022.1
requests==2.27.1
requests-oauthlib==1.3.1
sqlparse==0.4.2

View File

5
wheretogo/maps/admin.py Normal file
View File

@@ -0,0 +1,5 @@
from django.contrib import admin
from maps.models import Facility
admin.site.register(Facility)

8
wheretogo/maps/api.py Normal file
View File

@@ -0,0 +1,8 @@
from rest_framework import routers
from maps.viewsets import FacilityViewSet
router = routers.DefaultRouter()
router.register(r"facilities", FacilityViewSet)
urlpatterns = router.urls

7
wheretogo/maps/apps.py Normal file
View File

@@ -0,0 +1,7 @@
from django.apps import AppConfig
class MapConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "maps"
verbose_name = "Maps"

View File

@@ -0,0 +1,29 @@
# Generated by Django 4.0.3 on 2022-04-21 11:59
import django.contrib.gis.db.models.fields
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Facility',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('address', models.CharField(max_length=100)),
('city', models.CharField(max_length=50)),
('location', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326)),
],
options={
'verbose_name': 'facility',
'verbose_name_plural': 'Facilities',
},
),
]

View File

19
wheretogo/maps/models.py Normal file
View File

@@ -0,0 +1,19 @@
from django.contrib.gis.db import models as gis_models
from django.db import models
class Facility(models.Model):
name = models.CharField(max_length=200)
address = models.CharField(max_length=100)
city = models.CharField(max_length=50)
location = gis_models.PointField(
null=True,
blank=True,
)
class Meta:
verbose_name = "facility"
verbose_name_plural = "Facilities"
def __unicode__(self):
return self.name

View File

@@ -0,0 +1,11 @@
from rest_framework_gis import serializers
from maps.models import Facility
class FacilitySerializer(serializers.GeoFeatureModelSerializer):
class Meta:
fields = ("id", "name", "address", "city")
geo_field = "location"
model = Facility

3
wheretogo/maps/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

8
wheretogo/maps/urls.py Normal file
View File

@@ -0,0 +1,8 @@
from django.urls import path
from maps.views import MapView
app_name = "maps"
urlpatterns = [
path("map/", MapView.as_view(), name="map"),
]

6
wheretogo/maps/views.py Normal file
View File

@@ -0,0 +1,6 @@
from django.views.generic.base import TemplateView
class MapView(TemplateView):
template_name = "maps/map.html"

View File

@@ -0,0 +1,13 @@
from rest_framework import viewsets
from rest_framework_gis import filters
from maps.models import Facility
from maps.serializers import FacilitySerializer
class FacilityViewSet(viewsets.ReadOnlyModelViewSet):
bbox_filter_field = "location"
filter_backends = (filters.InBBoxFilter,)
queryset = Facility.objects.all()
serializer_class = FacilitySerializer

View File

@@ -0,0 +1,10 @@
html,
body {
height: 100%;
margin: 0;
}
#map {
height: 100%;
width: 100%;
}

View File

@@ -8,8 +8,11 @@
<head>
<title>{% block head_title %}{% endblock %}</title>
<link rel="icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}">
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<script type = "text/javascript" src="{% static 'js/bootstrap.bundle.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/thirdparty/bootstrap.min.css' %}">
<script type = "text/javascript" src="{% static 'js/thirdparty/bootstrap.bundle.min.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static 'css/own/map.css' %}" />
<link rel="stylesheet" type="text/css" href="https:///unpkg.com/leaflet/dist/leaflet.css" />
<script src="https:///unpkg.com/leaflet/dist/leaflet.js"></script>
{% csrf_token %}
{% block extra_head %}
{% endblock %}
@@ -20,6 +23,9 @@
<a class="navbar-brand" href="/">WhereToGo</a>
<div class="collapse navbar-collapse" id="navbarNavDropdown">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="{% url 'maps:map' %}">{% trans "Map" %}</a>
</li>
</ul>
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
{% if user.is_authenticated %}
@@ -41,9 +47,6 @@
</li>
{% endif %}
</ul>
<form class="d-flex">
</form>
</div>
</div>
</nav>

View File

@@ -0,0 +1,36 @@
{% extends "common/base.html" %}
{% block head_title %}WhereToGo{% endblock %}
{% block content %}
<div id="map"></div>
<script>
const copy = "© <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors";
const url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
const osm = L.tileLayer(url, { attribution: copy });
const map = L.map("map", { layers: [osm], minZoom: 5 });
map.
locate()
.on("locationfound", (e) => map.setView(e.latlng, 8))
.on("locationerror", () => map.setView([0, 0], 5));
async function load_facilities() {
const facilities_url = `/api/facilities/?in_bbox=${map.getBounds().toBBoxString()}`
const response = await fetch(facilities_url)
const geojson = await response.json()
return geojson
}
async function render_facilities() {
const facilities = await load_facilities();
L.geoJSON(facilities)
.bindPopup((layer) => layer.feature.properties.name)
.addTo(map);
}
map.on("moveend", render_facilities);
</script>
{% endblock %}

View File

@@ -32,11 +32,15 @@ INSTALLED_APPS = [
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.gis",
"rest_framework",
"rest_framework_gis",
"crispy_forms",
"crispy_bootstrap5",
"allauth",
"allauth.account",
"allauth.socialaccount",
"maps",
]
SITE_ID = 1
@@ -131,6 +135,7 @@ CRISPY_TEMPLATE_PACK = "bootstrap5"
LOGIN_REDIRECT_URL = "/"
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = "none"
MESSAGE_TAGS = {
messages.DEBUG: "alert-info",

View File

@@ -1,3 +1,4 @@
from argparse import Namespace
from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView
@@ -7,6 +8,8 @@ from django.conf.urls.static import static
urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include("maps.api")),
path("accounts/", include("allauth.urls")),
path("", TemplateView.as_view(template_name="common/index.html")),
path("maps/", include("maps.urls", namespace="maps")),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)