diff --git a/TeamForge/settings.py b/TeamForge/settings.py index da3e0e5..8dd4a41 100644 --- a/TeamForge/settings.py +++ b/TeamForge/settings.py @@ -45,6 +45,7 @@ INSTALLED_APPS = [ "django.contrib.staticfiles", "constance", "tailwind", + "django_filters", "rules.apps.AutodiscoverRulesConfig", "theme.apps.ThemeConfig", # Tailwind theme app "members.apps.MembersConfig", diff --git a/TeamForge/urls.py b/TeamForge/urls.py index 8280da8..de4aa5a 100644 --- a/TeamForge/urls.py +++ b/TeamForge/urls.py @@ -15,8 +15,9 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import include, path urlpatterns = [ + path('backend/', include('backend.urls')), path('admin/', admin.site.urls), ] diff --git a/backend/admin.py b/backend/admin.py deleted file mode 100644 index 8c38f3f..0000000 --- a/backend/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/backend/migrations/__init__.py b/backend/members/__init__.py similarity index 100% rename from backend/migrations/__init__.py rename to backend/members/__init__.py diff --git a/backend/members/urls.py b/backend/members/urls.py new file mode 100644 index 0000000..ddfff65 --- /dev/null +++ b/backend/members/urls.py @@ -0,0 +1,12 @@ +from django.urls import include, path + +from .views import MemberAddView, MemberDeleteView, MemberEditView, MemberListView, MemberLoadView + +app_name = "members" +urlpatterns = [ + path("", MemberListView.as_view(), name="list"), + # path("add/", MemberAddView.as_view(), name="add"), + # path("/edit/", MemberEditView.as_view(), name="edit"), + # path("/delete/", MemberDeleteView.as_view(), name="delete"), + # path("load/", MemberLoadView.as_view(), name="load"), +] diff --git a/backend/members/views.py b/backend/members/views.py new file mode 100644 index 0000000..124f05f --- /dev/null +++ b/backend/members/views.py @@ -0,0 +1,34 @@ +from typing import Any + +from django.contrib import messages +from django.http import HttpResponse, HttpResponseRedirect +from django.urls import reverse_lazy +from django.utils.translation import gettext_lazy as _ +from django_filters.views import FilterView +from rules.contrib.views import PermissionRequiredMixin + +from members.filters import MemberFilter +from members.models import Member + + +class MemberListView(PermissionRequiredMixin, FilterView): + filterset_class = MemberFilter + paginate_by = 50 + permission_denied_message = _("You do not have permission to view this page.") + permission_required = "members.view_member" + + def handle_no_permission(self) -> HttpResponseRedirect: + messages.error(self.request, self.get_permission_denied_message()) + return HttpResponseRedirect(reverse_lazy("backend:index")) + + +class MemberAddView: ... + + +class MemberEditView: ... + + +class MemberDeleteView: ... + + +class MemberLoadView: ... diff --git a/backend/tests.py b/backend/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/backend/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/backend/urls.py b/backend/urls.py new file mode 100644 index 0000000..8a6f503 --- /dev/null +++ b/backend/urls.py @@ -0,0 +1,9 @@ +from django.urls import include, path + +from .views import index + +app_name = "backend" +urlpatterns = [ + path("", index, name="index"), + path("members/", include("backend.members.urls")), +] diff --git a/backend/views.py b/backend/views.py index 91ea44a..91e8035 100644 --- a/backend/views.py +++ b/backend/views.py @@ -1,3 +1,6 @@ from django.shortcuts import render + # Create your views here. +def index(request): + return render(request, "backend/index.html") diff --git a/members/filters.py b/members/filters.py new file mode 100644 index 0000000..d32fbbe --- /dev/null +++ b/members/filters.py @@ -0,0 +1,16 @@ +import django_filters +from django.utils.translation import gettext_lazy as _ + +from .models import Member + + +class MemberFilter(django_filters.FilterSet): + user__first_name = django_filters.CharFilter(field_name="user__first_name", label=_("First name")) + user__last_name = django_filters.CharFilter(field_name="user__last_name", label=_("Last name")) + license = django_filters.CharFilter(label=_("License"), lookup_expr="icontains") + + class Meta: + model = Member + fields = ["user__first_name", "user__last_name", "license"] + + \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index a0ef2a4..84e0767 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,6 +8,7 @@ dependencies = [ "django>=6.0", "django-constance>=4.3.4", "django-extensions>=4.1", + "django-filter>=25.2", "django-phonenumber-field[phonenumbers]>=8.4.0", "django-tailwind[cookiecutter,honcho]>=4.4.2", "psycopg2-binary>=2.9.11", diff --git a/templates/backend/index.html b/templates/backend/index.html new file mode 100644 index 0000000..c5bd7e0 --- /dev/null +++ b/templates/backend/index.html @@ -0,0 +1 @@ +TEST FILE \ No newline at end of file diff --git a/templates/members/member_filter.html b/templates/members/member_filter.html new file mode 100644 index 0000000..e227992 --- /dev/null +++ b/templates/members/member_filter.html @@ -0,0 +1 @@ +TEST FILE 2 \ No newline at end of file diff --git a/uv.lock b/uv.lock index dc91dad..bda49b0 100644 --- a/uv.lock +++ b/uv.lock @@ -243,6 +243,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/96/d967ca440d6a8e3861120f51985d8e5aec79b9a8bdda16041206adfe7adc/django_extensions-4.1-py3-none-any.whl", hash = "sha256:0699a7af28f2523bf8db309a80278519362cd4b6e1fd0a8cd4bf063e1e023336", size = 232980, upload-time = "2025-04-11T01:15:37.701Z" }, ] +[[package]] +name = "django-filter" +version = "25.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2c/e4/465d2699cd388c0005fb8d6ae6709f239917c6d8790ac35719676fffdcf3/django_filter-25.2.tar.gz", hash = "sha256:760e984a931f4468d096f5541787efb8998c61217b73006163bf2f9523fe8f23", size = 143818, upload-time = "2025-10-05T09:51:31.521Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/40/6a02495c5658beb1f31eb09952d8aa12ef3c2a66342331ce3a35f7132439/django_filter-25.2-py3-none-any.whl", hash = "sha256:9c0f8609057309bba611062fe1b720b4a873652541192d232dd28970383633e3", size = 94145, upload-time = "2025-10-05T09:51:29.728Z" }, +] + [[package]] name = "django-phonenumber-field" version = "8.4.0" @@ -603,6 +615,7 @@ dependencies = [ { name = "django" }, { name = "django-constance" }, { name = "django-extensions" }, + { name = "django-filter" }, { name = "django-phonenumber-field", extra = ["phonenumbers"] }, { name = "django-tailwind", extra = ["cookiecutter", "honcho"] }, { name = "psycopg2-binary" }, @@ -622,6 +635,7 @@ requires-dist = [ { name = "django", specifier = ">=6.0" }, { name = "django-constance", specifier = ">=4.3.4" }, { name = "django-extensions", specifier = ">=4.1" }, + { name = "django-filter", specifier = ">=25.2" }, { name = "django-phonenumber-field", extras = ["phonenumbers"], specifier = ">=8.4.0" }, { name = "django-tailwind", extras = ["cookiecutter", "honcho"], specifier = ">=4.4.2" }, { name = "psycopg2-binary", specifier = ">=2.9.11" },