Как мне решить эту странную ошибку первичного ключа в Django? - PullRequest
0 голосов
/ 06 мая 2020

У меня есть приложение со списком Django дел. В этом приложении есть страница со всеми подробностями о задаче, такими как подзадачи, примечания и т. Д. c. URL этой страницы имеет вид «/ todo / name of task». Я использую sh, чтобы передать ПК задачи по соображениям безопасности. Кроме того, если я проверю задачу в базе данных с ее pk вместе с заголовком, это позволит пользователю иметь несколько задач с одинаковым именем. Но как только я передаю pk с URL-адресом, я сталкиваюсь со странными проблемами с подзадачами и заметками. Это моя функция просмотра, которая обрабатывает страницу задачи:

def todo_detail(request, title):
    try:
        todo = ToDo.objects.get(title=title, creator=request.user)
    except:
        return render(request, "ToDo/restrict_access.html")

    subtasks = SubTask.objects.filter(parent_task=todo)

    try:
        note = Notes.objects.get(parent_task=todo)
    except:
        note = Notes()

    if request.method == "POST":
        note_form = ToDoNotesForm(request.POST)
        subtask_form = SubTaskForm(request.POST)
        due_form = DueDateForm(request.POST)

        if note_form.is_valid():
            task_notes = note_form.cleaned_data.get("task_notes")

            new_note = Notes(content=task_notes)
            new_note.parent_task = todo
            new_note.save()

            todo.has_notes = True
            todo.save()

            messages.success(request, "Your notes are saved")

            return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))

        elif subtask_form.is_valid():
            subtask_title = subtask_form.cleaned_data.get("sub_task")

            subtask = SubTask(title=subtask_title)
            subtask.parent_task = todo

            subtask.parent_task.num_of_subtasks += 1
            subtask.parent_task.save()

            subtask.save()

            messages.success(request, "Subtask added")

            return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))

        elif due_form.is_valid():
            days = due_form.cleaned_data.get("due_date").lower()

            if days == "today":
                days = 0
            elif days == "tomorrow":
                days = 1
            elif days == "next week":
                days = 7
            elif days == "yesterday":
                days = -1
            elif days == "last week":
                days = -7
            else:
                days = int(days)

            today = datetime.datetime.today()
            due_date = today + datetime.timedelta(days=days)

            todo.due_date = due_date
            todo.save()

            messages.success(request, "Due Date added to task")

            return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))

    else:
        note_form = ToDoNotesForm()
        subtask_form = SubTaskForm()
        due_form = DueDateForm()

    context = {
        "todo": todo,
        "note_form": note_form,
        "note": note,
        "subtask_form": subtask_form,
        "subtasks": subtasks,
        "due_form": due_form,
        "title": todo.title,
        "percentage": percentage
    }

    return render(request, "ToDo/detailed_view.html", context=context)

На странице сведений есть ссылки для проверки, снятия отметки или редактирования подзадачи или редактирования заметок. На странице html я передал только соответствующий pk для функций редактирования или проверки.

