mirror of
https://github.com/HS-Flensburg-Klein/hausarbeit-hikmat_galan_neumann_stark_becker
synced 2025-04-04 21:43:31 +00:00
Merge 4b07f346a0
into d0c02ad76e
This commit is contained in:
commit
05337f6d45
39
.drone.yml
Normal file
39
.drone.yml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: build
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: docker
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
registry: docker.cybre.town
|
||||||
|
repo: docker.cybre.town/adb/webprog-homework
|
||||||
|
tags: "latest"
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: deploy
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- build
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: pull and deploy
|
||||||
|
image: appleboy/drone-ssh:linux-amd64
|
||||||
|
settings:
|
||||||
|
host:
|
||||||
|
from_secret: ssh_host
|
||||||
|
username:
|
||||||
|
from_secret: ssh_user_name
|
||||||
|
key:
|
||||||
|
from_secret: ssh_private_key
|
||||||
|
script: |
|
||||||
|
cd /media/docker/webprog-homework
|
||||||
|
docker compose -f docker-compose.prod.yml -p webprog-homework pull -q
|
||||||
|
docker compose -f docker-compose.prod.yml -p webprog-homework up -d
|
10
Dockerfile
Normal file
10
Dockerfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
FROM python:3-alpine
|
||||||
|
|
||||||
|
COPY ./ /usr/src/app
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
RUN pip install -r requirements.txt
|
||||||
|
RUN python ./manage.py migrate
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
CMD [ "python", "./manage.py", "runserver", "0.0.0.0:8000" ]
|
20
docker-compose.prod.yml
Normal file
20
docker-compose.prod.yml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
networks:
|
||||||
|
web:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
image: docker.cybre.town/adb/webprog-homework
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.webprog-homework.rule=Host(`webprog-homework.deploy.cat`)"
|
||||||
|
- "traefik.http.routers.webprog-homework.entrypoints=https"
|
||||||
|
- "traefik.http.services.webprog-homework.loadbalancer.server.port=8000"
|
||||||
|
- "traefik.http.routers.webprog-homework.tls.certresolver=mytlschallenge"
|
||||||
|
- "traefik.docker.network=web"
|
||||||
|
volumes:
|
||||||
|
- ./db.sqlite:/usr/src/app/db.sqlite
|
||||||
|
networks:
|
||||||
|
- web
|
22
manage.py
Normal file
22
manage.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""Django's command-line utility for administrative tasks."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run administrative tasks."""
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'webprog.settings')
|
||||||
|
try:
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
except ImportError as exc:
|
||||||
|
raise ImportError(
|
||||||
|
"Couldn't import Django. Are you sure it's installed and "
|
||||||
|
"available on your PYTHONPATH environment variable? Did you "
|
||||||
|
"forget to activate a virtual environment?"
|
||||||
|
) from exc
|
||||||
|
execute_from_command_line(sys.argv)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
0
mensaviewer/__init__.py
Normal file
0
mensaviewer/__init__.py
Normal file
23
mensaviewer/admin.py
Normal file
23
mensaviewer/admin.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from .models import *
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Menu)
|
||||||
|
class MenuAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Comment)
|
||||||
|
class CommentAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Location)
|
||||||
|
class LocationAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(NewsArticle)
|
||||||
|
class NewsArticleAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
6
mensaviewer/apps.py
Normal file
6
mensaviewer/apps.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class MensaviewerConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'mensaviewer'
|
46
mensaviewer/data.py
Normal file
46
mensaviewer/data.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
STATUS_VALUES = ['Student', 'Employee', 'Guest']
|
||||||
|
ALLERGENS = {
|
||||||
|
'Ei': 'Ei',
|
||||||
|
'En': 'Erdnüsse',
|
||||||
|
'Fi': 'Fisch',
|
||||||
|
'Gl': 'Glutenhaltiges Getreide',
|
||||||
|
'GlD': 'Dinkel',
|
||||||
|
'GlG': 'Gerste',
|
||||||
|
'GlH': 'Hafer',
|
||||||
|
'GlR': 'Roggen',
|
||||||
|
'GlW': 'Weizen',
|
||||||
|
'Kr': 'Krebstiere',
|
||||||
|
'Lac': 'Laktose',
|
||||||
|
'Lu': 'Lupinen',
|
||||||
|
'Mi': 'Milch',
|
||||||
|
'Sc': 'Schalenfrüchte',
|
||||||
|
'ScC': 'Cashews',
|
||||||
|
'ScH': 'Haselnüsse',
|
||||||
|
'ScM': 'Mandeln',
|
||||||
|
'ScP': 'Pistazien',
|
||||||
|
'ScW': 'Walnüsse',
|
||||||
|
'Se': 'Sesam',
|
||||||
|
'Sf': 'Senf',
|
||||||
|
'Sl': 'Sellerie',
|
||||||
|
'So': 'Soja',
|
||||||
|
'Sw': 'Schwefeldioxid / Sulphite',
|
||||||
|
'Wt': 'Weichtiere',
|
||||||
|
}
|
||||||
|
TYPES = {
|
||||||
|
'vn': 'Vegan',
|
||||||
|
've': 'Vegetarisch',
|
||||||
|
'BIO': 'Bio',
|
||||||
|
'IN': 'International',
|
||||||
|
'MV': 'MensaVital',
|
||||||
|
'S': 'Schwein',
|
||||||
|
'R': 'Rind',
|
||||||
|
'G': 'Geflügel',
|
||||||
|
'L': 'Lamm',
|
||||||
|
'AGS': 'Artgerechtes Schwein',
|
||||||
|
'AGR': 'Artgerechtes Rind',
|
||||||
|
'AGG': 'Artgerechtes Geflügel',
|
||||||
|
'AGL': 'Artgerechtes Lamm',
|
||||||
|
}
|
||||||
|
ALLERGENS_CHOICES = ((key, ALLERGENS[key]) for key in ALLERGENS)
|
||||||
|
TYPES_CHOICES = ((key, TYPES[key]) for key in TYPES)
|
||||||
|
ART_CHOICES = (('Mensa', 'Mensa'), ('Cafeteria', 'Cafeteria'))
|
15
mensaviewer/forms.py
Normal file
15
mensaviewer/forms.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from django import forms
|
||||||
|
|
||||||
|
from .models import *
|
||||||
|
from .data import TYPES_CHOICES, ALLERGENS_CHOICES
|
||||||
|
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
|
||||||
|
class MenuForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Menu
|
||||||
|
fields = ['location', 'art', 'name', 'price', 'allergens', 'types', 'day']
|
||||||
|
widgets = {
|
||||||
|
'day': forms.DateInput(attrs={'type': 'date'}),
|
||||||
|
}
|
84
mensaviewer/helpers.py
Normal file
84
mensaviewer/helpers.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.utils.dateparse import parse_date
|
||||||
|
|
||||||
|
from .models import *
|
||||||
|
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
example_json = [
|
||||||
|
{"day": "2022-12-19", "menus": [{"art": "Mensa", "name": "Spaghetti Carbonara", "price": "2,35 € / 4,15 € / 4,85 €", "allergens": ["GlW", "Mi"], "types": ["S", "IN"]}, {"art": "Mensa", "name": "Currywurst VEGAN Hot Pot(t) Karamellisierte Balsamico Zwiebeln Kartoffelspalten", "price": "4,05 € / 5,85 € / 6,55 €", "allergens": ["Sf", "Sl", "So", "Sw"], "types": ["ve", "vn"]}, {"art": "Mensa", "name": "Schupfnudeln, Schmorgemüse, Sojasoße", "price": "3,95 € / 5,75 € / 6,45 €", "allergens": ["GlW", "Se", "So"], "types": ["ve", "vn"]}, {"art": "Cafeteria", "name": "Currywurst Pommes Frites", "price": "4,70 € / 4,70 € / 4,70 €", "allergens": ["Sf"], "types": ["AGS"]}, {"art": "Cafeteria", "name": "Hähnchenschnitzel, Knuspermantel", "price": "2,95 € / 2,95 € / 2,95 €", "allergens": ["GlW", "GlG"], "types": ["G"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Erbsen, Karotten, Gouda", "price": "3,60 € / 3,60 € / 3,60 €", "allergens": ["Ei", "Mi"], "types": ["ve"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Hähnchenbruststreifen, Gouda", "price": "3,95 € / 3,95 € / 3,95 €", "allergens": ["Ei", "Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Ofenkartoffel mit Sour Creme [Bio]", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Mi"], "types": ["ve", "BIO"]}, {"art": "Cafeteria", "name": "OfenkartoffelTomaten- Zwiebel- Marmelade", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Sf", "Sw"], "types": ["ve", "vn"]}, {"art": "Cafeteria", "name": "Ofenkartoffel Hähnchenstreifen", "price": "3,80 € / 3,80 € / 3,80 €", "allergens": ["Mi"], "types": ["G"]}]},
|
||||||
|
{"day": "2022-12-20", "menus": [{"art": "Mensa", "name": "Linseneintopf Baguettebrot", "price": "2,35 € / 4,15 € / 4,85 €", "allergens": ["Sl", "Sw", "GlW"], "types": ["ve", "vn"]}, {"art": "Mensa", "name": "Phat Krapao Würzige Thai Soja Bolognese, Ingwer, Basilikum, Koriander, Limettenblätter, Mienudeln", "price": "2,80 € / 4,60 € / 5,30 €", "allergens": ["GlW", "GlG", "So"], "types": ["IN", "ve", "vn"]}, {"art": "Mensa", "name": "Bockwurst zum Eintopf", "price": "1,00 € / 1,10 € / 1,20 €", "allergens": [], "types": ["S"]}, {"art": "Mensa", "name": "Filipino Beef Caldereta Basmatireis", "price": "3,50 € / 5,30 € / 6,00 €", "allergens": ["Fi", "GlW", "Mi", "Sf", "So"], "types": ["G", "R", "IN"]}, {"art": "Cafeteria", "name": "Hähnchenschnitzel, Knuspermantel", "price": "2,95 € / 2,95 € / 2,95 €", "allergens": ["GlW", "GlG"], "types": ["G"]}, {"art": "Cafeteria", "name": "Currywurst Pommes Frites", "price": "4,70 € / 4,70 € / 4,70 €", "allergens": ["Sf"], "types": ["AGS"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Hähnchenbruststreifen, Gouda", "price": "3,95 € / 3,95 € / 3,95 €", "allergens": ["Ei", "Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Erbsen, Karotten, Gouda", "price": "3,60 € / 3,60 € / 3,60 €", "allergens": ["Ei", "Mi"], "types": ["ve"]}, {"art": "Cafeteria", "name": "OfenkartoffelTomaten- Zwiebel- Marmelade", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Sf", "Sw"], "types": ["ve", "vn"]}, {"art": "Cafeteria", "name": "Ofenkartoffel mit Sour Creme [Bio]", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Mi"], "types": ["ve", "BIO"]}, {"art": "Cafeteria", "name": "Ofenkartoffel Hähnchenstreifen", "price": "3,80 € / 3,80 € / 3,80 €", "allergens": ["Mi"], "types": ["G"]}]},
|
||||||
|
{"day": "2022-12-21", "menus": [{"art": "Mensa", "name": "Currywurst Hot Pot(t) Kartoffelspalten", "price": "3,90 € / 5,70 € / 6,40 €", "allergens": ["Sf", "Sl", "GlW"], "types": ["AGS"]}, {"art": "Mensa", "name": "Pasta, Kürbis- Ricotta- Soße, Walnüsse", "price": "2,35 € / 4,15 € / 4,85 €", "allergens": ["GlW", "Mi", "NW"], "types": ["ve"]}, {"art": "Mensa", "name": "Rindfleischcurry, Kokos, Karotten, Koriander Basmatireis", "price": "4,10 € / 5,90 € / 6,60 €", "allergens": ["GlW", "Mi", "Sf", "So"], "types": ["R"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Erbsen, Karotten, Gouda", "price": "3,60 € / 3,60 € / 3,60 €", "allergens": ["Ei", "Mi"], "types": ["ve"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Hähnchenbruststreifen, Gouda", "price": "3,95 € / 3,95 € / 3,95 €", "allergens": ["Ei", "Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Ofenkartoffel Hähnchenstreifen", "price": "3,80 € / 3,80 € / 3,80 €", "allergens": ["Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Ofenkartoffel mit Sour Creme [Bio]", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Mi"], "types": ["ve", "BIO"]}, {"art": "Cafeteria", "name": "OfenkartoffelTomaten- Zwiebel- Marmelade", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Sf", "Sw"], "types": ["ve", "vn"]}]},
|
||||||
|
{"day": "2022-12-22", "menus": [{"art": "Mensa", "name": "Spaghetti Carbonara", "price": "2,35 € / 4,15 € / 4,85 €", "allergens": ["Ei", "GlW", "Mi"], "types": ["S", "IN"]}, {"art": "Mensa", "name": "Tortellini, Kicherbsen, Spitzkohl, Cashewkerne und Rosmarin", "price": "3,50 € / 5,30 € / 6,00 €", "allergens": ["GlW", "NC"], "types": ["ve", "vn"]}, {"art": "Mensa", "name": "Bockwurst zum Eintopf", "price": "", "allergens": [], "types": ["S"]}, {"art": "Mensa", "name": "Vegetarisches Schnitzel, mediterran gefüllt Kartoffelpüree Gurkensalat", "price": "3,65 € / 5,45 € / 6,15 €", "allergens": ["Ei", "GlW", "GlH", "Mi"], "types": ["ve"]}, {"art": "Mensa", "name": "Linseneintopf", "price": "2,00 € / 3,80 € / 4,50 €", "allergens": ["Sl", "Sw"], "types": ["ve", "vn"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Hähnchenbruststreifen, Gouda", "price": "3,95 € / 3,95 € / 3,95 €", "allergens": ["Ei", "Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Erbsen, Karotten, Gouda", "price": "3,60 € / 3,60 € / 3,60 €", "allergens": ["Ei", "Mi"], "types": ["ve"]}, {"art": "Cafeteria", "name": "Ofenkartoffel mit Sour Creme [Bio]", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Mi"], "types": ["ve", "BIO"]}, {"art": "Cafeteria", "name": "Ofenkartoffel Hähnchenstreifen", "price": "3,80 € / 3,80 € / 3,80 €", "allergens": ["Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "OfenkartoffelTomaten- Zwiebel- Marmelade", "price": "", "allergens": ["Sf", "Sw"], "types": ["ve", "vn"]}]},
|
||||||
|
{"day": "2022-12-23", "menus": [{"art": "Mensa", "name": "Spaghetti Carbonara", "price": "2,35 € / 4,15 € / 4,85 €", "allergens": ["Ei", "GlW", "Mi"], "types": ["S", "IN"]}, {"art": "Mensa", "name": "Tortellini, Kicherbsen, Spitzkohl, Cashewkerne und Rosmarin", "price": "3,50 € / 5,30 € / 6,00 €", "allergens": ["GlW", "NC"], "types": ["ve", "vn"]}, {"art": "Mensa", "name": "Bockwurst zum Eintopf", "price": "", "allergens": [], "types": ["S"]}, {"art": "Mensa", "name": "Vegetarisches Schnitzel, mediterran gefüllt Kartoffelpüree Gurkensalat", "price": "3,65 € / 5,45 € / 6,15 €", "allergens": ["Ei", "GlW", "GlH", "Mi"], "types": ["ve"]}, {"art": "Mensa", "name": "Linseneintopf", "price": "2,00 € / 3,80 € / 4,50 €", "allergens": ["Sl", "Sw"], "types": ["ve", "vn"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Hähnchenbruststreifen, Gouda", "price": "3,95 € / 3,95 € / 3,95 €", "allergens": ["Ei", "Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Erbsen, Karotten, Gouda", "price": "3,60 € / 3,60 € / 3,60 €", "allergens": ["Ei", "Mi"], "types": ["ve"]}, {"art": "Cafeteria", "name": "Ofenkartoffel mit Sour Creme [Bio]", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Mi"], "types": ["ve", "BIO"]}, {"art": "Cafeteria", "name": "Ofenkartoffel Hähnchenstreifen", "price": "3,80 € / 3,80 € / 3,80 €", "allergens": ["Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "OfenkartoffelTomaten- Zwiebel- Marmelade", "price": "", "allergens": ["Sf", "Sw"], "types": ["ve", "vn"]}]}]
|
||||||
|
|
||||||
|
|
||||||
|
def load_data(locations, checked_types, status):
|
||||||
|
current_week = datetime.date.today().isocalendar().week
|
||||||
|
for location in locations:
|
||||||
|
menus = Menu.objects.filter(day__week=current_week, location=location)
|
||||||
|
if not menus.exists():
|
||||||
|
fetched_data = fetch(location.mensa_id)
|
||||||
|
store(fetched_data, location)
|
||||||
|
data = formatted_menu_data(locations, checked_types, status)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def formatted_menu_data(locations, checked_types, status):
|
||||||
|
current_week = datetime.date.today().isocalendar().week
|
||||||
|
today = datetime.date.today()
|
||||||
|
days = [today + datetime.timedelta(days=i)
|
||||||
|
for i in range(0 - today.weekday(), 5 - today.weekday())]
|
||||||
|
|
||||||
|
formatted_data = {}
|
||||||
|
for day in days:
|
||||||
|
if day not in formatted_data:
|
||||||
|
formatted_data[day] = []
|
||||||
|
for location in locations:
|
||||||
|
menus = Menu.objects.filter(location=location, day=day)
|
||||||
|
for menu in menus:
|
||||||
|
# AND or OR filter ???
|
||||||
|
if set(checked_types).issubset(set(menu.types)): # <-- AND
|
||||||
|
formatted_data[day].append({
|
||||||
|
'art': menu.art,
|
||||||
|
'name': menu.name,
|
||||||
|
'price': menu.price if status is None
|
||||||
|
else menu.get_price[status],
|
||||||
|
'allergens': menu.get_allergens,
|
||||||
|
'types': menu.get_types,
|
||||||
|
'likes': menu.likes,
|
||||||
|
'location': location,
|
||||||
|
'pk': menu.pk,
|
||||||
|
})
|
||||||
|
return formatted_data
|
||||||
|
|
||||||
|
|
||||||
|
def store(data, location):
|
||||||
|
for day_json in data:
|
||||||
|
date_string = day_json['day']
|
||||||
|
menus_json = day_json['menus']
|
||||||
|
day = parse_date(date_string)
|
||||||
|
for menu_json in menus_json:
|
||||||
|
art = menu_json['art']
|
||||||
|
name = menu_json['name']
|
||||||
|
price = menu_json['price'] or "0,00 € / 0,00 € / 0,00 €"
|
||||||
|
allergens = menu_json['allergens']
|
||||||
|
types = menu_json['types']
|
||||||
|
menu_exists = Menu.objects.filter(art=art, name=name, price=price,
|
||||||
|
allergens=allergens, types=types,
|
||||||
|
day=day).exists()
|
||||||
|
if not menu_exists:
|
||||||
|
Menu(art=art, name=name, price=price, allergens=allergens,
|
||||||
|
types=types, day=day, location=location).save()
|
||||||
|
|
||||||
|
|
||||||
|
def fetch(mensa_id: int):
|
||||||
|
res = requests.get('https://mensa.fly.dev/' + str(mensa_id))
|
||||||
|
if res.status_code != 200:
|
||||||
|
raise Exception('request failed')
|
||||||
|
return res.json()
|
48
mensaviewer/migrations/0001_initial.py
Normal file
48
mensaviewer/migrations/0001_initial.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2022-12-25 15:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Menu',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('mensa_id', models.IntegerField()),
|
||||||
|
('date', models.CharField(max_length=10)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Meal',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=144)),
|
||||||
|
('type', models.CharField(max_length=144)),
|
||||||
|
('allergens', models.CharField(max_length=144)),
|
||||||
|
('tags', models.CharField(max_length=144)),
|
||||||
|
('likes', models.IntegerField(default=0)),
|
||||||
|
('dislikes', models.IntegerField(default=0)),
|
||||||
|
('price_student', models.FloatField(max_length=8)),
|
||||||
|
('price_employee', models.FloatField(max_length=8)),
|
||||||
|
('price_guest', models.FloatField(max_length=8)),
|
||||||
|
('related_menus', models.ManyToManyField(to='mensaviewer.menu')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Comment',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('username', models.CharField(default='anon', max_length=144)),
|
||||||
|
('comment', models.CharField(max_length=720)),
|
||||||
|
('related_meal', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.meal')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
18
mensaviewer/migrations/0002_alter_menu_date.py
Normal file
18
mensaviewer/migrations/0002_alter_menu_date.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2022-12-26 15:17
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='date',
|
||||||
|
field=models.DateField(),
|
||||||
|
),
|
||||||
|
]
|
18
mensaviewer/migrations/0003_alter_menu_date.py
Normal file
18
mensaviewer/migrations/0003_alter_menu_date.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2022-12-26 15:56
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0002_alter_menu_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='date',
|
||||||
|
field=models.DateField(max_length=10),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,88 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2022-12-26 16:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0003_alter_menu_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Day',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('mensa_id', models.IntegerField()),
|
||||||
|
('date', models.DateField(max_length=10)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='date',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='mensa_id',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='allergens',
|
||||||
|
field=models.CharField(blank=True, max_length=144, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='dislikes',
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='likes',
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(blank=True, max_length=144, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='price_employee',
|
||||||
|
field=models.FloatField(default=0, max_length=8),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='price_guest',
|
||||||
|
field=models.FloatField(default=0, max_length=8),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='price_student',
|
||||||
|
field=models.FloatField(default=0, max_length=8),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='tags',
|
||||||
|
field=models.CharField(blank=True, max_length=144, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='type',
|
||||||
|
field=models.CharField(blank=True, max_length=144, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='comment',
|
||||||
|
name='related_meal',
|
||||||
|
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.menu'),
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Meal',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='related_menus',
|
||||||
|
field=models.ManyToManyField(to='mensaviewer.day'),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2022-12-26 21:04
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0004_day_remove_menu_date_remove_menu_mensa_id_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='menu',
|
||||||
|
old_name='related_menus',
|
||||||
|
new_name='related_days',
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,50 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2022-12-27 00:11
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0005_rename_related_menus_menu_related_days'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Allergen',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('allergen', models.CharField(blank=True, max_length=16, null=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Tag',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('tag', models.CharField(blank=True, max_length=16, null=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='allergens',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='tags',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='related_days',
|
||||||
|
field=models.ManyToManyField(related_name='menus', to='mensaviewer.day'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='related_allergens',
|
||||||
|
field=models.ManyToManyField(related_name='menus', to='mensaviewer.allergen'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='related_tags',
|
||||||
|
field=models.ManyToManyField(related_name='menus', to='mensaviewer.tag'),
|
||||||
|
),
|
||||||
|
]
|
23
mensaviewer/migrations/0007_allergen_name_tag_name.py
Normal file
23
mensaviewer/migrations/0007_allergen_name_tag_name.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-02 02:36
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0006_allergen_tag_remove_menu_allergens_remove_menu_tags_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='allergen',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(blank=True, max_length=144, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='tag',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(blank=True, max_length=144, null=True),
|
||||||
|
),
|
||||||
|
]
|
27
mensaviewer/migrations/0008_rename_tag_type_and_more.py
Normal file
27
mensaviewer/migrations/0008_rename_tag_type_and_more.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-02 17:22
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0007_allergen_name_tag_name'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameModel(
|
||||||
|
old_name='Tag',
|
||||||
|
new_name='Type',
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='menu',
|
||||||
|
old_name='related_tags',
|
||||||
|
new_name='related_types',
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='type',
|
||||||
|
old_name='tag',
|
||||||
|
new_name='type',
|
||||||
|
),
|
||||||
|
]
|
18
mensaviewer/migrations/0009_rename_type_menu_art.py
Normal file
18
mensaviewer/migrations/0009_rename_type_menu_art.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-03 02:20
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0008_rename_tag_type_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='menu',
|
||||||
|
old_name='type',
|
||||||
|
new_name='art',
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,37 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-03 23:21
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0009_rename_type_menu_art'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='related_days',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='day',
|
||||||
|
name='menus',
|
||||||
|
field=models.ManyToManyField(related_name='day', to='mensaviewer.menu'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='day',
|
||||||
|
name='date',
|
||||||
|
field=models.DateField(max_length=64),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='related_allergens',
|
||||||
|
field=models.ManyToManyField(related_name='menu', to='mensaviewer.allergen'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='related_types',
|
||||||
|
field=models.ManyToManyField(related_name='menu', to='mensaviewer.type'),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-04 03:34
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0010_remove_menu_related_days_day_menus_alter_day_date_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='comment',
|
||||||
|
old_name='related_meal',
|
||||||
|
new_name='related_menu',
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,84 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-04 16:57
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0011_rename_related_meal_comment_related_menu'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Location',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(blank=True, max_length=144, null=True)),
|
||||||
|
('mensa_id', models.CharField(blank=True, max_length=2, null=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='day',
|
||||||
|
name='menus',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='dislikes',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='price_employee',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='price_guest',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='price_student',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='related_allergens',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='related_types',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='allergens',
|
||||||
|
field=models.JSONField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='day',
|
||||||
|
field=models.DateField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='types',
|
||||||
|
field=models.JSONField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='comment',
|
||||||
|
name='related_menu',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.menu'),
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Allergen',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Day',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Type',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='location',
|
||||||
|
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.location'),
|
||||||
|
),
|
||||||
|
]
|
18
mensaviewer/migrations/0013_menu_price.py
Normal file
18
mensaviewer/migrations/0013_menu_price.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-04 22:25
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0012_location_remove_day_menus_remove_menu_dislikes_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='price',
|
||||||
|
field=models.CharField(blank=True, max_length=144, null=True),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,38 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-04 23:47
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0013_menu_price'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Day',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('date', models.DateField(blank=True, null=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='day',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='location',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='locations',
|
||||||
|
field=models.ManyToManyField(to='mensaviewer.location'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='days',
|
||||||
|
field=models.ManyToManyField(to='mensaviewer.day'),
|
||||||
|
),
|
||||||
|
]
|
19
mensaviewer/migrations/0015_comment_timestamp.py
Normal file
19
mensaviewer/migrations/0015_comment_timestamp.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-05 00:43
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0014_day_remove_menu_day_remove_menu_location_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='comment',
|
||||||
|
name='timestamp',
|
||||||
|
field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,25 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-06 00:06
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0015_comment_timestamp'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='days',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Day',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='days',
|
||||||
|
field=models.JSONField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,37 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-06 22:11
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0016_remove_menu_days_delete_day_menu_days'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='days',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='menu',
|
||||||
|
name='locations',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='location',
|
||||||
|
name='city',
|
||||||
|
field=models.CharField(blank=True, max_length=144, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='day',
|
||||||
|
field=models.DateField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='menu',
|
||||||
|
name='location',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.location'),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,42 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-06 22:32
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0017_remove_menu_days_remove_menu_locations_location_city_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='comment',
|
||||||
|
old_name='username',
|
||||||
|
new_name='author',
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='comment',
|
||||||
|
old_name='related_menu',
|
||||||
|
new_name='menu',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='comment',
|
||||||
|
name='comment',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='comment',
|
||||||
|
name='text',
|
||||||
|
field=models.CharField(blank=True, max_length=512, null=True),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='NewsArticle',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('author', models.CharField(default='anon', max_length=144)),
|
||||||
|
('text', models.CharField(blank=True, max_length=8192, null=True)),
|
||||||
|
('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.location')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-06 22:39
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0018_rename_username_comment_author_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='comment',
|
||||||
|
name='text',
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='newsarticle',
|
||||||
|
name='text',
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
19
mensaviewer/migrations/0020_newsarticle_timestamp.py
Normal file
19
mensaviewer/migrations/0020_newsarticle_timestamp.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-08 01:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0019_alter_comment_text_alter_newsarticle_text'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='newsarticle',
|
||||||
|
name='timestamp',
|
||||||
|
field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
|
||||||
|
),
|
||||||
|
]
|
18
mensaviewer/migrations/0021_newsarticle_title.py
Normal file
18
mensaviewer/migrations/0021_newsarticle_title.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-08 02:10
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0020_newsarticle_timestamp'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='newsarticle',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(blank=True, max_length=144),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,38 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-08 03:00
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0021_newsarticle_title'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='allergens',
|
||||||
|
field=models.JSONField(blank=True, default=[]),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='art',
|
||||||
|
field=models.CharField(choices=[('M', 'Mensa'), ('C', 'Cafeteria')], default='M', max_length=1),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(blank=True, default='', max_length=144),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='price',
|
||||||
|
field=models.CharField(blank=True, default='', max_length=144),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='types',
|
||||||
|
field=models.JSONField(blank=True, default=[]),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,38 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2023-01-08 18:03
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mensaviewer', '0022_alter_menu_allergens_alter_menu_art_alter_menu_name_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='allergens',
|
||||||
|
field=models.JSONField(blank=True, default=list),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='art',
|
||||||
|
field=models.CharField(choices=[('Mensa', 'Mensa'), ('Cafeteria', 'Cafeteria')], default='M', max_length=24),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(blank=True, default='---', max_length=144),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='price',
|
||||||
|
field=models.CharField(blank=True, default='---', max_length=144),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='menu',
|
||||||
|
name='types',
|
||||||
|
field=models.JSONField(blank=True, default=list),
|
||||||
|
),
|
||||||
|
]
|
0
mensaviewer/migrations/__init__.py
Normal file
0
mensaviewer/migrations/__init__.py
Normal file
84
mensaviewer/models.py
Normal file
84
mensaviewer/models.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.utils.timezone import now
|
||||||
|
|
||||||
|
from .data import TYPES, ART_CHOICES
|
||||||
|
|
||||||
|
|
||||||
|
class Location(models.Model):
|
||||||
|
city = models.CharField(max_length=144, null=True, blank=True)
|
||||||
|
name = models.CharField(max_length=144, null=True, blank=True)
|
||||||
|
mensa_id = models.CharField(max_length=2, null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.city} - {self.name}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def menus(self):
|
||||||
|
return [menu for menu in Menu.objects.filter(location=self)]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def news_articles(self):
|
||||||
|
return [news_article for news_article in NewsArticle.objects.filter(location=self)]
|
||||||
|
|
||||||
|
|
||||||
|
class Menu(models.Model):
|
||||||
|
art = models.CharField(max_length=24, choices=ART_CHOICES, default='M')
|
||||||
|
name = models.CharField(max_length=144, default='---', blank=True)
|
||||||
|
price = models.CharField(max_length=144, default='---', blank=True)
|
||||||
|
allergens = models.JSONField(default=list, blank=True)
|
||||||
|
types = models.JSONField(default=list, blank=True)
|
||||||
|
day = models.DateField(null=True, blank=True)
|
||||||
|
likes = models.IntegerField(default=0)
|
||||||
|
location = models.ForeignKey(Location, on_delete=models.CASCADE, null=True,
|
||||||
|
blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} - {self.location} | {self.day}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_price(self):
|
||||||
|
try:
|
||||||
|
return {
|
||||||
|
'Student': self.price.split(' / ')[0],
|
||||||
|
'Employee': self.price.split(' / ')[1],
|
||||||
|
'Guest': self.price.split(' / ')[2],
|
||||||
|
}
|
||||||
|
except IndexError:
|
||||||
|
return {
|
||||||
|
'Student': "0,00 €",
|
||||||
|
'Employee': "0,00 €",
|
||||||
|
'Guest': "0,00 €",
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_types(self):
|
||||||
|
return ', '.join([TYPES[type] for type in self.types])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_allergens(self):
|
||||||
|
return ', '.join([allergen for allergen in self.allergens])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def comments(self):
|
||||||
|
return [comment for comment in Comment.objects.filter(menu=self)]
|
||||||
|
|
||||||
|
|
||||||
|
class Comment(models.Model):
|
||||||
|
menu = models.ForeignKey(Menu, on_delete=models.CASCADE)
|
||||||
|
timestamp = models.DateTimeField(default=now, blank=True)
|
||||||
|
author = models.CharField(max_length=144, default='anon')
|
||||||
|
text = models.TextField(null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.menu} - {self.author} | {self.timestamp}"
|
||||||
|
|
||||||
|
|
||||||
|
class NewsArticle(models.Model):
|
||||||
|
location = models.ForeignKey(Location, on_delete=models.CASCADE)
|
||||||
|
timestamp = models.DateTimeField(default=now, blank=True)
|
||||||
|
author = models.CharField(max_length=144, default='anon')
|
||||||
|
title = models.CharField(max_length=144, blank=True)
|
||||||
|
text = models.TextField(null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.title} | {self.title} - {self.author} | {self.timestamp}"
|
32
mensaviewer/templates/base.html
Normal file
32
mensaviewer/templates/base.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{% load static %}
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link rel="stylesheet" href="{% static 'base.css' %}">
|
||||||
|
<title>Mensaviewer | {% block title %}Home{% endblock %}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
{% block header %}<h1>Header Title</h1>{% endblock %}
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<nav>
|
||||||
|
<a href="{% url 'mensaviewer:flensburg' %}">Flensburg</a>
|
||||||
|
<a href="{% url 'mensaviewer:custom' %}">Custom</a>
|
||||||
|
<hr>
|
||||||
|
<a href="{% url 'mensaviewer:location_list' %}">Locations</a>
|
||||||
|
<a href="{% url 'mensaviewer:news_list' %}">News Articles</a>
|
||||||
|
<a href="{% url 'mensaviewer:menu_list' %}">Menus</a>
|
||||||
|
<a href="{% url 'mensaviewer:comment_list' %}">Comments</a>
|
||||||
|
<hr>
|
||||||
|
<a href="/admin">Admin</a>
|
||||||
|
</nav>
|
||||||
|
<div class="content">
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
10
mensaviewer/templates/comment.html
Normal file
10
mensaviewer/templates/comment.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Comment">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
17
mensaviewer/templates/comment/delete.html
Normal file
17
mensaviewer/templates/comment/delete.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Delete Comment{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Delete comment by {{ object.author }}</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="model-form" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>Are you sure you want to delete "{{ object }}"?</p>
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Confirm">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
18
mensaviewer/templates/comment/detail.html
Normal file
18
mensaviewer/templates/comment/detail.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Comment{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Comment by {{ comment.author }}</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="detail-container">
|
||||||
|
<h3>Menu: <a href="{% url 'mensaviewer:menu_detail' comment.menu.pk %}">{{ comment.menu.name }}</a></h3>
|
||||||
|
<p>Timestamp: {{ comment.timestamp }}</p>
|
||||||
|
<hr>
|
||||||
|
<p>Text: </p>
|
||||||
|
<p>{{ comment.text }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
16
mensaviewer/templates/comment/edit.html
Normal file
16
mensaviewer/templates/comment/edit.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Edit Comment{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Edit Comment</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="model-form" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Save">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
36
mensaviewer/templates/comment/list.html
Normal file
36
mensaviewer/templates/comment/list.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Comments{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Comments</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<table class="comment-list">
|
||||||
|
<tr>
|
||||||
|
<td colspan="99" class="centered-td">
|
||||||
|
<a class="btn" href="{% url 'mensaviewer:comment_create' %}">Add Comment</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Text</th>
|
||||||
|
<th>Author</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Menu</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
{% for comment in object_list %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{% url 'mensaviewer:comment_detail' comment.pk %}">{{ comment.text }}</a></td>
|
||||||
|
<td>{{ comment.author }}</td>
|
||||||
|
<td class="fit-width">{{ comment.timestamp }}</td>
|
||||||
|
<td><a href="{% url 'mensaviewer:menu_detail' comment.menu.pk %}">{{ comment.menu }}</a></td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:comment_update' comment.pk %}">Edit</a></td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:comment_delete' comment.pk %}">Delete</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
11
mensaviewer/templates/create_location.html
Normal file
11
mensaviewer/templates/create_location.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<button type="submit" name="button">Save</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
66
mensaviewer/templates/custom.html
Normal file
66
mensaviewer/templates/custom.html
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Custom Locations{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Show menus for custom location selection</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="filter-form" action="{% url 'mensaviewer:custom' %}" method="get">
|
||||||
|
<input type="hidden" name="filterform" value="filter">
|
||||||
|
<div class="type-filter">
|
||||||
|
{% for name, id in types %}
|
||||||
|
<label>
|
||||||
|
{{ name }}
|
||||||
|
<input type="checkbox" name="type" value={{ id }} {% if id in checked_types %} checked{% endif %}>
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="status-filter">
|
||||||
|
{% for status_value in status_values %}
|
||||||
|
<label>
|
||||||
|
{{ status_value }}
|
||||||
|
<input type="radio" name="status" value="{{ status_value }}" {% if status == status_value %} checked{% endif %}>
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="location-filter">
|
||||||
|
{% for location in locations %}
|
||||||
|
<label>
|
||||||
|
{{ location.name }}
|
||||||
|
<input type="checkbox" name="location" value="{{ location.mensa_id }}" {% if location.mensa_id in selected_locations %} checked{% endif %}>
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<button type="submit">Filter</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
{% for day, menus in menu_data.items %}
|
||||||
|
<div class="column">
|
||||||
|
<h2>{{ day }}</h2>
|
||||||
|
|
||||||
|
{% for menu in menus %}
|
||||||
|
<div class="menu">
|
||||||
|
<p>{{ menu.art }} - <a href="{% url 'mensaviewer:location_detail' menu.location.pk %}">{{ menu.location.name }}</a></p>
|
||||||
|
<hr>
|
||||||
|
<h4><a href="{% url 'mensaviewer:menu_detail' menu.pk %}">{{ menu.name }}</a></h4>
|
||||||
|
<h5>{{ menu.price }}</h5>
|
||||||
|
<p>{{ menu.types }}</p>
|
||||||
|
<p>{{ menu.allergens }}</p>
|
||||||
|
<hr>
|
||||||
|
<p>Rating: {{ menu.likes }}</p>
|
||||||
|
<p>
|
||||||
|
<a href="{% url 'mensaviewer:like' menu.pk %}?next={{ request.path }}">Like</a> |
|
||||||
|
<a href="{% url 'mensaviewer:dislike' menu.pk %}?next={{ request.path }}">Dislike</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
57
mensaviewer/templates/flensburg.html
Normal file
57
mensaviewer/templates/flensburg.html
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Flensburg{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Mensen in Flensburg</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="filter-form" action="{% url 'mensaviewer:flensburg' %}" method="get">
|
||||||
|
<input type="hidden" name="filterform" value="filter">
|
||||||
|
<div class="type-filter">
|
||||||
|
{% for name, id in types %}
|
||||||
|
<label>
|
||||||
|
{{ name }}
|
||||||
|
<input type="checkbox" name="type" value={{ id }} {% if id in checked_types %} checked{% endif %}>
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="status-filter">
|
||||||
|
{% for status_value in status_values %}
|
||||||
|
<label>
|
||||||
|
{{ status_value }}
|
||||||
|
<input type="radio" name="status" value="{{ status_value }}" {% if status == status_value %} checked{% endif %}>
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<button type="submit">Filter</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
{% for day, menus in menu_data.items %}
|
||||||
|
<div class="column">
|
||||||
|
<h2>{{ day }}</h2>
|
||||||
|
|
||||||
|
{% for menu in menus %}
|
||||||
|
<div class="menu {% if menu.location.mensa_id == '1' %}a-mensa{% elif menu.location.mensa_id == '6' %}b-mensa{% endif %}">
|
||||||
|
<p>{{ menu.art }} - <a href="{% url 'mensaviewer:location_detail' menu.location.pk %}">{{ menu.location.name }}</a></p>
|
||||||
|
<hr>
|
||||||
|
<h4><a href="{% url 'mensaviewer:menu_detail' menu.pk %}">{{ menu.name }}</a></h4>
|
||||||
|
<h5>{{ menu.price }}</h5>
|
||||||
|
<p>{{ menu.types }}</p>
|
||||||
|
<p>{{ menu.allergens }}</p>
|
||||||
|
<hr>
|
||||||
|
<p>Rating: {{ menu.likes }}</p>
|
||||||
|
<p>
|
||||||
|
<a href="{% url 'mensaviewer:like' menu.pk %}?next={{ request.path }}">Like</a> |
|
||||||
|
<a href="{% url 'mensaviewer:dislike' menu.pk %}?next={{ request.path }}">Dislike</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
17
mensaviewer/templates/location/delete.html
Normal file
17
mensaviewer/templates/location/delete.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Delete Location{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Delete location {{ object.name }}</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="model-form" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>Are you sure you want to delete "{{ object }}"?</p>
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Confirm">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
65
mensaviewer/templates/location/detail.html
Normal file
65
mensaviewer/templates/location/detail.html
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}{{ location.city }} |{{ location.name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>{{ location.city }} |{{ location.name }}</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="detail-container">
|
||||||
|
<p>
|
||||||
|
<a class="btn" href="{% url 'mensaviewer:news_add' location.pk %}">Add News</a>
|
||||||
|
<a class="btn" href="{% url 'mensaviewer:menu_add' location.pk %}">Add Menu</a>
|
||||||
|
<a class="btn" href="{% url 'mensaviewer:location_update' location.pk %}">Edit</a>
|
||||||
|
<a class="btn" href="{% url 'mensaviewer:location_delete' location.pk %}">Delete</a>
|
||||||
|
</p>
|
||||||
|
<div class="related-items">
|
||||||
|
<h2>News</h2>
|
||||||
|
|
||||||
|
<table class="news-list">
|
||||||
|
<tr>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Author</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Menu</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
{% for newsarticle in location.news_articles %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{% url 'mensaviewer:news_detail' newsarticle.pk %}">{{ newsarticle.title }}</a></td>
|
||||||
|
<td>{{ newsarticle.author }}</td>
|
||||||
|
<td>{{ newsarticle.timestamp }}</td>
|
||||||
|
<td><a href="{% url 'mensaviewer:location_detail' newsarticle.location.pk %}">{{ newsarticle.location.city }} - {{ newsarticle.location.name }}</a></td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:news_update' newsarticle.pk %}">Edit</a></td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:news_delete' newsarticle.pk %}">Delete</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="related-items">
|
||||||
|
<h2>Menus</h2>
|
||||||
|
|
||||||
|
<table class="menu-list">
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th>Day</th>
|
||||||
|
<th>Edit</th>
|
||||||
|
<th>Delete</th>
|
||||||
|
</tr>
|
||||||
|
{% for menu in location.menus %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{% url 'mensaviewer:menu_detail' menu.pk %}">{{ menu.name }}</a></td>
|
||||||
|
<td><a href="{% url 'mensaviewer:location_detail' menu.location.pk %}">{{ menu.location.name }}</a></td>
|
||||||
|
<td>{{ menu.day }}</td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:menu_update' menu.pk %}">Edit</a></td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:menu_delete' menu.pk %}">Delete</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
16
mensaviewer/templates/location/edit.html
Normal file
16
mensaviewer/templates/location/edit.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Edit Location{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Edit location {{ object.name }}</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="model-form" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Save">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
34
mensaviewer/templates/location/list.html
Normal file
34
mensaviewer/templates/location/list.html
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Locations{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Locations</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<table class="location-list">
|
||||||
|
<tr>
|
||||||
|
<td colspan="99" class="centered-td">
|
||||||
|
<a class="btn" href="{% url 'mensaviewer:location_create' %}">New Location</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>City</th>
|
||||||
|
<th>ID</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
{% for location in object_list %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{% url 'mensaviewer:location_detail' location.pk %}">{{ location.name }}</a></td>
|
||||||
|
<td>{{ location.city }}</td>
|
||||||
|
<td class="fit-width">{{ location.mensa_id }}</td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:location_update' location.pk %}">Edit</a></td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:location_delete' location.pk %}">Delete</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
17
mensaviewer/templates/menu/delete.html
Normal file
17
mensaviewer/templates/menu/delete.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Delete Menu{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Delete menu {{ object.name }}</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="model-form" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>Are you sure you want to delete "{{ object }}"?</p>
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Confirm">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
69
mensaviewer/templates/menu/detail.html
Normal file
69
mensaviewer/templates/menu/detail.html
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}{{ menu.name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>{{ menu.name }}</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="detail-container">
|
||||||
|
<p>
|
||||||
|
<a class="btn" href="{% url 'mensaviewer:like' menu.id %}?next={{ request.path }}">Like</a>
|
||||||
|
<a class="btn" href="{% url 'mensaviewer:dislike' menu.id %}?next={{ request.path }}">Dislike</a>
|
||||||
|
<a class="btn" href="{% url 'mensaviewer:comment_add' menu.id %}">Comment</a>
|
||||||
|
</p>
|
||||||
|
<h3>Prices</h3>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Students</th>
|
||||||
|
<th>Employees</th>
|
||||||
|
<th>Guests</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ menu.get_price.Student }}</td>
|
||||||
|
<td>{{ menu.get_price.Employee }}</td>
|
||||||
|
<td>{{ menu.get_price.Guest }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h4>Art</h4>
|
||||||
|
<p>{{ menu.art }}</p>
|
||||||
|
<hr>
|
||||||
|
<h4>Allergens</h4>
|
||||||
|
<p>{{ menu.get_allergens }}</p>
|
||||||
|
<hr>
|
||||||
|
<h4>Types</h4>
|
||||||
|
<p>{{ menu.get_types }}</p>
|
||||||
|
<hr>
|
||||||
|
<h4>Rating</h4>
|
||||||
|
<p>{{ menu.likes }}</p>
|
||||||
|
<hr>
|
||||||
|
<h4>Location and Date</h4>
|
||||||
|
<p><a href="{% url 'mensaviewer:location_detail' menu.location.pk %}">{{ menu.location.city }} {{ menu.location.name }}</a> | {{ menu.day }}</p>
|
||||||
|
<hr>
|
||||||
|
<div class="related-items">
|
||||||
|
<h3>Comments</h3>
|
||||||
|
<table class="comment-list">
|
||||||
|
<tr>
|
||||||
|
<th>Text</th>
|
||||||
|
<th>Author</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Menu</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
{% for comment in menu.comments %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{% url 'mensaviewer:comment_detail' comment.pk %}">{{ comment.text }}</a></td>
|
||||||
|
<td>{{ comment.author }}</td>
|
||||||
|
<td class="fit-width">{{ comment.timestamp }}</td>
|
||||||
|
<td><a href="{% url 'mensaviewer:menu_detail' comment.menu.pk %}">{{ comment.menu }}</a></td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:comment_update' comment.pk %}">Edit</a></td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:comment_delete' comment.pk %}">Delete</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
16
mensaviewer/templates/menu/edit.html
Normal file
16
mensaviewer/templates/menu/edit.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Edit Menu{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Edit Menu {{ object.name }}</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="model-form" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Save">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
34
mensaviewer/templates/menu/list.html
Normal file
34
mensaviewer/templates/menu/list.html
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Menus{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Menus</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<table class="menu-list">
|
||||||
|
<tr>
|
||||||
|
<td colspan="99" class="centered-td">
|
||||||
|
<a class="btn" href="{% url 'mensaviewer:menu_create' %}">Add Menu</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th>Day</th>
|
||||||
|
<th>Edit</th>
|
||||||
|
<th>Delete</th>
|
||||||
|
</tr>
|
||||||
|
{% for menu in object_list %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{% url 'mensaviewer:menu_detail' menu.pk %}">{{ menu.name }}</a></td>
|
||||||
|
<td><a href="{% url 'mensaviewer:location_detail' menu.location.pk %}">{{ menu.location.name }}</a></td>
|
||||||
|
<td>{{ menu.day }}</td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:menu_update' menu.pk %}">Edit</a></td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:menu_delete' menu.pk %}">Delete</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
27
mensaviewer/templates/menu_detail.html
Normal file
27
mensaviewer/templates/menu_detail.html
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="menu-detail">
|
||||||
|
<h1>{{ menu.name }}</h1>
|
||||||
|
<p>Art: {{ menu.art }}</p>
|
||||||
|
<p>Price for Students: {{ menu.price_student }}€</p>
|
||||||
|
<p>Price for Employees: {{ menu.price_employee }}€</p>
|
||||||
|
<p>Price for Guests: {{ menu.price_guest }}€</p>
|
||||||
|
<p>Allergens: {{ menu.get_allergens }}</p>
|
||||||
|
<p>Types: {{ menu.get_types }}</p>
|
||||||
|
<p>Rating: {{ menu.likes }}</p>
|
||||||
|
<a href="{% url 'mensaviewer:like' menu.pk %}?next={{ request.path }}">Like</a>
|
||||||
|
<a href="{% url 'mensaviewer:dislike' menu.pk %}?next={{ request.path }}">Dislike</a>
|
||||||
|
<a href="{% url 'mensaviewer:comment' menu.pk %}">Comment</a>
|
||||||
|
<div class="comments">
|
||||||
|
{% for comment in menu.comments %}
|
||||||
|
<div class="comment">
|
||||||
|
<h3>{{ comment.username }}</h3>
|
||||||
|
<p>{{ comment.comment }}</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
17
mensaviewer/templates/news/delete.html
Normal file
17
mensaviewer/templates/news/delete.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Delete News{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Delete news article {{ object.title }}</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="model-form" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>Are you sure you want to delete "{{ object }}"?</p>
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Confirm">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
23
mensaviewer/templates/news/detail.html
Normal file
23
mensaviewer/templates/news/detail.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}{{ newsarticle.title }}{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>{{ newsarticle.title }}</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="detail-container">
|
||||||
|
<h1>Written by {{ newsarticle.author }}</h1>
|
||||||
|
<hr>
|
||||||
|
<h4>Timestamp</h4>
|
||||||
|
<p>{{ newsarticle.timestamp }}</p>
|
||||||
|
<hr>
|
||||||
|
<h4>Location</h4>
|
||||||
|
<p><a href="{% url 'mensaviewer:location_detail' newsarticle.location.pk %}">{{ newsarticle.location.name }}</a></p>
|
||||||
|
<hr>
|
||||||
|
<h4>Text</h4>
|
||||||
|
<p>{{ newsarticle.text }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
16
mensaviewer/templates/news/edit.html
Normal file
16
mensaviewer/templates/news/edit.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}Edit News Article{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>Edit news article {{ object.title }}</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form class="model-form" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Save">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
36
mensaviewer/templates/news/list.html
Normal file
36
mensaviewer/templates/news/list.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}News Articles{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h1>News Articles</h1>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<table class="news-list">
|
||||||
|
<tr>
|
||||||
|
<td colspan="99" class="centered-td">
|
||||||
|
<a class="btn" href="{% url 'mensaviewer:news_create' %}">Add News Article</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Author</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Menu</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
{% for newsarticle in object_list %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{% url 'mensaviewer:news_detail' newsarticle.pk %}">{{ newsarticle.title }}</a></td>
|
||||||
|
<td>{{ newsarticle.author }}</td>
|
||||||
|
<td>{{ newsarticle.timestamp }}</td>
|
||||||
|
<td><a href="{% url 'mensaviewer:location_detail' newsarticle.location.pk %}">{{ newsarticle.location.city }} - {{ newsarticle.location.name }}</a></td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:news_update' newsarticle.pk %}">Edit</a></td>
|
||||||
|
<td class="fit-width"><a href="{% url 'mensaviewer:news_delete' newsarticle.pk %}">Delete</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
3
mensaviewer/tests.py
Normal file
3
mensaviewer/tests.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
48
mensaviewer/urls.py
Normal file
48
mensaviewer/urls.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = 'mensaviewer'
|
||||||
|
urlpatterns = [
|
||||||
|
# routes for overview
|
||||||
|
path('', views.flensburg, name='flensburg'),
|
||||||
|
path('custom-location', views.custom, name='custom'),
|
||||||
|
|
||||||
|
# raw create routes
|
||||||
|
path('add-location/', views.LocationCreateView.as_view(), name='location_create'),
|
||||||
|
path('add-news-article/', views.NewsArticleCreateView.as_view(), name='news_create'),
|
||||||
|
path('add-menu/', views.MenuCreateView.as_view(), name='menu_create'),
|
||||||
|
path('add-comment/', views.CommentCreateView.as_view(), name='comment_create'),
|
||||||
|
|
||||||
|
# relation-dependent create routes
|
||||||
|
path('location/<int:pk>/add-news-article/', views.NewsArticleCreateView.as_view(), name='news_add'),
|
||||||
|
path('location/<int:pk>/add-menu/', views.MenuCreateView.as_view(), name='menu_add'),
|
||||||
|
path('menu/<int:pk>/add-comment/', views.CommentCreateView.as_view(), name='comment_add'),
|
||||||
|
|
||||||
|
# list-view routes
|
||||||
|
path('locations/', views.LocationListView.as_view(), name='location_list'),
|
||||||
|
path('news-articles/', views.NewsArticleListView.as_view(), name='news_list'),
|
||||||
|
path('menus/', views.MenuListView.as_view(), name='menu_list'),
|
||||||
|
path('comments/', views.CommentListView.as_view(), name='comment_list'),
|
||||||
|
|
||||||
|
# detail-view routes
|
||||||
|
path('location/<int:pk>/', views.LocationDetailView.as_view(), name='location_detail'),
|
||||||
|
path('news-article/<int:pk>/', views.NewsArticleDetailView.as_view(), name='news_detail'),
|
||||||
|
path('menu/<int:pk>/', views.MenuDetailView.as_view(), name='menu_detail'),
|
||||||
|
path('comment/<int:pk>/', views.CommentDetailView.as_view(), name='comment_detail'),
|
||||||
|
|
||||||
|
# update-view routes
|
||||||
|
path('location/<int:pk>/edit/', views.LocationUpdateView.as_view(), name='location_update'),
|
||||||
|
path('news-artice/<int:pk>/edit/', views.NewsArticleUpdateView.as_view(), name='news_update'),
|
||||||
|
path('menu/<int:pk>/edit/', views.MenuUpdateView.as_view(), name='menu_update'),
|
||||||
|
path('comment/<int:pk>/edit/', views.CommentUpdateView.as_view(), name='comment_update'),
|
||||||
|
|
||||||
|
# delete-view routes
|
||||||
|
path('location/<int:pk>/delete/', views.LocationDeleteView.as_view(), name='location_delete'),
|
||||||
|
path('news-artice/<int:pk>/delete/', views.NewsArticleDeleteView.as_view(), name='news_delete'),
|
||||||
|
path('menu/<int:pk>/delete/', views.MenuDeleteView.as_view(), name='menu_delete'),
|
||||||
|
path('comment/<int:pk>/delete/', views.CommentDeleteView.as_view(), name='comment_delete'),
|
||||||
|
|
||||||
|
# like / dislike routes
|
||||||
|
path('menu/<int:pk>/like/', views.like, name='like'),
|
||||||
|
path('menu/<int:pk>/dislike/', views.dislike, name='dislike'),
|
||||||
|
]
|
222
mensaviewer/views.py
Normal file
222
mensaviewer/views.py
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
from django.views.generic import DetailView, ListView
|
||||||
|
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
||||||
|
from django.shortcuts import render, redirect, reverse
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
|
||||||
|
from .models import *
|
||||||
|
from .helpers import *
|
||||||
|
from .forms import *
|
||||||
|
from .data import *
|
||||||
|
|
||||||
|
|
||||||
|
def flensburg(request):
|
||||||
|
filter_query = request.COOKIES.get('filter_query', '')
|
||||||
|
if len(request.GET.getlist('filterform')) == 0 and filter_query != '':
|
||||||
|
return redirect(reverse('mensaviewer:flensburg') + '?' + filter_query)
|
||||||
|
|
||||||
|
checked_types = request.GET.getlist('type')
|
||||||
|
status = request.GET.get('status')
|
||||||
|
selected_locations = Location.objects.filter(mensa_id__in=[7, 14])
|
||||||
|
if not selected_locations.exists():
|
||||||
|
Location(city="Flensburg", name="Hauptmensa", mensa_id=7).save()
|
||||||
|
Location(city="Flensburg", name="B-Mensa", mensa_id=14).save()
|
||||||
|
context = {
|
||||||
|
'types': [(TYPES[type], type) for type in TYPES],
|
||||||
|
'checked_types': checked_types,
|
||||||
|
'status_values': STATUS_VALUES,
|
||||||
|
'status': status,
|
||||||
|
'menu_data': load_data(selected_locations, checked_types, status),
|
||||||
|
}
|
||||||
|
response = render(request, "flensburg.html", context)
|
||||||
|
response.set_cookie('filter_query', request.GET.urlencode())
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
def custom(request):
|
||||||
|
filter_query = request.COOKIES.get('filter_query', '')
|
||||||
|
if len(request.GET.getlist('filterform')) == 0 and filter_query != '':
|
||||||
|
return redirect(reverse('mensaviewer:custom') + '?' + filter_query)
|
||||||
|
|
||||||
|
selected_location_ids = request.GET.getlist('location')
|
||||||
|
checked_types = request.GET.getlist('type')
|
||||||
|
status = request.GET.get('status')
|
||||||
|
selected_locations = Location.objects.filter(mensa_id__in=selected_location_ids)
|
||||||
|
context = {
|
||||||
|
'types': [(TYPES[type], type) for type in TYPES],
|
||||||
|
'checked_types': checked_types,
|
||||||
|
'status_values': STATUS_VALUES,
|
||||||
|
'status': status,
|
||||||
|
'locations': Location.objects.all(),
|
||||||
|
'selected_locations': selected_location_ids,
|
||||||
|
'menu_data': load_data(selected_locations, checked_types, status),
|
||||||
|
}
|
||||||
|
response = render(request, "custom.html", context)
|
||||||
|
response.set_cookie('filter_query', request.GET.urlencode())
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
def like(request, pk):
|
||||||
|
if request.method == 'GET':
|
||||||
|
menu = Menu.objects.get(pk=pk)
|
||||||
|
menu.likes += 1
|
||||||
|
menu.save()
|
||||||
|
return redirect(request.GET.get('next'))
|
||||||
|
|
||||||
|
|
||||||
|
def dislike(request, pk):
|
||||||
|
if request.method == 'GET':
|
||||||
|
menu = Menu.objects.get(pk=pk)
|
||||||
|
menu.likes -= 1
|
||||||
|
menu.save()
|
||||||
|
return redirect(request.GET.get('next'))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LocationCreateView(CreateView):
|
||||||
|
model = Location
|
||||||
|
template_name = "location/edit.html"
|
||||||
|
fields = '__all__'
|
||||||
|
success_url = reverse_lazy("mensaviewer:location_list")
|
||||||
|
|
||||||
|
|
||||||
|
class LocationUpdateView(UpdateView):
|
||||||
|
model = Location
|
||||||
|
template_name = "location/edit.html"
|
||||||
|
fields = '__all__'
|
||||||
|
success_url = reverse_lazy("mensaviewer:location_list")
|
||||||
|
|
||||||
|
|
||||||
|
class LocationDeleteView(DeleteView):
|
||||||
|
model = Location
|
||||||
|
template_name = "location/delete.html"
|
||||||
|
success_url = reverse_lazy("mensaviewer:location_list")
|
||||||
|
|
||||||
|
|
||||||
|
class LocationDetailView(DetailView):
|
||||||
|
model = Location
|
||||||
|
template_name = "location/detail.html"
|
||||||
|
|
||||||
|
|
||||||
|
class LocationListView(ListView):
|
||||||
|
model = Location
|
||||||
|
template_name = "location/list.html"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class NewsArticleCreateView(CreateView):
|
||||||
|
model = NewsArticle
|
||||||
|
template_name = "news/edit.html"
|
||||||
|
fields = ['location', 'title', 'author', 'text']
|
||||||
|
success_url = reverse_lazy("mensaviewer:news_list")
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
if 'pk' in self.kwargs:
|
||||||
|
return { 'location': get_object_or_404(Location, pk=self.kwargs['pk']) }
|
||||||
|
else:
|
||||||
|
return { 'location': None }
|
||||||
|
|
||||||
|
|
||||||
|
class NewsArticleUpdateView(UpdateView):
|
||||||
|
model = NewsArticle
|
||||||
|
template_name = "news/edit.html"
|
||||||
|
fields = ['location', 'title', 'author', 'text']
|
||||||
|
success_url = reverse_lazy("mensaviewer:news_list")
|
||||||
|
|
||||||
|
|
||||||
|
class NewsArticleDeleteView(DeleteView):
|
||||||
|
model = NewsArticle
|
||||||
|
template_name = "news/delete.html"
|
||||||
|
success_url = reverse_lazy("mensaviewer:news_list")
|
||||||
|
|
||||||
|
|
||||||
|
class NewsArticleDetailView(DetailView):
|
||||||
|
model = NewsArticle
|
||||||
|
template_name = "news/detail.html"
|
||||||
|
|
||||||
|
|
||||||
|
class NewsArticleListView(ListView):
|
||||||
|
model = NewsArticle
|
||||||
|
template_name = "news/list.html"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MenuCreateView(CreateView):
|
||||||
|
model = Menu
|
||||||
|
form_class = MenuForm
|
||||||
|
template_name = "menu/edit.html"
|
||||||
|
success_url = reverse_lazy("mensaviewer:menu_list")
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
if 'pk' in self.kwargs:
|
||||||
|
return { 'location': get_object_or_404(Location, pk=self.kwargs['pk']) }
|
||||||
|
else:
|
||||||
|
return { 'location': None }
|
||||||
|
|
||||||
|
|
||||||
|
class MenuUpdateView(UpdateView):
|
||||||
|
model = Menu
|
||||||
|
form_class = MenuForm
|
||||||
|
template_name = "menu/edit.html"
|
||||||
|
success_url = reverse_lazy("mensaviewer:menu_list")
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
menu = get_object_or_404(Menu, pk=self.kwargs['pk'])
|
||||||
|
print(menu.types)
|
||||||
|
return { 'types': menu.types }
|
||||||
|
|
||||||
|
|
||||||
|
class MenuDeleteView(DeleteView):
|
||||||
|
model = Menu
|
||||||
|
template_name = "menu/delete.html"
|
||||||
|
success_url = reverse_lazy("mensaviewer:menu_list")
|
||||||
|
|
||||||
|
|
||||||
|
class MenuDetailView(DetailView):
|
||||||
|
model = Menu
|
||||||
|
template_name = "menu/detail.html"
|
||||||
|
|
||||||
|
|
||||||
|
class MenuListView(ListView):
|
||||||
|
model = Menu
|
||||||
|
template_name = "menu/list.html"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CommentCreateView(CreateView):
|
||||||
|
model = Comment
|
||||||
|
fields = ['menu', 'author', 'text']
|
||||||
|
template_name = "comment/edit.html"
|
||||||
|
success_url = '/menu/{menu_id}/'
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
if 'pk' in self.kwargs:
|
||||||
|
return { 'menu': get_object_or_404(Menu, pk=self.kwargs['pk']) }
|
||||||
|
else:
|
||||||
|
return { 'menu': None }
|
||||||
|
|
||||||
|
|
||||||
|
class CommentUpdateView(UpdateView):
|
||||||
|
model = Comment
|
||||||
|
fields = ['author', 'text']
|
||||||
|
template_name = "comment/edit.html"
|
||||||
|
success_url = '/menu/{menu_id}/'
|
||||||
|
|
||||||
|
|
||||||
|
class CommentDeleteView(DeleteView):
|
||||||
|
model = Comment
|
||||||
|
template_name = "comment/delete.html"
|
||||||
|
success_url = '/menu/{menu_id}/'
|
||||||
|
|
||||||
|
|
||||||
|
class CommentDetailView(DetailView):
|
||||||
|
model = Comment
|
||||||
|
template_name = "comment/detail.html"
|
||||||
|
|
||||||
|
|
||||||
|
class CommentListView(ListView):
|
||||||
|
model = Comment
|
||||||
|
template_name = "comment/list.html"
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Django==4.1.3
|
||||||
|
requests==2.28.1
|
226
static/base.css
Normal file
226
static/base.css
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
* {
|
||||||
|
font-family: Tahoma;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background-color: #1D1D28;
|
||||||
|
color: #EEEDFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3 {
|
||||||
|
margin: 0;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
padding-left: 12vw;
|
||||||
|
box-shadow: 0px 0px 32px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: flex;
|
||||||
|
background-color: #3E3949;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
border-right: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 16vw;
|
||||||
|
min-width: 16em;
|
||||||
|
padding-top: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 18px;
|
||||||
|
padding: 0.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a:hover {
|
||||||
|
transition: 250ms;
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
nav hr {
|
||||||
|
width: 16em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #EEEDFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
transition: 250ms;
|
||||||
|
color: #FFEFCA;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:active {
|
||||||
|
color: #CEA716;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
padding: 1em;
|
||||||
|
margin: 0.5em;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 0.5em;
|
||||||
|
box-shadow: inset 0px 0px 1em rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
padding: 1em;
|
||||||
|
margin: 0.5em;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 0.5em;
|
||||||
|
box-shadow: inset 0px 0px 1em rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
padding: 0.5em;
|
||||||
|
color: #CEA716;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0.5em;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 0.2em;
|
||||||
|
max-width: 30vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fit-width {
|
||||||
|
width: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin-left: 4vw;
|
||||||
|
margin-right: 4vw;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered-td {
|
||||||
|
text-align: center;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 0.4em;
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-form input, .model-form textarea, .model-form select, button {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
padding: 0.5em;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 1);
|
||||||
|
border-radius: 0.5em;
|
||||||
|
color: #EEEDFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-form .type-filter, .filter-form .status-filter, .filter-form .location-filter {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-form label {
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 0.3em;
|
||||||
|
padding: 0.3em;
|
||||||
|
margin: 0.5em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-form hr {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"], button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"]:active, button:active {
|
||||||
|
transition: 200ms;
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 0.3em;
|
||||||
|
margin: 0.3em;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 0.5em;
|
||||||
|
box-shadow: inset 0px 0px 1em rgba(0, 0, 0, 0.2);
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
flex: 1;
|
||||||
|
flex-flow: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-items {
|
||||||
|
margin: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment {
|
||||||
|
border-radius: 0.2em;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||||
|
margin: 0.5em;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu, .news-article {
|
||||||
|
padding: 1em;
|
||||||
|
margin: 0.2em;
|
||||||
|
margin-bottom: 0.8em;
|
||||||
|
border-radius: 0.2em;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||||
|
box-shadow: inset 0px 0px 1em rgba(0, 0, 0, 0.2);
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu hr {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu p {
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu a {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.a-mensa {
|
||||||
|
background-color: rgba(40, 29, 40, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-mensa {
|
||||||
|
background-color: rgba(29, 40, 40, 0.7);
|
||||||
|
}
|
0
webprog/__init__.py
Normal file
0
webprog/__init__.py
Normal file
16
webprog/asgi.py
Normal file
16
webprog/asgi.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
ASGI config for webprog project.
|
||||||
|
|
||||||
|
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'webprog.settings')
|
||||||
|
|
||||||
|
application = get_asgi_application()
|
128
webprog/settings.py
Normal file
128
webprog/settings.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
"""
|
||||||
|
Django settings for webprog project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 4.1.4.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/4.1/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/4.1/ref/settings/
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = 'django-insecure-srl4kvoe3zz=@x^h6aew)s4(&4!$96g%)%ar+yfpp@4t*0oo9('
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ['127.0.0.1', '192.168.178.36', 'webprog-homework.deploy.cat']
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'mensaviewer.apps.MensaviewerConfig',
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
]
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
]
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'webprog.urls'
|
||||||
|
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
|
'DIRS': [],
|
||||||
|
'APP_DIRS': True,
|
||||||
|
'OPTIONS': {
|
||||||
|
'context_processors': [
|
||||||
|
'django.template.context_processors.debug',
|
||||||
|
'django.template.context_processors.request',
|
||||||
|
'django.contrib.auth.context_processors.auth',
|
||||||
|
'django.contrib.messages.context_processors.messages',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'webprog.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': BASE_DIR / 'db.sqlite3',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Password validation
|
||||||
|
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
# https://docs.djangoproject.com/en/4.1/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
|
TIME_ZONE = 'UTC'
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/4.1/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = 'static/'
|
||||||
|
|
||||||
|
STATICFILES_DIRS = [
|
||||||
|
BASE_DIR/"static",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Default primary key field type
|
||||||
|
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
22
webprog/urls.py
Normal file
22
webprog/urls.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"""webprog URL Configuration
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/4.1/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.contrib import admin
|
||||||
|
from django.urls import path, include
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('admin/', admin.site.urls),
|
||||||
|
path('', include('mensaviewer.urls'))
|
||||||
|
]
|
16
webprog/wsgi.py
Normal file
16
webprog/wsgi.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
WSGI config for webprog project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'webprog.settings')
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
Loading…
Reference in New Issue
Block a user