Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions task_manager/statuses/urls.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from django.urls import path

from .views import (
StatusListView, StatusCreateView, StatusUpdateView, StatusDeleteView
StatusCreateView,
StatusDeleteView,
StatusListView,
StatusUpdateView,
)

app_name = "statuses"

urlpatterns = [
path("", StatusListView.as_view(), name="statuses_index"),
path("create/", StatusCreateView.as_view(), name="statuses_create"),
path("<int:pk>/update/", StatusUpdateView.as_view(),
name="statuses_update"),
path("<int:pk>/delete/", StatusDeleteView.as_view(),
name="statuses_delete"),
path("", StatusListView.as_view(), name="index"),
path("create/", StatusCreateView.as_view(), name="create"),
path("<int:pk>/update/", StatusUpdateView.as_view(), name="update"),
path("<int:pk>/delete/", StatusDeleteView.as_view(), name="delete"),
]
17 changes: 9 additions & 8 deletions task_manager/statuses/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.views.generic import ListView, CreateView, UpdateView, DeleteView
from django.views.generic import CreateView, DeleteView, ListView, UpdateView

from .models import Status
from .forms import StatusForm
Expand All @@ -19,7 +19,7 @@ class StatusCreateView(LoginRequiredMixin, CreateView):
model = Status
form_class = StatusForm
template_name = "statuses/form.html"
success_url = reverse_lazy("statuses_index")
success_url = reverse_lazy("statuses:index")
login_url = "users:login"

def form_valid(self, form):
Expand All @@ -31,7 +31,7 @@ class StatusUpdateView(LoginRequiredMixin, UpdateView):
model = Status
form_class = StatusForm
template_name = "statuses/form.html"
success_url = reverse_lazy("statuses_index")
success_url = reverse_lazy("statuses:index")
login_url = "users:login"

def form_valid(self, form):
Expand All @@ -42,16 +42,17 @@ def form_valid(self, form):
class StatusDeleteView(LoginRequiredMixin, DeleteView):
model = Status
template_name = "statuses/confirm_delete.html"
success_url = reverse_lazy("statuses_index")
success_url = reverse_lazy("statuses:index")
login_url = "users:login"

def post(self, request, *args, **kwargs):
status = self.get_object()
if status.tasks.exists():
messages.error(request,
"Невозможно удалить статус, "
"потому что он используется")
return redirect("statuses_index")
messages.error(
request,
"Невозможно удалить статус, потому что он используется",
)
return redirect("statuses:index")
response = super().post(request, *args, **kwargs)
messages.success(request, "Статус успешно удален")
return response
13 changes: 6 additions & 7 deletions task_manager/tasks/filters.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# tasks/filters.py
import django_filters as df
from django import forms
from django.contrib.auth import get_user_model
from .models import Task
from task_manager.statuses.models import Status

from task_manager.labels.models import Label
from task_manager.statuses.models import Status
from task_manager.users.utils import format_user_display

from .models import Task

User = get_user_model()

Expand Down Expand Up @@ -40,10 +42,7 @@ def __init__(self, data=None, queryset=None, request=None, **kwargs):
super().__init__(data=data, queryset=queryset,
request=request, **kwargs)
self.request = request
self.filters["executor"].field.label_from_instance = (
lambda u: (u.get_full_name().strip()
if (u.get_full_name() or "").strip() else u.username)
)
self.filters["executor"].field.label_from_instance = format_user_display

def filter_self_tasks(self, queryset, name, value):
return queryset.filter(author=self.request.user) if value else queryset
9 changes: 4 additions & 5 deletions task_manager/tasks/forms.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from django import forms
from django.contrib.auth import get_user_model

from task_manager.users.utils import format_user_display

from .models import Task

User = get_user_model()
Expand Down Expand Up @@ -29,8 +32,4 @@ class Meta:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["executor"].queryset = User.objects.all().order_by("id")

def user_label(u):
full = (u.get_full_name() or "").strip()
return full if full else u.username
self.fields["executor"].label_from_instance = user_label
self.fields["executor"].label_from_instance = format_user_display
18 changes: 13 additions & 5 deletions task_manager/tasks/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.conf import settings
from django.db import models
from django.contrib.auth.models import User