There were some HTML code here that is not relevent

    {% if subtasks %}
        <br><br>
        <center style="font-size:27px; background-color: burlywood; color: 'black';">Subtasks for this task:</center>
        <br>
        <div style="padding-left: 4ch;">
            {% for subtask in subtasks %}
                <div class="content-section dark-mode-assist-section">
                    {% if not subtask.done %}
                        {% if request.user_agent.is_mobile %}
                            <li style="font-size: 23px;">
                                <a style="color:inherit; text-decoration: none;" href="{% url 'todo-edit-subtask' subtask.pk %}"> {{ subtask.title }} </a>
                                <br>
                                <button onclick="location.href='{% url 'todo-toggle-subtask' subtask.pk %}'" type="button" class="btn btn-outline-success">Check it off</button>
                                <button onclick="location.href='{% url 'delete-item' 'subtask' subtask.pk %}'" type="submit" class="btn btn-outline-danger">Delete</button> 
                            </li>
                        {% else %}
                            <li style="font-size: 23px;">
                                <a style="color:inherit; text-decoration: none;" href="{% url 'todo-edit-subtask' subtask.pk %}"> {{ subtask.title }} </a> 
                                <button onclick="location.href='{% url 'todo-toggle-subtask' subtask.pk %}'" style="float: right; size:3ch" type="button" class="btn btn-outline-success">Check it off</button> 
                                <button onclick="location.href='{% url 'delete-item' 'subtask' subtask.pk %}'" style="float: right; size:3ch" type="submit" class="btn btn-outline-danger">Delete</button> 
                            </li>
                        {% endif %}
                    {% else %}
                        {% if request.user_agent.is_mobile %}
                            <li style="font-size: 23px;">
                                <a style="color:inherit; text-decoration: line-through;" href="{% url 'todo-edit-subtask' subtask.pk %}"> {{ subtask.title }} </a>
                                <br>
                                <button onclick="location.href='{% url 'todo-toggle-subtask' subtask.pk %}'" type="button" class="btn btn-outline-success">Uncheck it </button> 
                                <button onclick="location.href='{% url 'delete-item' 'subtask' subtask.pk %}'" type="submit" class="btn btn-outline-danger">Delete</button> 
                            </li>
                        {% else %}
                            <li style="font-size: 23px;"><a class="control-subtask" style="color:inherit; text-decoration: line-through;" href="{% url 'todo-edit-subtask' subtask.pk %}"> {{ subtask.title }} </a> <button onclick="location.href='{% url 'todo-toggle-subtask' subtask.pk %}'" style="float: right; size:3ch" type="button" class="btn btn-outline-success">Uncheck it</button> <button onclick="location.href='{% url 'delete-item' 'subtask' subtask.pk %}'" style="float: right; size:3ch" type="submit" class="btn btn-outline-danger">Delete</button> </li>
                        {% endif %}
                    {% endif %}
                </div>
            {% endfor %}
            {% if percentage != 0 %}
                <center style="font-size:23px; background-color: burlywood; color: 'black';">Your progress:</center>
                <center> <span style="font-size:10ch; color:lightseagreen">{{ percentage }}%</span></center>
            {% endif %}
        </div>
    {% endif %}

    {% if todo.has_notes %}
        <br>
        <center style="font-size:27px; background-color: burlywood; color: 'black';">Notes for this task:</center>
        <h3>
            <br>
            <div style="font-family:Candara">{{ note.content|linebreaks }}</div>
            <button class="btn btn-outline-danger" type="submit" onclick="location.href='{% url 'delete-item' 'notes' note.pk %}'">Delete notes</button>
            <button class="btn btn-outline-info" type="submit" onclick="location.href='{% url 'todo-edit-notes' note.pk %}'">Edit notes</button>
        </h3>
        <p>
            <br>
            Notes added on: <b>{{ note.date_added|date:"F d, Y" }}</b>
            <br>

            {% if note.date_edited != note.date_added %}
                Notes edited on: <b>{{ note.date_edited|date:"F d, Y" }}</b>
            {% endif %}
        </p>

    {% else %}

        <br>
        <form method="POST" name={{ note.pk }} >
            {% csrf_token %}
            <fieldset class="form-group dark-mode-assist">
                <legend class="border-bottom mb-4">Add notes</legend>
                {{ note_form|crispy }}
                <input type="hidden" name="title" value={{ note.pk }}>
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Add</button>
            </div>
        </form>

    {% endif %}
</div>

{% endblock content %}

Пока я передаю только заголовок на страницу сведений, все остальные ссылки работают. Но если я передаю ПК задачи на страницу сведений и хочу проверить конкретную подзадачу, то произойдет следующее: enter image description here

Как вы можете видеть ПК после toggle-subtask - это ПК для этой подзадачи, но Django сообщает, что не может найти объект ToDo? Для проверки подзадачи существует другой URL-адрес, который не связан со страницей сведений. В этом нет смысла.

Мы будем очень благодарны за любую помощь по этому вопросу. Спасибо всем.

Изменить: это моя функция просмотра, которая проверяет и снимает отметку с подзадачи:

@login_required
def toggle_subtask(request, pk):
    try:
        subtask = SubTask.objects.get(pk=pk)
        # Security check
        if subtask.parent_task.creator != request.user:
            return render(request, "ToDo/restrict_access.html")
    except:
        return render(request, "ToDo/restrict_access.html")



    if subtask.done:
        subtask.done = False
        subtask.save()

        messages.info(request, "Okay, take your time!")

    else:

        subtask.done = True
        subtask.save()

        messages.info(request, "Awesome!")

    return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))

Так что, очевидно, я должен был получить ошибку в первую очередь при просмотре деталей страницу, если ToDo не найдено. Но я смог попасть на страницу с подробностями. Проблема в том, что когда я хочу проверить подзадачу, они говорят, что ToDo не найдено, но на самом деле я проверяю SubTask, а не ToDo.

Ответы [ 2 ]

1 голос
/ 06 мая 2020

Ваша функция просмотра toggle_subtask не маршрутизируется, потому что todo_detail направляется первой.

Из документов django в Как Django обрабатывает запрос :

Django запускает по каждому шаблону URL в порядке и останавливается на первом, который соответствует запрошенному URL, сопоставляя его с path_info.

В вашем файле urls.py вы можете структурировать URL-адреса так, чтобы наиболее точные c (например, /todo/toggle_subtask/<pk>/) были перед наименее конкретными c (например, /todo/<title>/):

from django.urls import path

from . import views  # Wherever your `views.py` should be imported from

urlpatterns = [
    # /todo/toggle_subtask/<pk>/
    path('/todo/toggle_subtask/<int:pk>/', views.toggle_subtask),
    # /todo/<title>/
    path('/todo/<str:title>/', views.todo_detail),
]
0 голосов
/ 06 мая 2020

Поскольку первый запрос не соответствует базе данных. Вы получили эту ошибку. Итак, вы можете использовать ToDo.DoesNotExist для отслеживания исключения, например:

    try:
        todo = ToDo.objects.get(title=title, creator=request.user)
    except ToDo.DoesNotExist:
        return render(request, "ToDo/restrict_access.html")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...