Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/forms #10

Merged
merged 9 commits into from
Jun 6, 2024
235 changes: 235 additions & 0 deletions building_dialouge_webapp/heat/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
from django import forms


class ElectricityConsumptionForm(forms.Form):
household_members = forms.ChoiceField(
label="Wie viele Personen leben in ihrem Haushalt?",
choices=[
("", "bitte auswählen"),
("1", "1"),
("2", "2"),
("3", "3"),
("4", "4"),
("5", "5"),
],
widget=forms.Select(attrs={"class": "form-select"}),
)
net_electricity_consumption1 = forms.IntegerField(
label="Netto strom Verbrauch genau:",
widget=forms.NumberInput(attrs={"class": "form-control"}),
required=False,
)
net_electricity_consumption2 = forms.ChoiceField(
label="oder ungefähr",
choices=[
("", "bitte auswählen"),
("high_consumption", "viel"),
("medium_consumption", "mittel"),
("low_consumption", "wenig"),
],
required=False,
widget=forms.Select(attrs={"class": "form-select"}),
)

def clean(self):
cleaned_data = super().clean()
net_electricity_consumption1 = cleaned_data.get("net_electricity_consumption1")
net_electricity_consumption2 = cleaned_data.get("net_electricity_consumption2")

if not net_electricity_consumption1 and not net_electricity_consumption2:
self.add_error(
"net_electricity_consumption2",
"Nettostromverbrauch entweder genau oder ungefähr eingeben.",
)

return cleaned_data


class ElectricityGenerationForm(forms.Form):
pv_owned = forms.BooleanField(
label="Haben Sie eine PV-Anlage?",
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
required=False,
)
installed_pv_power = forms.IntegerField(
label="Wie groß ist die installierte Leistung?",
widget=forms.NumberInput(attrs={"class": "form-control"}),
required=False,
)
roof_cardinal_direction = forms.ChoiceField(
label="In welcher Richtung ist ihr Haus ausgerichtet?",
choices=[
("north", "Norden"),
("east", "Osten"),
("south_east", "Süd/Ost"),
("south", "Süden"),
("west", "Westen"),
],
widget=forms.RadioSelect,
)
roof_angle = forms.ChoiceField(
label="Welchen Winkel hat das Dach?",
choices=[
("north", "Flach"),
("east", "Schräg"),
],
widget=forms.RadioSelect,
)

def clean(self):
cleaned_data = super().clean()
pv_owned = cleaned_data.get("pv_owned")
installed_pv_power = cleaned_data.get("installed_pv_power")

if pv_owned and not installed_pv_power:
self.add_error("installed_pv_power", "Installierte Leistung eingeben.")
if not pv_owned and installed_pv_power:
self.add_error(
"pv_owned",
"Ankreuzen/auswählen, wenn eine installierte Leistung eingegeben wird.",
)

return cleaned_data


class HeatGenerationForm(forms.Form):
heat_output = forms.IntegerField(
label="thermische Leistung der Heizungsanlage (Kessel)",
widget=forms.NumberInput(attrs={"class": "form-control"}),
required=False,
)
cannot_enter_info = forms.BooleanField(
label="nicht vorhanden",
required=False,
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
)
heat_pump_share = forms.MultipleChoiceField(
label="Aus welchen Anteilen setzt sich ihre Wärmepumpe zusammen?",
choices=[
("air", "Luft"),
("water", "Wasser"),
("brine", "Sole"),
("no_heat_pump", "keine Wärmepumpe"),
],
widget=forms.CheckboxSelectMultiple,
)

def clean(self):
cleaned_data = super().clean()
heat_output = cleaned_data.get("heat_output")
cannot_enter_info = cleaned_data.get("cannot_enter_info")

if not heat_output and not cannot_enter_info:
self.add_error("cannot_enter_info", "'Nicht vorhanden' auswählen.")
if heat_output and cannot_enter_info:
self.add_error(
"heat_output",
"Keine Leistung eintragen, wenn 'Nicht vorhanden'.",
)

return cleaned_data


class HeatGenerationForm2(forms.Form):
solar_thermal_system = forms.BooleanField(
label="Haben Sie eine Solarthermieanlage?",
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
required=False,
)
collector_surface = forms.IntegerField(
label="Kollektorfläche",
widget=forms.NumberInput(attrs={"class": "form-control"}),
required=False,
)
collector_cardinal_direction = forms.ChoiceField(
label="In welcher Richtung ist sie ausgerichtet?",
choices=[
("north", "Norden"),
("east", "Osten"),
("south", "Süden"),
("west", "Westen"),
],
widget=forms.RadioSelect,
)
roof_angle = forms.ChoiceField(
label="Welchen Winkel hat das Dach?",
choices=[
("north", "Flach"),
("east", "Schräg"),
],
widget=forms.RadioSelect,
)

def clean(self):
cleaned_data = super().clean()
solar_thermal_system = cleaned_data.get("solar_thermal_system")
collector_surface = cleaned_data.get("collector_surface")
collector_cardinal_direction = cleaned_data.get("collector_cardinal_direction")

