feat: Auto-add location to adoption notice
This commit is contained in:
parent
c8f65c9c54
commit
2a9dc337d2
@ -40,6 +40,7 @@ class AdoptionNoticeForm(forms.ModelForm):
|
|||||||
'name',
|
'name',
|
||||||
'group_only',
|
'group_only',
|
||||||
'searching_since',
|
'searching_since',
|
||||||
|
'location_string',
|
||||||
'description',
|
'description',
|
||||||
'further_information',
|
'further_information',
|
||||||
),
|
),
|
||||||
@ -47,7 +48,7 @@ class AdoptionNoticeForm(forms.ModelForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AdoptionNotice
|
model = AdoptionNotice
|
||||||
fields = ['name', "group_only", "further_information", "description", "searching_since"]
|
fields = ['name', "group_only", "further_information", "description", "searching_since", "location_string"]
|
||||||
|
|
||||||
|
|
||||||
class AnimalForm(forms.ModelForm):
|
class AnimalForm(forms.ModelForm):
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
# Generated by Django 5.0.6 on 2024-06-05 13:19
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("fellchensammlung", "0006_announcement_type"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="location",
|
||||||
|
name="country",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="location",
|
||||||
|
name="description",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="location",
|
||||||
|
name="postcode",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="adoptionnotice",
|
||||||
|
name="location",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
to="fellchensammlung.location",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="adoptionnotice",
|
||||||
|
name="location_string",
|
||||||
|
field=models.CharField(
|
||||||
|
default="72072", max_length=200, verbose_name="Ortsangabe"
|
||||||
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="location",
|
||||||
|
name="latitude",
|
||||||
|
field=models.FloatField(default=47),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="location",
|
||||||
|
name="longitude",
|
||||||
|
field=models.FloatField(default=9),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="location",
|
||||||
|
name="osm_id",
|
||||||
|
field=models.IntegerField(default=1),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="location",
|
||||||
|
name="place_id",
|
||||||
|
field=models.IntegerField(default=1),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="rescueorganization",
|
||||||
|
name="location_string",
|
||||||
|
field=models.CharField(
|
||||||
|
default="72072", max_length=200, verbose_name="Ort der Organisation"
|
||||||
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="location",
|
||||||
|
name="name",
|
||||||
|
field=models.CharField(max_length=2000),
|
||||||
|
),
|
||||||
|
]
|
@ -66,19 +66,11 @@ class Location(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.name}"
|
return f"{self.name}"
|
||||||
|
|
||||||
GERMANY = "DE"
|
place_id = models.IntegerField()
|
||||||
AUSTRIA = "AT"
|
osm_id = models.IntegerField()
|
||||||
SWITZERLAND = "CH"
|
latitude = models.FloatField()
|
||||||
COUNTRIES_CHOICES = {
|
longitude = models.FloatField()
|
||||||
GERMANY: "Germany",
|
name = models.CharField(max_length=2000)
|
||||||
AUSTRIA: "Austria",
|
|
||||||
SWITZERLAND: "Switzerland"
|
|
||||||
}
|
|
||||||
|
|
||||||
name = models.CharField(max_length=200)
|
|
||||||
postcode = models.CharField(max_length=200)
|
|
||||||
country = models.CharField(max_length=20, choices=COUNTRIES_CHOICES)
|
|
||||||
description = models.TextField(null=True, blank=True, verbose_name=_('Beschreibung'))
|
|
||||||
|
|
||||||
|
|
||||||
class RescueOrganization(models.Model):
|
class RescueOrganization(models.Model):
|
||||||
@ -87,6 +79,7 @@ class RescueOrganization(models.Model):
|
|||||||
|
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
trusted = models.BooleanField(default=False, verbose_name=_('Vertrauenswürdig'))
|
trusted = models.BooleanField(default=False, verbose_name=_('Vertrauenswürdig'))
|
||||||
|
location_string = models.CharField(max_length=200, verbose_name=_("Ort der Organisation"))
|
||||||
location = models.ForeignKey(Location, on_delete=models.PROTECT)
|
location = models.ForeignKey(Location, on_delete=models.PROTECT)
|
||||||
instagram = models.URLField(null=True, blank=True, verbose_name=_('Instagram Profil'))
|
instagram = models.URLField(null=True, blank=True, verbose_name=_('Instagram Profil'))
|
||||||
facebook = models.URLField(null=True, blank=True, verbose_name=_('Facebook Profil'))
|
facebook = models.URLField(null=True, blank=True, verbose_name=_('Facebook Profil'))
|
||||||
@ -112,6 +105,8 @@ class AdoptionNotice(models.Model):
|
|||||||
further_information = models.URLField(null=True, blank=True, verbose_name=_('Link zu mehr Informationen'))
|
further_information = models.URLField(null=True, blank=True, verbose_name=_('Link zu mehr Informationen'))
|
||||||
group_only = models.BooleanField(default=False, verbose_name=_('Ausschließlich Gruppenadoption'))
|
group_only = models.BooleanField(default=False, verbose_name=_('Ausschließlich Gruppenadoption'))
|
||||||
photos = models.ManyToManyField(Image, blank=True)
|
photos = models.ManyToManyField(Image, blank=True)
|
||||||
|
location_string = models.CharField(max_length=200, verbose_name=_("Ortsangabe"))
|
||||||
|
location = models.ForeignKey(Location, blank=True, null=True, on_delete=models.SET_NULL,)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def animals(self):
|
def animals(self):
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import requests
|
import requests
|
||||||
import json
|
import json
|
||||||
from notfellchen import __version__ as nf_version
|
from notfellchen import __version__ as nf_version
|
||||||
|
from fellchensammlung.models import Location
|
||||||
|
|
||||||
from math import radians, sqrt, sin, cos, atan2
|
from math import radians, sqrt, sin, cos, atan2
|
||||||
|
|
||||||
@ -21,13 +22,15 @@ def calculate_distance_between_coordinates(position1, position2):
|
|||||||
distance_lat = radians(latitude2 - latitude1)
|
distance_lat = radians(latitude2 - latitude1)
|
||||||
distance_long = radians(longitude2 - longitude1)
|
distance_long = radians(longitude2 - longitude1)
|
||||||
|
|
||||||
a = pow(sin(distance_lat / 2), 2) + cos(radians(latitude1)) * cos(radians(latitude2)) * pow(sin(distance_long / 2), 2)
|
a = pow(sin(distance_lat / 2), 2) + cos(radians(latitude1)) * cos(radians(latitude2)) * pow(sin(distance_long / 2),
|
||||||
|
2)
|
||||||
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||||
|
|
||||||
distance_in_km = earth_radius_km * c
|
distance_in_km = earth_radius_km * c
|
||||||
|
|
||||||
return distance_in_km
|
return distance_in_km
|
||||||
|
|
||||||
|
|
||||||
class ResponseMock:
|
class ResponseMock:
|
||||||
content = b'[{"place_id":138181499,"licence":"Data \xc2\xa9 OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright","osm_type":"relation","osm_id":1247237,"lat":"48.4949904","lon":"9.040330235970146","category":"boundary","type":"postal_code","place_rank":21, "importance":0.12006895017929346,"addresstype":"postcode","name":"72072","display_name":"72072, Derendingen, T\xc3\xbcbingen, Landkreis T\xc3\xbcbingen, Baden-W\xc3\xbcrttemberg, Deutschland", "boundingbox":["48.4949404","48.4950404","9.0402802","9.0403802"]}]'
|
content = b'[{"place_id":138181499,"licence":"Data \xc2\xa9 OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright","osm_type":"relation","osm_id":1247237,"lat":"48.4949904","lon":"9.040330235970146","category":"boundary","type":"postal_code","place_rank":21, "importance":0.12006895017929346,"addresstype":"postcode","name":"72072","display_name":"72072, Derendingen, T\xc3\xbcbingen, Landkreis T\xc3\xbcbingen, Baden-W\xc3\xbcrttemberg, Deutschland", "boundingbox":["48.4949404","48.4950404","9.0402802","9.0403802"]}]'
|
||||||
status_code = 200
|
status_code = 200
|
||||||
@ -43,21 +46,33 @@ class RequestMock:
|
|||||||
|
|
||||||
|
|
||||||
class GeoAPI:
|
class GeoAPI:
|
||||||
|
api_url = "https://nominatim.openstreetmap.org/search"
|
||||||
|
headers = {
|
||||||
|
'User-Agent': f"Notfellchen {nf_version}",
|
||||||
|
'From': 'info@notfellchen.org' # This is another valid field
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, debug=True):
|
def __init__(self, debug=True):
|
||||||
self.api_url = "https://nominatim.openstreetmap.org/search"
|
|
||||||
if debug:
|
if debug:
|
||||||
self.requests = RequestMock
|
self.requests = RequestMock
|
||||||
else:
|
else:
|
||||||
self.requests = requests
|
self.requests = requests
|
||||||
|
|
||||||
def get_coordinates_from_postcode(self, postcode):
|
def get_coordinates_from_postcode(self, postcode):
|
||||||
headers = {
|
result = self.requests.get(self.api_url, {"q": postcode, "format": "jsonv2"}, headers=self.headers).json()[0]
|
||||||
'User-Agent': f"Notfellchen {nf_version}",
|
|
||||||
'From': 'info@notfellchen.org' # This is another valid field
|
|
||||||
}
|
|
||||||
result = self.requests.get(self.api_url, {"q": postcode, "format": "jsonv2"}, headers=headers).json()[0]
|
|
||||||
return result["lat"], result["lon"]
|
return result["lat"], result["lon"]
|
||||||
|
|
||||||
|
def get_location_from_string(self, location_string):
|
||||||
|
result = self.requests.get(self.api_url, {"q": location_string, "format": "jsonv2"}, headers=self.headers).json()[0]
|
||||||
|
location = Location.objects.create(
|
||||||
|
place_id=result["place_id"],
|
||||||
|
osm_id=result["osm_id"],
|
||||||
|
latitude=result["lat"],
|
||||||
|
longitude=result["lon"],
|
||||||
|
name=result["name"],
|
||||||
|
)
|
||||||
|
return location
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
geo = GeoAPI(debug=True)
|
geo = GeoAPI(debug=True)
|
||||||
|
@ -27,7 +27,7 @@ urlpatterns = [
|
|||||||
# ex: /search/
|
# ex: /search/
|
||||||
path("suchen/", views.search, name="search"),
|
path("suchen/", views.search, name="search"),
|
||||||
# ex: /vermitteln/
|
# ex: /vermitteln/
|
||||||
path("vermitteln/", views.add_adoption, name="add-adoption"),
|
path("vermitteln/", views.add_adoption_notice, name="add-adoption"),
|
||||||
|
|
||||||
path("ueber-uns/", views.about, name="about"),
|
path("ueber-uns/", views.about, name="about"),
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ from fellchensammlung.models import AdoptionNotice, Text, Animal, Rule, Image, R
|
|||||||
Member
|
Member
|
||||||
from .forms import AdoptionNoticeForm, ImageForm, ReportAdoptionNoticeForm, CommentForm, ReportCommentForm, AnimalForm
|
from .forms import AdoptionNoticeForm, ImageForm, ReportAdoptionNoticeForm, CommentForm, ReportCommentForm, AnimalForm
|
||||||
from .models import Language, Announcement
|
from .models import Language, Announcement
|
||||||
|
from .tools.geo import GeoAPI
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
@ -93,12 +94,19 @@ def search(request):
|
|||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_adoption(request):
|
def add_adoption_notice(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = AdoptionNoticeForm(request.POST, request.FILES, in_adoption_notice_creation_flow=True)
|
form = AdoptionNoticeForm(request.POST, request.FILES, in_adoption_notice_creation_flow=True)
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
instance = form.save()
|
instance = form.save()
|
||||||
|
|
||||||
|
"""Search the location given in the location string and add it to the adoption notice"""
|
||||||
|
geo_api = GeoAPI(debug=True)
|
||||||
|
location = geo_api.get_location_from_string(instance.location_string)
|
||||||
|
instance.location = location
|
||||||
|
instance.save()
|
||||||
|
|
||||||
return redirect(reverse("adoption-notice-add-animal", args=[instance.pk]))
|
return redirect(reverse("adoption-notice-add-animal", args=[instance.pk]))
|
||||||
else:
|
else:
|
||||||
form = AdoptionNoticeForm(in_adoption_notice_creation_flow=True)
|
form = AdoptionNoticeForm(in_adoption_notice_creation_flow=True)
|
||||||
|
Loading…
Reference in New Issue
Block a user