from task_manager.labels.models import Label
from task_manager.statuses.models import Status
Expand All @@ -10,10 +10,18 @@ class Task(models.Model):
description = models.TextField(blank=True)
status = models.ForeignKey(Status, on_delete=models.PROTECT,
related_name="tasks")
author = models.ForeignKey(User, on_delete=models.PROTECT,
related_name="created_tasks")
executor = models.ForeignKey(User, on_delete=models.PROTECT, null=True,
blank=True, related_name="executed_tasks")
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
related_name="created_tasks",
)
executor = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
null=True,
blank=True,
related_name="executed_tasks",
)
created_at = models.DateTimeField(auto_now_add=True)
labels = models.ManyToManyField(Label, related_name="labeled_tasks",
blank=True)
Expand Down
19 changes: 13 additions & 6 deletions task_manager/tasks/urls.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
from django.urls import path

from .views import (
TaskListView, TaskCreateView, TaskUpdateView, TaskDeleteView, TaskDetailView
TaskCreateView,
TaskDeleteView,
TaskDetailView,
TaskListView,
TaskUpdateView,
)

app_name = "tasks"

urlpatterns = [
path("", TaskListView.as_view(), name="tasks_index"),
path("create/", TaskCreateView.as_view(), name="tasks_create"),
path("<int:pk>/", TaskDetailView.as_view(), name="tasks_detail"),
path("<int:pk>/update/", TaskUpdateView.as_view(), name="tasks_update"),
path("<int:pk>/delete/", TaskDeleteView.as_view(), name="tasks_delete"),
path("", TaskListView.as_view(), name="index"),
path("create/", TaskCreateView.as_view(), name="create"),
path("<int:pk>/", TaskDetailView.as_view(), name="detail"),
path("<int:pk>/update/", TaskUpdateView.as_view(), name="update"),
path("<int:pk>/delete/", TaskDeleteView.as_view(), name="delete"),
]
10 changes: 5 additions & 5 deletions task_manager/tasks/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.views.generic import CreateView, UpdateView, DeleteView, DetailView
from django.views.generic import CreateView, DeleteView, DetailView, UpdateView
from django_filters.views import FilterView

from .filters import TaskFilter
Expand Down Expand Up @@ -37,7 +37,7 @@ class TaskCreateView(LoginRequiredMixin, CreateView):
model = Task
form_class = TaskForm
template_name = "tasks/form.html"
success_url = reverse_lazy("tasks_index")
success_url = reverse_lazy("tasks:index")
login_url = "users:login"

def form_valid(self, form):
Expand All @@ -50,7 +50,7 @@ class TaskUpdateView(LoginRequiredMixin, UpdateView):
model = Task
form_class = TaskForm
template_name = "tasks/form.html"
success_url = reverse_lazy("tasks_index")
success_url = reverse_lazy("tasks:index")
login_url = "users:login"

def form_valid(self, form):
Expand All @@ -61,7 +61,7 @@ def form_valid(self, form):
class TaskDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
model = Task
template_name = "tasks/confirm_delete.html"
success_url = reverse_lazy("tasks_index")
success_url = reverse_lazy("tasks:index")
login_url = "users:login"

def test_func(self):
Expand All @@ -70,7 +70,7 @@ def test_func(self):
def handle_no_permission(self):
if self.request.user.is_authenticated:
messages.error(self.request, "Задачу может удалить только ее автор")
return redirect("tasks_index")
return redirect("tasks:index")
return super().handle_no_permission()

def post(self, request, *args, **kwargs):
Expand Down
4 changes: 2 additions & 2 deletions task_manager/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@

{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'statuses_index' %}">Статусы</a>
<a class="nav-link" href="{% url 'statuses:index' %}">Статусы</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'tasks_index' %}">Задачи</a>
<a class="nav-link" href="{% url 'tasks:index' %}">Задачи</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'labels:index' %}">Метки</a>
Expand Down
2 changes: 1 addition & 1 deletion task_manager/templates/statuses/confirm_delete.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ <h1>Удалить статус</h1>
<form method="post">
{% csrf_token %}
<button type="submit" class="btn btn-danger">Да, удалить</button>
<a href="{% url 'statuses_index' %}" class="btn btn-link">Отмена</a>
<a href="{% url 'statuses:index' %}" class="btn btn-link">Отмена</a>
</form>
{% endblock %}
2 changes: 1 addition & 1 deletion task_manager/templates/statuses/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ <h1>{% if object %}Изменить статус{% else %}Создать ста
<button type="submit" class="btn btn-primary">
{% if object %}Изменить{% else %}Создать{% endif %}
</button>
<a href="{% url 'statuses_index' %}" class="btn btn-link">Отмена</a>
<a href="{% url 'statuses:index' %}" class="btn btn-link">Отмена</a>
</form>
{% endblock %}
6 changes: 3 additions & 3 deletions task_manager/templates/statuses/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{% block content %}
<h1>Статусы</h1>

