Skip to content

Commit

Permalink
apps: add kiezradar models
Browse files Browse the repository at this point in the history
  • Loading branch information
m4ra committed Nov 20, 2024
1 parent b352c8c commit 7619a7f
Show file tree
Hide file tree
Showing 17 changed files with 545 additions and 0 deletions.
6 changes: 6 additions & 0 deletions changelog/8473.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
### Added

- kiezradar app
- SearchProfile model
- KiezRadarFilter model with a m2m relation with SearchProfile for multiselect topics
- custom signal to add filtering topics via the viewset create api to the searchprofile
Empty file.
3 changes: 3 additions & 0 deletions meinberlin/apps/kiezradar/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
36 changes: 36 additions & 0 deletions meinberlin/apps/kiezradar/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated

from .models import SearchProfile
from .serializers import SearchProfileSerializer


class SearchProfileViewSet(viewsets.ModelViewSet):
"""
ViewSet for managing SearchProfile objects.
"""

queryset = SearchProfile.objects.all()
serializer_class = SearchProfileSerializer
permission_classes = [IsAuthenticated]

def perform_create(self, serializer):
"""
Override to handle saving of many-to-many relations.
"""
# Save the instance first to get a primary key.
search_profile = serializer.save(user=self.request.user)

# Get the many-to-many data from the request.
queries_data = self.request.data.get("queries", [])
organisations_data = self.request.data.get("organisations", [])
districts_data = self.request.data.get("districts", [])
project_types_data = self.request.data.get("project_types", [])
topics_data = self.request.data.get("topics", [])

# Add many-to-many relations.
search_profile.queries.set(queries_data)
search_profile.organisations.set(organisations_data)
search_profile.districts.set(districts_data)
search_profile.project_types.set(project_types_data)
search_profile.topics.set(topics_data)
6 changes: 6 additions & 0 deletions meinberlin/apps/kiezradar/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class Config(AppConfig):
name = "meinberlin.apps.kiezradar"
label = "meinberlin_kiezradar"
135 changes: 135 additions & 0 deletions meinberlin/apps/kiezradar/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Generated by Django 4.2.11 on 2024-11-19 16:45

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.A4_ORGANISATIONS_MODEL),
("a4administrative_districts", "0001_initial"),
("a4projects", "0046_alter_project_information_alter_project_result"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="KiezradarQuery",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("text", models.CharField(max_length=256, unique=True)),
],
),
migrations.CreateModel(
name="ProjectType",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"participation",
models.SmallIntegerField(
choices=[
(0, "information (no participation)"),
(1, "consultation"),
(2, "cooperation"),
(3, "decision-making"),
],
verbose_name="Type",
),
),
],
),
migrations.CreateModel(
name="SearchProfile",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255)),
("description", models.TextField(blank=True, null=True)),
("disabled", models.BooleanField(default=False)),
(
"status",
models.SmallIntegerField(
choices=[(0, "running"), (1, "done")], verbose_name="Status"
),
),
(
"districts",
models.ManyToManyField(
blank=True,
related_name="search_profiles",
to="a4administrative_districts.administrativedistrict",
),
),
(
"organisations",
models.ManyToManyField(
blank=True,
related_name="search_profiles",
to=settings.A4_ORGANISATIONS_MODEL,
),
),
(
"project_types",
models.ManyToManyField(
blank=True,
related_name="search_profiles",
to="meinberlin_kiezradar.projecttype",
),
),
(
"queries",
models.ManyToManyField(
blank=True,
related_name="search_profiles",
to="meinberlin_kiezradar.kiezradarquery",
),
),
(
"topics",
models.ManyToManyField(
blank=True,
related_name="search_profiles",
to="a4projects.topic",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="search_profiles",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"ordering": ["name"],
},
),
]
Empty file.
85 changes: 85 additions & 0 deletions meinberlin/apps/kiezradar/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _

from adhocracy4.administrative_districts.models import AdministrativeDistrict
from adhocracy4.projects.models import Topic

Organisation = settings.A4_ORGANISATIONS_MODEL


class KiezradarQuery(models.Model):
text = models.CharField(max_length=256, unique=True)

def __str__(self):
return f"kiezradar query - {self.text}"


class ProjectType(models.Model):
PARTICIPATION_INFORMATION = 0
PARTICIPATION_CONSULTATION = 1
PARTICIPATION_COOPERATION = 2
PARTICIPATION_DECISION_MAKING = 3
PARTICIPATION_CHOICES = (
(PARTICIPATION_INFORMATION, _("information (no participation)")),
(PARTICIPATION_CONSULTATION, _("consultation")),
(PARTICIPATION_COOPERATION, _("cooperation")),
(PARTICIPATION_DECISION_MAKING, _("decision-making")),
)
participation = models.SmallIntegerField(
choices=PARTICIPATION_CHOICES,
verbose_name=_("Type"),
)

def __str__(self):
return f"participation type - {self.participation}"


