[LM] changed project structure

main
Lukas Martin 1 year ago
parent 870633c078
commit 5654ed40c1

@ -41,6 +41,8 @@ TEMPLATES = [
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'dataHandler.context_processors.plant_list',
], ],
}, },
}, },

@ -1,33 +1,28 @@
"""
URL configuration for ArduinoSensorServer project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.urls import path, include
from . import views
from django.contrib import admin from django.contrib import admin
from django.urls import path, include
from dataHandler import views
urlpatterns = [ urlpatterns = [
# Admin Site
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
# WebPages of root project, including plant/<int:plant_id> to access dynamic webpages of plants # Startseite (z.B. Überblick, Dashboard)
path("", views.home, name="home"), path('', views.startpage, name='startpage'),
path("plant/<int:plant_id>", views.plant_page, name="plant"),
# Detailansicht einzelner Pflanzen
path('plant/<int:plant_id>/', views.plant_page, name='plant_detail'),
# Pflanzenliste
path('plants/', views.plant_list, name='plant_list'),
# Neue Pflanze anlegen
path('plants/create/', views.plant_create, name='plant_create'),
# Sensor- und API-Daten
path('plants/', views.plant_list, name='plant_list'), # zeigt Liste direkt unter /plants/
path('plant/<int:plant_id>/', views.plant_page, name='plant_detail'), # Detailseite
path('plant/create/', views.plant_create, name='plant_create'), # Anlegen einer Pflanze
# includes all dataHandler urls after /data/ Example: data/1/ # Sensor- / Daten-Handling (unter /data/)
path('data/', include("dataHandler.urls")), path('data/', include('dataHandler.urls')),
] ]

@ -1,19 +1,7 @@
from django.shortcuts import render, redirect from django.contrib import admin
from dataHandler.models import BasicPlant from django.urls import path, include
from django.core.exceptions import ObjectDoesNotExist
urlpatterns = [
# Renders the request home, opens home.html and passes through all BasicPlants Objects path('admin/', admin.site.urls),
def home(request): path('', include('dataHandler.urls')), # übernimmt Startseite und alles weitere
plant = BasicPlant.objects.all() ]
return render(request, "home.html", {"plants": plant})
# Renders the request plant_page, plant_id is needed to open the corresponding website of the plant, if a plant_id
# which is unknown is given, return redirects to home. Uses plant.html and passes through one plant (plant_id)
def plant_page(request, plant_id):
try:
plant = BasicPlant.objects.get(id=plant_id)
return render(request, "plant.html", {"plant": plant})
except ObjectDoesNotExist:
return redirect("/")

@ -0,0 +1,6 @@
from .models import BasicPlant
def plant_list(request):
return {
"nav_plants": BasicPlant.objects.all()
}

@ -0,0 +1,7 @@
from django import forms
from .models import BasicPlant
class BasicPlantForm(forms.ModelForm):
class Meta:
model = BasicPlant
fields = ['name', 'plantGenus', 'plantSpecies']

@ -1,15 +1,22 @@
import datetime import datetime
from django.db import models from django.db import models
from django.db.models import PROTECT, CASCADE from django.db.models import CASCADE
# Create your models here. # Create your models here.
class BasicPlant(models.Model): class BasicPlant(models.Model):
id = models.AutoField(primary_key=True) id = models.AutoField(primary_key=True)
name = models.CharField(max_length=64, default="Pflanze") name = models.CharField(max_length=64, default="sensitive plant")
plantFamily = models.CharField(max_length=64, default="Fabaceae")
plantSubfamily = models.CharField(max_length=64, default="Caesalpinioideae")
plantGenus = models.CharField(max_length=64, default="Mimosa")
plantSpecies = models.CharField(max_length=64, default="pudica")
bought = models.DateTimeField(default=datetime.datetime.now()) bought = models.DateTimeField(default=datetime.datetime.now())
@property
def scientificname(self):
return f"{self.plantGenus} {self.plantSpecies}"
class Temperature(models.Model): class Temperature(models.Model):

@ -1,8 +1,12 @@
from django.shortcuts import redirect
from django.urls import path from django.urls import path
from . import views from . import views
urlpatterns = [ urlpatterns = [
path("", views.dataPage01, name="dataPage01"), path('', lambda request: redirect('/'), name='disable_data_root'),
# Testdaten
path("datapage/", views.dataPage01, name="dataPage01"),
path("1/", views.data_temp, name="data_temp"), path("1/", views.data_temp, name="data_temp"),
path("2/", views.data_moist, name="data_moist"), path("2/", views.data_moist, name="data_moist"),
path("3/", views.data_moist_temp, name="data_moist_temp"), path("3/", views.data_moist_temp, name="data_moist_temp"),

@ -1,40 +1,73 @@
from django.shortcuts import render, HttpResponse from django.core.exceptions import ObjectDoesNotExist
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from .forms import BasicPlantForm
from .models import BasicPlant, Temperature, Moisture from .models import BasicPlant, Temperature, Moisture
from django.shortcuts import redirect
# Temporary Test page to check moisture, temperature and plant data. # 🌱 Startseite zeigt z.B. allgemeine Infos oder Dashboard (noch leer)
def startpage(request):
return render(request, "startpage.html")
# 🌿 Pflanzenliste alle Pflanzen anzeigen
def plant_list(request):
plants = BasicPlant.objects.all()
return render(request, "plant_list.html", {"plants": plants})
# 🌱 Pflanze anlegen
def plant_create(request):
if request.method == 'POST':
form = BasicPlantForm(request.POST)
if form.is_valid():
plant = form.save()
return redirect('plant_detail', plant_id=plant.pk)
else:
form = BasicPlantForm()
return render(request, 'plant_create.html', {'form': form})
# 🌿 Pflanzendetailseite
def plant_page(request, plant_id):
try:
plant = BasicPlant.objects.get(id=plant_id)
return render(request, "plant.html", {"plant": plant})
except ObjectDoesNotExist:
return redirect("plant_list")
# 🌡️ Temporäre Test-Seite (z.B. für Sensor-Entwicklung)
def dataPage01(request): def dataPage01(request):
plant = BasicPlant.objects.get(id=1) plant = BasicPlant.objects.get(id=1)
temp = Temperature.objects.filter(plant_id=1).all() temps = Temperature.objects.filter(plant_id=1).all()
moist = Moisture.objects.filter(plant_id=1).all() moists = Moisture.objects.filter(plant_id=1).all()
return render(request, "dataPage.html", {"plant": plant, "temps": temp, "moists": moist}) return render(request, "dataPage.html", {"plant": plant, "temps": temps, "moists": moists})
# Post Only, handles temperature data send to data/1/, if accessed with GET, gets redirected to test data page # 📡 Temperatur-Daten-API
@csrf_exempt @csrf_exempt
def data_temp(request): def data_temp(request):
if request.method == "POST": if request.method == "POST":
p = BasicPlant.objects.get(id=request.POST["plant_id"]) p = BasicPlant.objects.get(id=request.POST["plant_id"])
Temperature.objects.create(temp=request.POST["temp"], plant_id=p) Temperature.objects.create(temp=request.POST["temp"], plant_id=p)
return HttpResponse("data received") return HttpResponse("data received")
else: return redirect("/data/")
return redirect("/data/")
# Post Only, handles moisture data send to data/2/, if accessed with GET, gets redirected to test data page # 📡 Feuchtigkeits-Daten-API
@csrf_exempt @csrf_exempt
def data_moist(request): def data_moist(request):
if request.method == "POST": if request.method == "POST":
p = BasicPlant.objects.get(id=request.POST["plant_id"]) p = BasicPlant.objects.get(id=request.POST["plant_id"])
Moisture.objects.create(moisture=request.POST["moist"], plant_id=p) Moisture.objects.create(moisture=request.POST["moist"], plant_id=p)
return HttpResponse("data received") return HttpResponse("data received")
else: return redirect("/data/")
return redirect("/data/")
# Post Only, handles moisture & temp data send to data/3/, if accessed with GET, gets redirected to test data page # 📡 Kombinierte Daten-API
@csrf_exempt @csrf_exempt
def data_moist_temp(request): def data_moist_temp(request):
if request.method == "POST": if request.method == "POST":
@ -42,5 +75,4 @@ def data_moist_temp(request):
Temperature.objects.create(temp=request.POST["temp"], plant_id=p) Temperature.objects.create(temp=request.POST["temp"], plant_id=p)
Moisture.objects.create(moisture=request.POST["moist"], plant_id=p) Moisture.objects.create(moisture=request.POST["moist"], plant_id=p)
return HttpResponse("data received") return HttpResponse("data received")
else: return redirect("/data/")
return redirect("/data/")

@ -1,3 +1,5 @@
asgiref==3.8.1 asgiref==3.8.1
Django==5.2 Django==5.2
sqlparse==0.5.3 sqlparse==0.5.3
requests~=2.32.4

@ -1,96 +1,45 @@
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <!DOCTYPE html>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script> <html lang="de">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <head>
{% load static %} <meta charset="UTF-8">
<link rel="stylesheet" href="{% static "css/base.css" %}"> <title>{% block title %}Meine Pflanzen{% endblock %}</title>
<!------ Include the above in your HEAD tag ---------->
<div class="navbar navbar-expand-md navbar-dark bg-dark mb-4" role="navigation"> <!-- Bootstrap & jQuery -->
<a class="navbar-brand" href="#">Bootstrap 4 NavBar</a> <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation"> <script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<span class="navbar-toggler-icon"></span>
</button> {% load static %}
<div class="collapse navbar-collapse" id="navbarCollapse"> <link rel="stylesheet" href="{% static 'css/base.css' %}">
<ul class="navbar-nav mr-auto"> </head>
<li class="nav-item active"> <body class="bg-light">
<a class="nav-link" href="{% url 'home'%}">Home <span class="sr-only">(current)</span></a>
</li> <!-- NAVIGATION -->
<li class="nav-item"> <nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4">
<a class="nav-link" href="https://github.com/Kaabp/" <a class="navbar-brand" href="{% url 'startpage' %}">🌱 PflanzenApp</a>
target="_blank">Github</a>
</li> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse"
<li class="nav-item"> aria-controls="navbarCollapse" aria-expanded="false" aria-label="Navigation ein-/ausblenden">
<a class="nav-link disabled" href="#">Disabled</a> <span class="navbar-toggler-icon"></span>
</li> </button>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" id="dropdown1" data-toggle="dropdown" aria-haspopup="true" <div class="collapse navbar-collapse" id="navbarCollapse">
aria-expanded="false">Dropdown1</a> <ul class="navbar-nav mr-auto">
<ul class="dropdown-menu" aria-labelledby="dropdown1"> <li class="nav-item">
<li class="dropdown-item" href="#"><a>Action 1</a></li> <a class="nav-link" href="{% url 'plant_list' %}">Pflanzen</a>
<li class="dropdown-item dropdown"> </li>
<a class="dropdown-toggle" id="dropdown1-1" data-toggle="dropdown" aria-haspopup="true" </ul>
aria-expanded="false">Dropdown1.1</a> </div>
<ul class="dropdown-menu" aria-labelledby="dropdown1-1"> </nav>
<li class="dropdown-item" href="#"><a>Action 1.1</a></li>
<li class="dropdown-item dropdown">
<a class="dropdown-toggle" id="dropdown1-1-1" data-toggle="dropdown" <!-- INHALTSBEREICH -->
aria-haspopup="true" aria-expanded="false">Dropdown1.1.1</a>
<ul class="dropdown-menu" aria-labelledby="dropdown1-1-1">
<li class="dropdown-item" href="#"><a>Action 1.1.1</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" id="dropdown2" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">Dropdown2</a>
<ul class="dropdown-menu" aria-labelledby="dropdown2">
<li class="dropdown-item" href="#"><a>Action 2 A</a></li>
<li class="dropdown-item" href="#"><a>Action 2 B</a></li>
<li class="dropdown-item" href="#"><a>Action 2 C</a></li>
<li class="dropdown-item dropdown">
<a class="dropdown-toggle" id="dropdown2-1" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">Dropdown2.1</a>
<ul class="dropdown-menu" aria-labelledby="dropdown2-1">
<li class="dropdown-item" href="#"><a>Action 2.1 A</a></li>
<li class="dropdown-item" href="#"><a>Action 2.1 B</a></li>
<li class="dropdown-item" href="#"><a>Action 2.1 C</a></li>
<li class="dropdown-item dropdown">
<a class="dropdown-toggle" id="dropdown2-1-1" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">Dropdown2.1.1</a>
<ul class="dropdown-menu" aria-labelledby="dropdown2-1-1">
<li class="dropdown-item" href="#"><a>Action 2.1.1 A</a></li>
<li class="dropdown-item" href="#"><a>Action 2.1.1 B</a></li>
<li class="dropdown-item" href="#"><a>Action 2.1.1 C</a></li>
</ul>
</li>
<li class="dropdown-item dropdown">
<a class="dropdown-toggle" id="dropdown2-1-2" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">Dropdown2.1.2</a>
<ul class="dropdown-menu" aria-labelledby="dropdown2-1-2">
<li class="dropdown-item" href="#"><a>Action 2.1.2 A</a></li>
<li class="dropdown-item" href="#"><a>Action 2.1.2 B</a></li>
<li class="dropdown-item" href="#"><a>Action 2.1.2 C</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<form class="form-inline mt-2 mt-md-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</div>
<body class="bg">
<main role="main" class="container"> <main role="main" class="container">
<div> <div class="card p-4 shadow-sm bg-white">
{% block content %} {% endblock %} {% block content %}
{% endblock %}
</div> </div>
</main> </main>
</body> </body>
</html>

@ -1,8 +0,0 @@
{% extends "base.html" %}
{% block content %}
{% for plant in plants %}
<li href="#">
<a href="{% url 'plant' plant.id %}">{{ plant.name }} </a>
</li>
{% endfor %}
{% endblock %}

@ -1,8 +1,13 @@
{% extends "base.html" %} {% extends "base.html" %}
<head>
<title>{% block title %}Meine Pflanzen{% endblock %}</title>
</head>
{% block content %} {% block content %}
<title>{{ plant.name }}</title>
<h4>{{ plant.name }}</h4> <h4>{{ plant.name }}</h4>
<h3>{{ plant.scientificname }}</h3>
<p>{{ plant.bought.date }}</p> <p>{{ plant.bought.date }}</p>
<br> <br>

@ -0,0 +1,72 @@
{% extends "base.html" %}
{% load static %}
{% block title %}Neue Pflanze anlegen{% endblock %}
{% block content %}
<h2>🌱 Neue Pflanze anlegen</h2>
<hr>
<form method="post">
{% csrf_token %}
<div class="form-row">
<div class="form-group col-md-6">
<label for="id_name">Trivialname</label>
{{ form.name }}
</div>
<div class="form-group col-md-3">
<label for="id_plantGenus">Gattung (Genus)</label>
{{ form.plantGenus }}
</div>
<div class="form-group col-md-3">
<label for="id_plantSpecies">Art (Species)</label>
{{ form.plantSpecies }}
</div>
</div>
<button type="button" id="fetch-trefle" class="btn btn-info mb-3">🔍 Daten von Trefle holen</button>
<div class="form-row">
<div class="form-group col-md-6">
<label for="id_plantFamily">Familie</label>
{{ form.plantFamily }}
</div>
<div class="form-group col-md-6">
<label for="id_plantSubfamily">Unterfamilie</label>
{{ form.plantSubfamily }}
</div>
</div>
<button type="submit" class="btn btn-success">💾 Speichern</button>
</form>
<script>
document.getElementById("fetch-trefle").addEventListener("click", function() {
const genus = document.getElementById("id_plantGenus").value;
const species = document.getElementById("id_plantSpecies").value;
if (!genus || !species) {
alert("Bitte Gattung und Art eingeben.");
return;
}
fetch(`/data/trefle-lookup/?genus=${genus}&species=${species}`)
.then(response => response.json())
.then(data => {
if (data.family) {
document.getElementById("id_plantFamily").value = data.family;
}
if (data.subfamily) {
document.getElementById("id_plantSubfamily").value = data.subfamily;
}
if (data.error) {
alert("Fehler: " + data.error);
}
})
.catch(error => {
alert("Fehler beim Abrufen der Daten.");
console.error(error);
});
});
</script>
{% endblock %}

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% block content %}
{% for plant in plants %}
<li href="#">
<a href="{% url 'plant_detail' plant.id %}">{{ plant.name }}</a>
</li>
<a href="{% url 'plant_create' %}" class="btn btn-success rounded-circle"
style="position: fixed; bottom: 20px; right: 20px; width: 60px; height: 60px; font-size: 30px; text-align: center;">
+
</a>
{% endfor %}
{% endblock %}

@ -0,0 +1,5 @@
{% extends "base.html" %}
{% block content %}
<h1>Willkommen bei deiner Pflanzenverwaltung!</h1>
<p>Nutze das Menü oben, um deine Pflanzen zu verwalten.</p>
{% endblock %}
Loading…
Cancel
Save