<p><a class="btn btn-primary" href="{% url 'statuses_create' %}">Создать статус</a></p>
<p><a class="btn btn-primary" href="{% url 'statuses:create' %}">Создать статус</a></p>

<table class="table table-striped align-middle">
<thead>
Expand All @@ -18,8 +18,8 @@ <h1>Статусы</h1>
<td>{{ st.id }}</td>
<td>{{ st.name }}</td>
<td class="text-end">
<a class="btn btn-sm btn-outline-secondary" href="{% url 'statuses_update' st.pk %}">Изменить</a>
<a class="btn btn-sm btn-outline-danger" href="{% url 'statuses_delete' st.pk %}">Удалить</a>
<a class="btn btn-sm btn-outline-secondary" href="{% url 'statuses:update' st.pk %}">Изменить</a>
<a class="btn btn-sm btn-outline-danger" href="{% url 'statuses:delete' st.pk %}">Удалить</a>
</td>
</tr>
{% empty %}
Expand Down
2 changes: 1 addition & 1 deletion task_manager/templates/tasks/confirm_delete.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ <h1>Удаление задачи</h1>
<form method="post">
{% csrf_token %}
<button type="submit" class="btn btn-danger">Да, удалить</button>
<a href="{% url 'tasks_index' %}" class="btn btn-link">Отмена</a>
<a href="{% url 'tasks:index' %}" class="btn btn-link">Отмена</a>
</form>
{% endblock %}
6 changes: 3 additions & 3 deletions task_manager/templates/tasks/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ <h1>{{ task.name }}</h1>
{% endif %}

<p class="mt-3">
<a class="btn btn-outline-secondary" href="{% url 'tasks_update' task.pk %}">Изменить</a>
<a class="btn btn-outline-danger" href="{% url 'tasks_delete' task.pk %}">Удалить</a>
<a class="btn btn-link" href="{% url 'tasks_index' %}">К списку</a>
<a class="btn btn-outline-secondary" href="{% url 'tasks:update' task.pk %}">Изменить</a>
<a class="btn btn-outline-danger" href="{% url 'tasks:delete' task.pk %}">Удалить</a>
<a class="btn btn-link" href="{% url 'tasks:index' %}">К списку</a>
</p>
{% endblock %}
2 changes: 1 addition & 1 deletion task_manager/templates/tasks/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ <h1>{{ object|default_if_none:"Создать задачу" }}</h1>

<button type="submit" class="btn btn-primary">
{% if object %}Изменить{% else %}Создать{% endif %}
</button> <a href="{% url 'tasks_index' %}" class="btn btn-link">Отмена</a>
</button> <a href="{% url 'tasks:index' %}" class="btn btn-link">Отмена</a>
</form>

{% endblock %}
8 changes: 4 additions & 4 deletions task_manager/templates/tasks/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{% block content %}
<h1>Задачи</h1>

<p><a class="btn btn-primary" href="{% url 'tasks_create' %}">Создать задачу</a></p>
<p><a class="btn btn-primary" href="{% url 'tasks:create' %}">Создать задачу</a></p>

{# Форма фильтров #}
<form method="get" class="row g-2 align-items-end mb-3">
Expand Down Expand Up @@ -51,7 +51,7 @@ <h1>Задачи</h1>
{% for t in tasks %}
<tr>
<td>{{ t.id }}</td>
<td><a href="{% url 'tasks_detail' t.pk %}">{{ t.name }}</a></td>
<td><a href="{% url 'tasks:detail' t.pk %}">{{ t.name }}</a></td>
<td>{{ t.status }}</td>
<td>{{ t.author.get_full_name|default:t.author.username }}</td>
<td>
Expand All @@ -62,8 +62,8 @@ <h1>Задачи</h1>
{% endif %}
</td>
<td class="text-end">
<a class="btn btn-sm btn-outline-secondary" href="{% url 'tasks_update' t.pk %}">Изменить</a>
<a class="btn btn-sm btn-outline-danger" href="{% url 'tasks_delete' t.pk %}">Удалить</a>
<a class="btn btn-sm btn-outline-secondary" href="{% url 'tasks:update' t.pk %}">Изменить</a>
<a class="btn btn-sm btn-outline-danger" href="{% url 'tasks:delete' t.pk %}">Удалить</a>
</td>
</tr>
{% empty %}
Expand Down
9 changes: 9 additions & 0 deletions task_manager/users/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Utilities for working with user objects."""

from typing import Any


def format_user_display(user: Any) -> str:
"""Return a human-friendly representation of a user."""
full_name = (user.get_full_name() or "").strip()
return full_name if full_name else user.get_username()