Django网站创建日历事件出现405 Method Not Allowed错误求助
问题:创建日历事件时出现405 Method Not Allowed错误
管理员在创建日历事件时遭遇405错误,该功能在旧版Django中可正常运行,相关代码如下:
urls.py
from django.urls import path from main_website import views from main_website.views import (AboutView, ArticleCreateView, ArticleDeleteView, ArticleUpdateView, CalendarView, ContactUsView, DonateView, EditEventView, EventView, HelpUsView, ImageAddView, ImageCategoryAddView, ImageDetailView, ImageGalleryView, IndexView, SearchView, TaggedView) urlpatterns = [ path('', IndexView.as_view(), name='main_website_home'), path('about', AboutView.as_view(), name='main_website_about'), path('search/', SearchView.as_view(), name='main_website_search'), path('article_create', ArticleCreateView.as_view(), name='main_website_article_create'), path('article/<slug:slug>', views.article_detail, name='main_website_article_detail'), path('article/update/<slug:slug>/', ArticleUpdateView.as_view(), name='main_website_article_update'), path('article/delete/<slug:slug>/', ArticleDeleteView.as_view(), name='main_website_article_delete'), path('tags/<slug:slug>/articles/', TaggedView.as_view(), name="main_website_article_tags"), path('calendar/', CalendarView.as_view(), name='main_website_calendar'), path('calendar/event/new/', EventView.as_view(), name='main_website_calendar_new_event'), path('calendar/event/edit/<event_id>/', EditEventView.as_view(), name='main_website_calendar_edit_event'), path('waiting_list/register', views.waiting_list_register, name='main_website_waiting_list_register'), path('gallery', ImageGalleryView.as_view(), name='main_website_gallery'), path('gallery/upload', ImageAddView.as_view(), name='main_website_gallery_upload'), path('gallery/category/add/', ImageCategoryAddView.as_view(), name='main_website_gallery_add_category'), path('gallery/image/<str:pk>/', ImageDetailView.as_view(), name='main_website_gallery_image_detail'), path('help_us', HelpUsView.as_view(), name='main_website_help_us'), path('ways_to_donate', DonateView.as_view(), name='main_website_ways_to_donate'), path('contact_us', ContactUsView.as_view(), name='main_website_contact_us') ]
utils.py
import calendar from calendar import HTMLCalendar from datetime import date, datetime, timedelta from main_website.models import Event class Calendar(HTMLCalendar): def __init__(self, year=None, month=None): self.year = year self.month = month super(Calendar, self).__init__() # 格式化日期单元格 # 按日期筛选事件 def formatday(self, day, events): events_per_day = events.filter(start_time__day=day) d = '' for event in events_per_day: d += f'<li> {event.get_html_url} </li>' if day != 0: return f"<td><span class='date'>{day}</span><ul> {d} </ul></td>" return '<td></td>' # 格式化周行 def formatweek(self, theweek, events): week = '' for d, weekday in theweek: week += self.formatday(d, events) return f'<tr> {week} </tr>' # 格式化月日历表格 # 按年月筛选事件 def formatmonth(self, withyear=True): events = Event.objects.filter(start_time__year=self.year, start_time__month=self.month) cal = f'<table border="0" cellpadding="0" cellspacing="0" class="calendar">\n' cal += f'{self.formatmonthname(self.year, self.month, withyear=withyear)}\n' cal += f'{self.formatweekheader()}\n' for week in self.monthdays2calendar(self.year, self.month): cal += f'{self.formatweek(week, events)}\n' return cal def get_date(req_month): if req_month: year, month = (int(x) for x in req_month.split('-')) return date(year, month, day=1) return datetime.today() def prev_month(d): first = d.replace(day=1) prev_month = first - timedelta(days=1) month = 'month=' + str(prev_month.year) + '-' + str(prev_month.month) return month def next_month(d): days_in_month = calendar.monthrange(d.year, d.month)[1] last = d.replace(day=days_in_month) next_month = last + timedelta(days=1) month = 'month=' + str(next_month.year) + '-' + str(next_month.month) return month def get_filename(filename): return filename.upper()
views.py(日历相关代码)
import calendar from datetime import date, datetime, timedelta from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.db.models import Q from django.shortcuts import get_object_or_404, redirect, render from django.utils.safestring import mark_safe from django.views import generic from django.views.generic import CreateView, DeleteView, ListView, UpdateView from taggit.models import Tag from main_website.forms import (AddImageCategoryForm, ArticleForm, EventForm, UploadImageForm, WaitingListForm) from main_website.models import (Article, Event, ImageGallery, ImageGalleryCategory) from main_website.utils import Calendar, get_date, next_month, prev_month class CalendarView(generic.ListView): model = Event template_name = 'calendar/calendar.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) d = get_date(self.request.GET.get('month', None)) cal = Calendar(d.year, d.month) html_cal = cal.formatmonth(withyear=True) context['calendar'] = mark_safe(html_cal) context['prev_month'] = prev_month(d) context['next_month'] = next_month(d) context['title'] = 'Calendar' return context class EventView(LoginRequiredMixin, generic.View): def get(self, request, event_id=None): instance = Event() if event_id: instance = get_object_or_404(Event, pk=event_id) else: instance = Event() form = EventForm() context = { 'form': form, 'instance': instance, 'title': 'New Event', } return render(request, 'calendar/event.html', context) class EditEventView(LoginRequiredMixin, generic.View): def get(self, request, event_id=None): instance = Event() if event_id: instance = get_object_or_404(Event, pk=event_id) else: instance = Event() form = EventForm() context = { 'form': form, 'instance': instance, 'title': 'Edit Event', } return render(request, 'calendar/edit_event.html', context) def post(self, request): instance = Event() form = EventForm(request.POST or None, instance=instance) if form.is_valid(): form.save() return redirect('main_website_calendar')
forms.py(日历相关代码)
from django import forms from django.forms import DateInput from taggit.forms import TagField from taggit_labels.widgets import LabelWidget from accounts.models import User from main_website.models import (Article, Event, ImageGallery, ImageGalleryCategory, WaitingList) class EventForm(forms.ModelForm): class Meta: model = Event # 使用HTML5 datetime-local输入控件,指定格式让日期正常显示 widgets = { 'start_time': DateInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'), 'end_time': DateInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'), } fields = '__all__' def __init__(self, *args, **kwargs): super(EventForm, self).__init__(*args, **kwargs) # 设置输入格式,解析HTML5 datetime-local输入为Django datetime字段 self.fields['start_time'].input_formats = ('%Y-%m-%dT%H:%M',) self.fields['end_time'].input_formats = ('%Y-%m-%dT%H:%M',)
event.html
{% extends 'calendar/base.html' %} {% load crispy_forms_tags %} {% block content %} <div class="calendar-section"> <form method="POST"> {% csrf_token %} <legend class="border-bottom mb-4">Create New Event</legend> {{ form | crispy }} <button type="submit" class="btn btn-custom-purple"> <i class="fa-duotone fa-calendar-plus"></i> Submit </button> </form> <hr> <button class="btn btn-custom-purple"> <i class="fa-duotone fa-angles-left"></i> <a href="{% url 'main_website_calendar' %}"> Back to Calendar</a> </button> </div> {% endblock %}
问题原因及修复方案
核心问题
EventView类仅实现了get方法,未处理POST请求。当表单以POST方式提交时,视图没有对应处理逻辑,直接返回405错误。此外EditEventView的post方法也存在逻辑错误:总是创建新实例,未使用传入的event_id获取待编辑事件。
修复步骤
- 给
EventView添加post方法,同时修正get方法中表单未绑定实例的问题:
class EventView(LoginRequiredMixin, generic.View): def get(self, request, event_id=None): instance = get_object_or_404(Event, pk=event_id) if event_id else Event() form = EventForm(instance=instance) # 绑定实例,编辑时自动填充数据 context = { 'form': form, 'instance': instance, 'title': 'New Event', } return render(request, 'calendar/event.html', context) def post(self, request): form = EventForm(request.POST) if form.is_valid(): form.save() return redirect('main_website_calendar') # 表单验证失败时返回原页面并展示错误 return render(request, 'calendar/event.html', {'form': form, 'title': 'New Event'})
- 修正
EditEventView的post方法,绑定待编辑的事件实例:
class EditEventView(LoginRequiredMixin, generic.View): def get(self, request, event_id=None): instance = get_object_or_404(Event, pk=event_id) if event_id else Event() form = EventForm(instance=instance) context = { 'form': form, 'instance': instance, 'title': 'Edit Event', } return render(request, 'calendar/edit_event.html', context) def post(self, request, event_id): instance = get_object_or_404(Event, pk=event_id) form = EventForm(request.POST, instance=instance) if form.is_valid(): form.save() return redirect('main_website_calendar') return render(request, 'calendar/edit_event.html', {'form': form, 'instance': instance, 'title': 'Edit Event'})
- 推荐优化:使用Django内置的
CreateView和UpdateView简化代码,减少重复逻辑:
# 替换原EventView class EventView(LoginRequiredMixin, CreateView): model = Event form_class = EventForm template_name = 'calendar/event.html' success_url = reverse_lazy('main_website_calendar') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['title'] = 'New Event' return context # 替换原EditEventView class EditEventView(LoginRequiredMixin, UpdateView): model = Event form_class = EventForm template_name = 'calendar/edit_event.html' success_url = reverse_lazy('main_website_calendar') pk_url_kwarg = 'event_id' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['title'] = 'Edit Event' return context
内容的提问来源于stack exchange,提问作者Kiran Sarda
相关产品推荐
相关产品推荐