class SearchProfile(models.Model):
STATUS_ONGOING = 0
STATUS_DONE = 1
STATUS_CHOICES = ((STATUS_ONGOING, _("running")), (STATUS_DONE, _("done")))

user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="search_profiles",
)
name = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
disabled = models.BooleanField(default=False)
status = models.SmallIntegerField(
choices=STATUS_CHOICES,
verbose_name=_("Status"),
)
queries = models.ManyToManyField(
KiezradarQuery,
related_name="search_profiles",
blank=True,
)
organisations = models.ManyToManyField(
Organisation,
related_name="search_profiles",
blank=True,
)
districts = models.ManyToManyField(
AdministrativeDistrict,
related_name="search_profiles",
blank=True,
)
project_types = models.ManyToManyField(
ProjectType,
related_name="search_profiles",
blank=True,
)
topics = models.ManyToManyField(
Topic,
related_name="search_profiles",
blank=True,
)

class Meta:
ordering = ["name"]

def __str__(self):
return f"kiezradar search profile - {self.name}, disabled {self.disabled}"
92 changes: 92 additions & 0 deletions meinberlin/apps/kiezradar/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
from rest_framework import serializers

from adhocracy4.administrative_districts.models import AdministrativeDistrict
from meinberlin.apps.kiezradar.models import KiezradarQuery
from meinberlin.apps.kiezradar.models import ProjectType
from meinberlin.apps.kiezradar.models import SearchProfile
from meinberlin.apps.organisations.models import Organisation
from meinberlin.apps.projects.serializers import TopicSerializer


class KiezradarQuerySerializer(serializers.ModelSerializer):
"""Serializer for the KiezradarQuery model."""

class Meta:
model = KiezradarQuery
fields = ["id", "text"]


class ProjectTypeSerializer(serializers.ModelSerializer):
"""Serializer for the ProjectType model."""

participation_display = serializers.CharField(
source="get_participation_display", read_only=True
)

class Meta:
model = ProjectType
fields = ["id", "participation", "participation_display"]


class SearchProfileSerializer(serializers.ModelSerializer):
"""Serializer for the SearchProfile model."""

queries = KiezradarQuerySerializer(many=True)
organisations = serializers.PrimaryKeyRelatedField(
many=True, queryset=Organisation.objects.all()
)
districts = serializers.PrimaryKeyRelatedField(
many=True, queryset=AdministrativeDistrict.objects.all()
)
project_types = ProjectTypeSerializer(many=True)
topics = TopicSerializer(many=True)
status_display = serializers.CharField(source="get_status_display", read_only=True)

class Meta:
model = SearchProfile
fields = [
"id",
"user",
"name",
"description",
"disabled",
"status",
"status_display",
"queries",
"organisations",
"districts",
"project_types",
"topics",
]

read_only_fields = ["user"]

def update(self, instance, validated_data):
"""
Custom update to handle many-to-many relationships.
"""
# Pop many-to-many fields from validated_data
queries_data = validated_data.pop("queries", None)
organisations_data = validated_data.pop("organisations", None)
districts_data = validated_data.pop("districts", None)
project_types_data = validated_data.pop("project_types", None)
topics_data = validated_data.pop("topics", None)

# Update non-m2m fields
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()

# Update many-to-many relationships
if queries_data:
instance.queries.set(queries_data)
if organisations_data:
instance.organisations.set(organisations_data)
if districts_data:
instance.districts.set(districts_data)
if project_types_data:
instance.project_types.set(project_types_data)
if topics_data:
instance.topics.set(topics_data)

return instance
3 changes: 3 additions & 0 deletions meinberlin/apps/kiezradar/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
1 change: 1 addition & 0 deletions meinberlin/config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
"meinberlin.apps.captcha",
"meinberlin.apps.cms",
"meinberlin.apps.contrib",
"meinberlin.apps.kiezradar",
"meinberlin.apps.likes",
"meinberlin.apps.livequestions",
"meinberlin.apps.maps",
Expand Down
2 changes: 2 additions & 0 deletions meinberlin/config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from meinberlin.apps.extprojects.api import ExternalProjectListViewSet
from meinberlin.apps.ideas.api import IdeaViewSet
from meinberlin.apps.kiezkasse.api import KiezkasseViewSet
from meinberlin.apps.kiezradar.api import SearchProfileViewSet
from meinberlin.apps.likes.api import LikesViewSet
from meinberlin.apps.likes.routers import LikesDefaultRouter
from meinberlin.apps.livequestions.api import LiveQuestionViewSet
Expand All @@ -47,6 +48,7 @@

router = routers.DefaultRouter()
router.register(r"follows", FollowViewSet, basename="follows")
router.register(r"searchprofiles", SearchProfileViewSet, basename="searchprofiles")
router.register(r"reports", ReportViewSet, basename="reports")
router.register(r"polls", PollViewSet, basename="polls")
router.register(r"projects", ProjectListViewSet, basename="projects")
Expand Down
Loading

0 comments on commit 7619a7f

Please sign in to comment.