feat: Add important locations to search around

This commit is contained in:
moanos [he/him] 2025-04-27 14:06:17 +02:00
parent f387930dee
commit bb14a346cb
7 changed files with 100 additions and 9 deletions

View File

@ -7,7 +7,7 @@ from django.urls import reverse
from django.utils.http import urlencode
from .models import User, Language, Text, ReportComment, ReportAdoptionNotice, Log, Timestamp, SearchSubscription, \
SpeciesSpecificURL
SpeciesSpecificURL, ImportantLocation
from .models import Animal, Species, RescueOrganization, AdoptionNotice, Location, Rule, Image, ModerationAction, \
Comment, Report, Announcement, AdoptionNoticeStatus, User, Subscriptions, BaseNotification
@ -94,9 +94,11 @@ class ReportAdoptionNoticeAdmin(admin.ModelAdmin):
reported_content_link.short_description = "Reported Content"
class SpeciesSpecificURLInline(admin.StackedInline):
model = SpeciesSpecificURL
@admin.register(RescueOrganization)
class RescueOrganizationAdmin(admin.ModelAdmin):
search_fields = ("name", "description", "internal_comment", "location_string")
@ -122,14 +124,26 @@ class CommentAdmin(admin.ModelAdmin):
class BaseNotificationAdmin(admin.ModelAdmin):
list_filter = ("user", "read")
@admin.register(SearchSubscription)
class SearchSubscriptionAdmin(admin.ModelAdmin):
list_filter = ("owner",)
class ImportantLocationInline(admin.StackedInline):
model = ImportantLocation
@admin.register(Location)
class LocationAdmin(admin.ModelAdmin):
search_fields = ("name__icontains", "city__icontains")
inlines = [
ImportantLocationInline,
]
admin.site.register(Animal)
admin.site.register(Species)
admin.site.register(Location)
admin.site.register(Rule)
admin.site.register(Image)
admin.site.register(ModerationAction)

View File

@ -0,0 +1,23 @@
# Generated by Django 5.1.4 on 2025-04-27 11:31
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0044_alter_location_place_id'),
]
operations = [
migrations.CreateModel(
name='ImportantLocation',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('slug', models.SlugField(unique=True)),
('name', models.CharField(max_length=200)),
('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fellchensammlung.location')),
],
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 5.1.4 on 2025-04-27 11:51
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0045_importantlocation'),
]
operations = [
migrations.AlterField(
model_name='importantlocation',
name='location',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='fellchensammlung.location'),
),
]

View File

@ -3,6 +3,7 @@ from random import choices
from tabnanny import verbose
from django.db import models
from django.template.defaultfilters import slugify
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
@ -99,6 +100,12 @@ class Location(models.Model):
instance.save()
class ImportantLocation(models.Model):
location = models.OneToOneField(Location, on_delete=models.CASCADE)
slug = models.SlugField(unique=True)
name = models.CharField(max_length=200)
class ExternalSourceChoices(models.TextChoices):
OSM = "OSM", _("Open Street Map")

View File

@ -47,7 +47,6 @@ class Search:
elif search_subscription:
self.search_from_search_subscription(search_subscription)
def __str__(self):
return f"Search: {self.sex=}, {self.location=}, {self.area_search=}, {self.max_distance=}"
@ -93,7 +92,6 @@ class Search:
return False
return True
def get_adoption_notices(self):
adoptions = AdoptionNotice.objects.order_by("-created_at")
# Filter for active adoption notices
@ -118,13 +116,21 @@ class Search:
else:
self.search_form = AdoptionNoticeSearchForm()
def search_from_predefined_i_location(self, i_location, max_distance=100):
self.sex = SexChoicesWithAll.ALL
self.location = i_location.location
self.area_search = True
self.search_form = AdoptionNoticeSearchForm(initial={"location_string": self.location.name,
"max_distance": max_distance,
"sex": SexChoicesWithAll.ALL})
self.max_distance = max_distance
def search_from_search_subscription(self, search_subscription: SearchSubscription):
self.sex = search_subscription.sex
self.location = search_subscription.location
self.area_search = True
self.max_distance = search_subscription.max_distance
def subscribe(self, user):
logging.info(f"{user} subscribed to search")
if isinstance(self.location, LocationProxy):

View File

@ -45,6 +45,7 @@ urlpatterns = [
# ex: /search/
path("suchen/", views.search, name="search"),
path("suchen/<slug:important_location_slug>", views.search_important_locations, name="search-by-location"),
# ex: /map/
path("map/", views.map, name="map"),
# ex: /vermitteln/

View File

@ -18,7 +18,8 @@ from notfellchen import settings
from fellchensammlung import logger
from .models import AdoptionNotice, Text, Animal, Rule, Image, Report, ModerationAction, \
User, Location, AdoptionNoticeStatus, Subscriptions, CommentNotification, BaseNotification, RescueOrganization, \
Species, Log, Timestamp, TrustLevel, SexChoicesWithAll, SearchSubscription, AdoptionNoticeNotification
Species, Log, Timestamp, TrustLevel, SexChoicesWithAll, SearchSubscription, AdoptionNoticeNotification, \
ImportantLocation
from .forms import AdoptionNoticeForm, AdoptionNoticeFormWithDateWidget, ImageForm, ReportAdoptionNoticeForm, \
CommentForm, ReportCommentForm, AnimalForm, \
AdoptionNoticeSearchForm, AnimalFormWithDateWidget, AdoptionNoticeFormWithDateWidgetAutoAnimal
@ -200,6 +201,26 @@ def animal_detail(request, animal_id):
return render(request, 'fellchensammlung/details/detail_animal.html', context=context)
def search_important_locations(request, important_location_slug):
i_location = ImportantLocation.objects.get(slug=important_location_slug)
search = Search()
search.search_from_predefined_i_location(i_location)
context = {"adoption_notices": search.get_adoption_notices(),
"search_form": search.search_form,
"place_not_found": search.place_not_found,
"subscribed_search": None,
"searched": False,
"adoption_notices_map": AdoptionNotice.get_active_ANs(),
"map_center": search.position,
"search_center": search.position,
"map_pins": [search],
"location": search.location,
"search_radius": search.max_distance,
"zoom_level": zoom_level_for_radius(search.max_distance),
"geocoding_api_url": settings.GEOCODING_API_URL, }
return render(request, 'fellchensammlung/search.html', context=context)
def search(request):
# A user just visiting the search site did not search, only upon completing the search form a user has really
# searched. This will toggle the "subscribe" button