diff --git a/README.md b/README.md
index 2a7eb74..684c323 100644
--- a/README.md
+++ b/README.md
@@ -12,9 +12,3 @@ Start container with `docker-compose up -d` and create admin user (first-run):
```sh
docker-compose exec app python manage.py createsuperuser --email ''
```
-
-Optionally, create an initial set of cities:
-
-```sh
-docker-compose exec app python manage.py loaddata initial_cities.json
-```
diff --git a/backend/app/admin.py b/backend/app/admin.py
index 6a0daa7..904411b 100644
--- a/backend/app/admin.py
+++ b/backend/app/admin.py
@@ -1,7 +1,7 @@
from django.contrib import admin
from django.contrib.auth.models import Group # , User
-from app.models import City, Place
+from app.models import Place
# admin.site.register(Place, )
@@ -21,21 +21,8 @@ admin.site.unregister(Group)
# App adjustments
#############################
-@admin.register(City)
-class CityAdmin(admin.ModelAdmin):
- list_display = ['name', 'place_count', 'center', 'zoom']
-
- def get_readonly_fields(self, request, obj=None):
- return ['name'] if obj else []
-
- @admin.display(description='Orte')
- def place_count(self, instance: 'City'):
- return instance.places.count()
-
-
@admin.register(Place)
class PlaceAdmin(admin.ModelAdmin):
- list_display = ['address', 'city', 'since', 'until', 'created', 'updated']
- list_filter = ['city']
+ list_display = ['address', 'since', 'until', 'created', 'updated']
search_fields = ['address', 'description']
ordering = ['-updated']
diff --git a/backend/app/fixtures/__init__.py b/backend/app/fixtures/__init__.py
deleted file mode 100755
index e69de29..0000000
diff --git a/backend/app/fixtures/initial_cities.json b/backend/app/fixtures/initial_cities.json
deleted file mode 100644
index 8ae891a..0000000
--- a/backend/app/fixtures/initial_cities.json
+++ /dev/null
@@ -1,10 +0,0 @@
-[
- {
- "model": "app.city",
- "fields": {
- "name": "Berlin",
- "center": "52.52, 13.40",
- "zoom": 12
- }
- }
-]
\ No newline at end of file
diff --git a/backend/app/migrations/0002_single_city.py b/backend/app/migrations/0002_single_city.py
new file mode 100644
index 0000000..8366d6f
--- /dev/null
+++ b/backend/app/migrations/0002_single_city.py
@@ -0,0 +1,22 @@
+# Generated by Django 4.2.13 on 2024-07-27 23:43
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('app', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='place',
+ name='city',
+ ),
+ migrations.DeleteModel(
+ name='City',
+ ),
+ migrations.RunSQL(
+ "UPDATE app_place SET img = 'img/'||id||'.jpg' WHERE img != '';"),
+ ]
diff --git a/backend/app/models/__init__.py b/backend/app/models/__init__.py
index e7872b4..c4897dc 100644
--- a/backend/app/models/__init__.py
+++ b/backend/app/models/__init__.py
@@ -1,2 +1 @@
-from .city import City # noqa: F401
from .place import Place # noqa: F401
diff --git a/backend/app/models/city.py b/backend/app/models/city.py
deleted file mode 100644
index afae4c4..0000000
--- a/backend/app/models/city.py
+++ /dev/null
@@ -1,85 +0,0 @@
-from django.conf import settings
-from django.core.validators import MaxValueValidator, MinValueValidator
-from django.db import models
-from django.db.models.signals import post_delete
-from django.dispatch import receiver
-from django.template.defaultfilters import slugify
-
-import json
-import shutil
-from pathlib import Path
-
-from map_location.fields import LocationField
-
-import typing
-if typing.TYPE_CHECKING:
- from app.models.place import Place
-
-
-class City(models.Model):
- name = models.CharField('Name', max_length=100)
- center = LocationField('Zentrum', options={
- 'markerZoom': 12,
- })
- zoom = models.IntegerField('Zoom', validators=[
- MinValueValidator(4), MaxValueValidator(18)])
-
- places: 'models.QuerySet[Place]'
-
- class Meta:
- verbose_name = 'Stadt'
- verbose_name_plural = 'Städte'
- ordering = ['name']
-
- def __str__(self) -> str:
- return self.name
-
- @property
- def slug(self):
- return slugify(self.name)
-
- @property
- def data_path(self) -> Path:
- return settings.MEDIA_ROOT / str(self.pk)
-
- @property
- def data_url(self) -> str:
- return f'{self.pk}'
-
- def save(self, *args, **kwargs):
- rv = super().save(*args, **kwargs)
- City.update_cities_json()
- return rv
-
- def asJson(self) -> 'dict[str, str|list[float]|int|None]':
- return {
- 'id': self.pk,
- 'slug': self.slug,
- 'name': self.name,
- 'zoom': self.zoom,
- 'loc': [round(self.center.lat, 6),
- round(self.center.long, 6)] if self.center else None,
- }
-
- def update_json(self):
- rv = []
- for place in self.places.all():
- if not place.location or not place.isVacant:
- continue
- rv.append(place.asJson())
- self.data_path.mkdir(parents=True, exist_ok=True)
- with open(self.data_path / 'data.json', 'w') as fp:
- json.dump(rv, fp)
-
- @staticmethod
- def update_cities_json():
- cities_json = settings.MEDIA_ROOT / 'cities.json'
- with open(cities_json, 'w') as fp:
- json.dump([city.asJson() for city in City.objects.all()], fp)
-
-
-@receiver(post_delete, sender=City)
-def on_delete_City(sender, instance: 'City', using, **kwargs):
- if instance.data_path.exists():
- shutil.rmtree(instance.data_path, ignore_errors=True)
- City.update_cities_json()
diff --git a/backend/app/models/place.py b/backend/app/models/place.py
index 6c9f473..95c58ea 100644
--- a/backend/app/models/place.py
+++ b/backend/app/models/place.py
@@ -1,8 +1,10 @@
+from django.conf import settings
from django.db import models
from django.db.models.signals import post_delete
from django.dispatch import receiver
import os
+import json
from datetime import date
from map_location.fields import LocationField
@@ -10,28 +12,20 @@ from map_location.fields import LocationField
from app.fields import MonthField
from common.form.img_with_preview import ThumbnailImageField
-import typing
-if typing.TYPE_CHECKING:
- from app.models.city import City
-
def overwrite_img_upload(instance: 'Place', filename: str):
id = instance.pk or (Place.objects.count() + 1)
- path = instance.city.data_path / f'{id}.jpg'
+ path = settings.MEDIA_ROOT / 'img' / f'{id}.jpg'
if path.is_file():
os.remove(path)
- return f'{instance.city.data_url}/{id}.jpg'
+ return f'img/{id}.jpg'
class Place(models.Model):
created = models.DateTimeField('Erstellt', auto_now_add=True)
updated = models.DateTimeField('Geändert', auto_now=True)
- city: 'models.ForeignKey[City]' = models.ForeignKey(
- 'City', on_delete=models.CASCADE, related_name='places',
- verbose_name='Stadt')
-
address = models.CharField('Adresse', max_length=100)
img = ThumbnailImageField('Bild', blank=True, null=True,
upload_to=overwrite_img_upload) # type: ignore
@@ -65,7 +59,7 @@ class Place(models.Model):
def save(self, *args, **kwargs):
rv = super().save(*args, **kwargs)
- self.city.update_json()
+ Place.update_json()
return rv
def asJson(self) -> 'dict[str, str|list[float]|None]':
@@ -80,7 +74,13 @@ class Place(models.Model):
round(self.location.long, 6)] if self.location else None,
}
+ @staticmethod
+ def update_json():
+ with open(settings.MEDIA_ROOT / 'data.json', 'w') as fp:
+ json.dump([x.asJson() for x in Place.objects.all()
+ if x.location and x.isVacant], fp)
+
@receiver(post_delete, sender=Place)
def on_delete_Place(sender, instance: 'Place', using, **kwargs):
- instance.city.update_json()
+ Place.update_json()
diff --git a/frontend/index.html b/frontend/index.html
index c7afa0f..08a2f10 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -31,12 +31,7 @@
-