if solar_thermal_system:
if not collector_surface:
self.add_error(
"collector_surface",
"Dieses Feld ausfüllen, wenn Solarthermieanlage vorhanden.",
)
if not collector_cardinal_direction:
self.add_error(
"collector_cardinal_direction",
"Dieses Feld ausfüllen, wenn Solarthermieanlage vorhanden.",
)
elif collector_surface or collector_cardinal_direction:
error_message = (
"Kollektorfläche und Ausrichtung auslassen, "
"wenn keine Solarthermieanlage vorhanden."
)
raise forms.ValidationError(error_message)

return cleaned_data


class HeatConsumptionForm(forms.Form):
heating_requirement1 = forms.IntegerField(
label="Jahresheizbedarf pro m² genau:",
widget=forms.NumberInput(attrs={"class": "form-control"}),
initial=1,
required=False,
)
heating_requirement2 = forms.ChoiceField(
label="ungefähr:",
choices=[
("high_consumption", "viel"),
("medium_consumption", "mittel"),
("low_consumption", "wenig"),
],
required=False,
widget=forms.Select(attrs={"class": "form-select"}),
)

def clean(self):
cleaned_data = super().clean()
heating_requirement1 = cleaned_data.get("heating_requirement1")
heating_requirement2 = cleaned_data.get("heating_requirement2")

if not heating_requirement1 and not heating_requirement2:
self.add_error(
"heating_requirement2",
"Jahresheizbedarf entweder genau oder ungefähr eingeben.",
)

return cleaned_data


class HeatStorageForm(forms.Form):
buffer_storage_owned = forms.BooleanField(
label="Ist ein Pufferspeicher vorhanden?",
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
required=False,
)


class ElectricityStorageForm(forms.Form):
battery_owned = forms.BooleanField(
label="Ist eine Batterie vorhanden?",
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
required=False,
)
8 changes: 7 additions & 1 deletion building_dialouge_webapp/heat/urls.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
from django.urls import path

from . import views

app_name = "heat"

urlpatterns = []
urlpatterns = [
path("forms/", views.handle_forms, name="forms"),
]
55 changes: 54 additions & 1 deletion building_dialouge_webapp/heat/views.py
Original file line number Diff line number Diff line change
@@ -1 +1,54 @@
# Create your views here.
from django.http import HttpResponse
from django.shortcuts import render

from .forms import ElectricityConsumptionForm
from .forms import ElectricityGenerationForm
from .forms import ElectricityStorageForm
from .forms import HeatConsumptionForm
from .forms import HeatGenerationForm
from .forms import HeatGenerationForm2
from .forms import HeatStorageForm


def handle_forms(request):
"""
This view renders a list which contains all the forms for the app (GET)
or it gets all the responses from the submits and validates the forms (POST).

Parameters:
- request: HttpRequest object representing the client's request.

Returns:
- HttpResponse object containing the rendered template with the list
of form instances.
- HttpResponse object indicating successful form processing if all
forms are valid.
"""
form_classes = [
ElectricityConsumptionForm,
ElectricityGenerationForm,
ElectricityStorageForm,
HeatGenerationForm,
HeatGenerationForm2,
HeatConsumptionForm,
HeatStorageForm,
]

if request.method == "POST":
# Instantiate form instances with submitted data
form_instances = [f(request.POST) for f in form_classes]
all_valid = all(form.is_valid() for form in form_instances)

context = {"form_instances": form_instances}
if all_valid:
for form in form_instances:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, you could check if some are not valid first, and return view with forms back to user showing the errors in the form.

print(form.cleaned_data) # noqa: T201
# logic to handle form data
return HttpResponse("All forms are valid and have been processed.")

else:
context = {
"form_instances": [f() for f in form_classes],
}

return render(request, "pages/heat_forms.html", context)
3 changes: 3 additions & 0 deletions building_dialouge_webapp/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
<li class="nav-item">
<a class="nav-link" href="{% url 'about' %}">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'heat:forms' %}">Formulare</a>
</li>
{% if request.user.is_authenticated %}
<li class="nav-item">
<a class="nav-link"
Expand Down
14 changes: 14 additions & 0 deletions building_dialouge_webapp/templates/pages/heat_forms.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% extends "base.html" %}

{% block content %}
<form method="post" action="{% url 'heat:forms' %}">
{% csrf_token %}
{% for form in form_instances %}
<div class="mb-3">
{{ form.as_p }}
<hr />
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Save All</button>
</form>
{% endblock content %}
2 changes: 1 addition & 1 deletion requirements/local.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Werkzeug[watchdog]==3.0.2 # https://github.com/pallets/werkzeug
ipdb==0.13.13 # https://github.com/gotcha/ipdb
psycopg[c]==3.1.18 # https://github.com/psycopg/psycopg
psycopg2-binary==2.9.9 # https://github.com/psycopg/psycopg
watchfiles==0.21.0 # https://github.com/samuelcolvin/watchfiles

# Testing
Expand Down
2 changes: 1 addition & 1 deletion requirements/production.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
-r base.txt

gunicorn==22.0.0 # https://github.com/benoitc/gunicorn
psycopg[c]==3.1.18 # https://github.com/psycopg/psycopg
psycopg2-binary==2.9.9 # https://github.com/psycopg/psycopg
sentry-sdk==2.1.1 # https://github.com/getsentry/sentry-python

# Django
Expand Down
Loading