feat: Implementierung von Phase 3 und Profilbearbeitung
This commit is contained in:
parent
e119b5c914
commit
05da0c94ac
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -20,3 +20,9 @@ class CustomUserCreationForm(forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = CustomUser
|
model = CustomUser
|
||||||
fields = ('username', 'first_name', 'last_name', 'email', 'birth_date', 'player_number', 'password')
|
fields = ('username', 'first_name', 'last_name', 'email', 'birth_date', 'player_number', 'password')
|
||||||
|
|
||||||
|
class CustomUserChangeForm(forms.ModelForm):
|
||||||
|
birth_date = forms.DateField(input_formats=['%d.%m.%Y'], widget=forms.DateInput(format='%d.%m.%Y'))
|
||||||
|
class Meta:
|
||||||
|
model = CustomUser
|
||||||
|
fields = ('username', 'first_name', 'last_name', 'email', 'birth_date', 'player_number', 'team')
|
||||||
|
|||||||
20
accounts/migrations/0002_customuser_team.py
Normal file
20
accounts/migrations/0002_customuser_team.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 5.2.6 on 2025-09-30 18:09
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0001_initial'),
|
||||||
|
('clubs', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customuser',
|
||||||
|
name='team',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='players', to='clubs.team'),
|
||||||
|
),
|
||||||
|
]
|
||||||
Binary file not shown.
@ -6,6 +6,7 @@ import datetime
|
|||||||
class CustomUser(AbstractUser):
|
class CustomUser(AbstractUser):
|
||||||
birth_date = models.DateField(null=True, blank=True)
|
birth_date = models.DateField(null=True, blank=True)
|
||||||
player_number = models.IntegerField(default=999)
|
player_number = models.IntegerField(default=999)
|
||||||
|
team = models.ForeignKey('clubs.Team', on_delete=models.SET_NULL, null=True, blank=True, related_name='players')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def age(self):
|
def age(self):
|
||||||
|
|||||||
10
accounts/templates/accounts/edit_profile.html
Normal file
10
accounts/templates/accounts/edit_profile.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h2>Edit Profile</h2>
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<button type="submit">Save Changes</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
@ -7,4 +7,5 @@ urlpatterns = [
|
|||||||
path('register/', views.register_view, name='register'),
|
path('register/', views.register_view, name='register'),
|
||||||
path('login/', auth_views.LoginView.as_view(template_name='accounts/login.html'), name='login'),
|
path('login/', auth_views.LoginView.as_view(template_name='accounts/login.html'), name='login'),
|
||||||
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
|
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
|
||||||
|
path('profile/', views.edit_profile, name='edit_profile'),
|
||||||
]
|
]
|
||||||
@ -1,6 +1,7 @@
|
|||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from .forms import InvitationCodeForm, CustomUserCreationForm
|
from .forms import InvitationCodeForm, CustomUserCreationForm, CustomUserChangeForm
|
||||||
from .models import InvitationCode
|
from .models import InvitationCode
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
|
||||||
def invitation_code_view(request):
|
def invitation_code_view(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@ -40,4 +41,15 @@ def register_view(request):
|
|||||||
return redirect('login') # Or wherever you want to redirect after registration
|
return redirect('login') # Or wherever you want to redirect after registration
|
||||||
else:
|
else:
|
||||||
form = CustomUserCreationForm()
|
form = CustomUserCreationForm()
|
||||||
return render(request, 'accounts/register.html', {'form': form})
|
return render(request, 'accounts/register.html', {'form': form})
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def edit_profile(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = CustomUserChangeForm(request.POST, instance=request.user)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
return redirect('edit_profile') # Or wherever you want to redirect
|
||||||
|
else:
|
||||||
|
form = CustomUserChangeForm(instance=request.user)
|
||||||
|
return render(request, 'accounts/edit_profile.html', {'form': form})
|
||||||
Binary file not shown.
Binary file not shown.
@ -1,3 +1,5 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from .models import Club, Team
|
||||||
|
|
||||||
# Register your models here.
|
admin.site.register(Club)
|
||||||
|
admin.site.register(Team)
|
||||||
37
clubs/migrations/0001_initial.py
Normal file
37
clubs/migrations/0001_initial.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Generated by Django 5.2.6 on 2025-09-30 18:09
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Club',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
('website', models.URLField(blank=True)),
|
||||||
|
('administrators', models.ManyToManyField(related_name='administered_clubs', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Team',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
('assistant_coaches', models.ManyToManyField(blank=True, related_name='assisted_teams', to=settings.AUTH_USER_MODEL)),
|
||||||
|
('club', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teams', to='clubs.club')),
|
||||||
|
('head_coach', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='coached_teams', to=settings.AUTH_USER_MODEL)),
|
||||||
|
('parent_team', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='child_teams', to='clubs.team')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
BIN
clubs/migrations/__pycache__/0001_initial.cpython-313.pyc
Normal file
BIN
clubs/migrations/__pycache__/0001_initial.cpython-313.pyc
Normal file
Binary file not shown.
@ -1,3 +1,20 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
# Create your models here.
|
class Club(models.Model):
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
website = models.URLField(blank=True)
|
||||||
|
administrators = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='administered_clubs')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Team(models.Model):
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
club = models.ForeignKey(Club, on_delete=models.CASCADE, related_name='teams')
|
||||||
|
head_coach = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name='coached_teams')
|
||||||
|
assistant_coaches = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='assisted_teams', blank=True)
|
||||||
|
parent_team = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name='child_teams')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
27
docs/phase3.md
Normal file
27
docs/phase3.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
## Phase 3: Organisationsstruktur
|
||||||
|
|
||||||
|
Diese Phase befasst sich mit den Modellen für Clubs, Mannschaften und Teams.
|
||||||
|
|
||||||
|
Schritt 1: Club-Modell erstellen
|
||||||
|
|
||||||
|
Navigiere in das clubs-Verzeichnis und öffne models.py.
|
||||||
|
|
||||||
|
Erstelle ein Club-Modell mit den Feldern name und website.
|
||||||
|
|
||||||
|
Verknüpfe den Club mit dem User-Modell, um Administratoren zuzuweisen.
|
||||||
|
|
||||||
|
Schritt 2: Mannschafts- und Team-Modelle erstellen
|
||||||
|
|
||||||
|
Erstelle ein Team-Modell, das die Mannschaft repräsentiert, da in der Projektbeschreibung die Mannschaft als Team behandelt werden kann. Ein is_team Feld könnte hier nützlich sein, ist aber nicht notwendig, da die Beziehungen zu parent_team die Hierarchie festlegen.
|
||||||
|
|
||||||
|
Ein Team-Modell hat die Felder: name, head_coach (Fremdschlüssel zu User), assistant_coaches (ManyToMany-Feld zu User), und parent_team (Fremdschlüssel zu sich selbst für die Untergliederung).
|
||||||
|
|
||||||
|
Ein Team gehört zu einem Club.
|
||||||
|
|
||||||
|
Schritt 3: Benutzerbeziehungen implementieren
|
||||||
|
|
||||||
|
Stelle sicher, dass die Beziehungen zwischen User und Team korrekt definiert sind:
|
||||||
|
|
||||||
|
Ein User kann Player sein und einem Team zugewiesen werden.
|
||||||
|
|
||||||
|
Ein User kann HeadCoach oder AssistantCoach eines Team sein.
|
||||||
69
docs/traceback/trace1.log
Normal file
69
docs/traceback/trace1.log
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
Traceback (most recent call last):
|
||||||
|
File "/usr/lib64/python3.13/threading.py", line 1043, in _bootstrap_inner
|
||||||
|
self.run()
|
||||||
|
~~~~~~~~^^
|
||||||
|
File "/usr/lib64/python3.13/threading.py", line 994, in run
|
||||||
|
self._target(*self._args, **self._kwargs)
|
||||||
|
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/utils/autoreload.py", line 64, in wrapper
|
||||||
|
fn(*args, **kwargs)
|
||||||
|
~~^^^^^^^^^^^^^^^^^
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/management/commands/runserver.py", line 134, in inner_run
|
||||||
|
self.check(**check_kwargs)
|
||||||
|
~~~~~~~~~~^^^^^^^^^^^^^^^^
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/management/base.py", line 492, in check
|
||||||
|
all_issues = checks.run_checks(
|
||||||
|
app_configs=app_configs,
|
||||||
|
...<2 lines>...
|
||||||
|
databases=databases,
|
||||||
|
)
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/checks/registry.py", line 89, in run_checks
|
||||||
|
new_errors = check(app_configs=app_configs, databases=databases)
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/checks/urls.py", line 16, in check_url_config
|
||||||
|
return check_resolver(resolver)
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/checks/urls.py", line 26, in check_resolver
|
||||||
|
return check_method()
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/urls/resolvers.py", line 531, in check
|
||||||
|
for pattern in self.url_patterns:
|
||||||
|
^^^^^^^^^^^^^^^^^
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/utils/functional.py", line 47, in __get__
|
||||||
|
res = instance.__dict__[self.name] = self.func(instance)
|
||||||
|
~~~~~~~~~^^^^^^^^^^
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/urls/resolvers.py", line 718, in url_patterns
|
||||||
|
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/utils/functional.py", line 47, in __get__
|
||||||
|
res = instance.__dict__[self.name] = self.func(instance)
|
||||||
|
~~~~~~~~~^^^^^^^^^^
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/urls/resolvers.py", line 711, in urlconf_module
|
||||||
|
return import_module(self.urlconf_name)
|
||||||
|
File "/usr/lib64/python3.13/importlib/__init__.py", line 88, in import_module
|
||||||
|
return _bootstrap._gcd_import(name[level:], package, level)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
|
||||||
|
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
|
||||||
|
File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
|
||||||
|
File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
|
||||||
|
File "<frozen importlib._bootstrap_external>", line 1026, in exec_module
|
||||||
|
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/baseball_organisator/urls.py", line 22, in <module>
|
||||||
|
path('accounts/', include('accounts.urls')),
|
||||||
|
~~~~~~~^^^^^^^^^^^^^^^^^
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/urls/conf.py", line 39, in include
|
||||||
|
urlconf_module = import_module(urlconf_module)
|
||||||
|
File "/usr/lib64/python3.13/importlib/__init__.py", line 88, in import_module
|
||||||
|
return _bootstrap._gcd_import(name[level:], package, level)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
|
||||||
|
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
|
||||||
|
File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
|
||||||
|
File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
|
||||||
|
File "<frozen importlib._bootstrap_external>", line 1026, in exec_module
|
||||||
|
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/accounts/urls.py", line 2, in <module>
|
||||||
|
from . import views
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/accounts/views.py", line 2, in <module>
|
||||||
|
@login_required
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
NameError: name 'login_required' is not defined
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user