1

我正在制作一个使用 ListView 显示事件的网站,每个事件都有一个注册表单。

表单验证错误都出现了,但是在成功提交表单后,它只是将我带到成功页面并且表单没有保存到数据库中。

当我通过管理员而不是表单提交表单时,它给了我一个错误:NameError at /admin/home/signups/add/ global name 'fullname' is not defined with traceback to: instance.fullname = fullname in forms.py .

如果我完全删除该行,另一个错误是:/admin/home/signups/add/ 全局名称'request' 处的NameError 未定义回溯到forms.py 中的instance.ip = get_ip(request)。

表格.py:

from django import forms
from .models import SignUps, Hours, Events
import datetime
from ipware.ip import get_ip

class SignUpForm(forms.ModelForm):
    fullname = forms.CharField(label="Full name", widget=forms.TextInput(attrs={'placeholder': 'Full name', 'class': 'form-control'}))

    class Meta:
        model = SignUps
        fields = ['eventname','fullname','ip']

    def clean_fullname(self):
        fullname = self.cleaned_data.get('fullname').title()
        eventname = self.cleaned_data.get('eventname')
        try:
            name = Hours.objects.get(fullname=fullname)
        except Hours.DoesNotExist:
            raise forms.ValidationError("Please enter a valid Key Club member's full name as displayed in the hours page.")
        try:
            name = SignUps.objects.get(fullname=fullname)
        except SignUps.DoesNotExist:
            try:
                numOfSignUps = SignUps.objects.filter(eventname=eventname).count()
            except SignUps.DoesNotExist:
                numOfSignUps = 0
            try:
                event = Events.objects.get(name=eventname)
            except Events.DoesNotExist:
                raise forms.ValidationError("Something went wrong. This event does not exist.")
            try:
                ifFull = Events.objects.filter(name=eventname).get(maximum__gt=numOfSignUps)
            except Events.DoesNotExist:
                raise forms.ValidationError("The maximum number of attendees has already been reached.")
            try:
                date = Events.objects.filter(name=eventname).get(date=datetime.date.today())
            except Events.DoesNotExist:
                return fullname
            raise forms.ValidationError("It is too late to sign up for this event.")
        raise forms.ValidationError("This member is already signed up.")

    def save(self, commit=True):
        instance =  super(SignUpForm, self).save(commit=False)
        instance.fullname = fullname
        instance.ip = get_ip(request)
        if commit:
            instance.save()
        return instance

events/index.html 主体:

<div class="container" style="margin-top:75px;">

    {% block content %}

    {% for announcements in announcement %}
    <div class="alert alert-info" role="alert">
      <h4 class="alert-heading">{{ announcements.announcementname }}</h4>
      <p style="margin:0 0;">{{ announcements.announcement | safe | linebreaksbr | urlize }}</p>
    </div>
    {% endfor %}

    {% for events in events_list %}
    <div id="checkIn" class="modal fade">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
              <span aria-hidden="true">&times;</span>
            </button>
            <h4 class="modal-title">OCC Check-Ins</h4>
          </div>
          <div class="modal-body">
            <form method="POST">
              <div class="form-group">
                <input type="password" class="form-control" id="passcode" placeholder="Passcode" maxlength="4" autocomplete="off">
              </div>
              <div class="form-group"><button type="submit" class="btn btn-primary btn-block">Sign in</button></div>
            </form>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
          </div>
        </div><!-- /.modal-content -->
      </div><!-- /.modal-dialog -->
    </div><!-- /.modal -->

    <div class="card card-block col-sm-6" style="display:inline-block;">
      <div class="dropdown" style="float:right;">
        <a href="#" style="color:black;" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><h5><i class="fa fa-caret-down" aria-hidden="true"></i></h5></a>
        <div class="dropdown-menu dropdown-menu-left" aria-labelledby="dropdownMenuButton" style="right:0;left:auto;">
          <a class="dropdown-item" href="#">View</a>
        </div>
      </div>
      <h4 class="card-title">{{ events.name }}</h4>
      <p class="card-text">Description: <span class="text-muted">{{ events.description }}</span><br>Where: <a href="https://www.google.com/maps/place/{{ events.location }}" class="text-muted">{{ events.location }}</a><br>When: <span class="text-muted">{{ events.date|date:"D, M d, Y" }}</span><br>Time: <span class="text-muted">{{ events.time|time:"P" }}</span><br>Max: <span class="text-muted">{{ events.maximum }}</span><br>Hours: <span class="text-muted">{{ events.hours }}</span><br>Check in with: <span class="text-muted">{{ events.occ }}</span></p>
      <h4 class="card-text" style="margin-top:-6px;margin-bottom:8px;"><a href="#" style="color:black; text-decoration:none;" data-toggle="modal" data-target="#checkIn"><i class="fa fa-sign-in" aria-hidden="true" style="margin-bottom:10px;"></i> OCC Check-Ins</a></h4>
      <form action="/events/" class="form" method="POST">{% csrf_token %}
        <div class="form-group">
          <input id="id_eventname" maxlength="125" name="eventname" type="hidden" value="{{ events.name }}">
          {{ form.fullname }}
          {{ form.fullname.errors }}
        </div>
        <button class="btn btn-primary btn-block" type="submit">Sign up</button>
      </form>
    </div>
    {% endfor %}
    {% endblock %}

  </div>

success.html 只是一个显示“成功”的空白 HTML 页面:

<div class="container" style="margin-top:75px;">
    Success
  </div>

视图.py:

from django.shortcuts import render
from django.views.generic import ListView, FormView
from django.views.generic.detail import SingleObjectMixin
from home.models import Events, Announcement, Hours, SignUps
from django import forms
from .forms import SignUpForm
from django.http import HttpResponseForbidden
from django.urls import reverse
from django.views import View
from ipware.ip import get_ip
from django.views.generic.edit import FormView

# Create your views here.
def index(request):
    return render(request, 'home/index.html')

def about(request):
    return render(request, 'about/index.html')

def success(request):
    return render(request, 'events/success.html')

class EventsDisplay(ListView, FormView):
    template_name='events/index.html'
    context_object_name = "events_list"
    queryset = Events.objects.all().order_by("date")
    form_class = SignUpForm
    success_url = "/events/success"

    def get_context_data(self, **kwargs):
        self.object_list = self.get_queryset()
        context = super(EventsDisplay, self).get_context_data(**kwargs)
        context['announcement'] = Announcement.objects.all().order_by("-datetime")
        context['signup'] = SignUps.objects.all().order_by("fullname")
        return context

class HoursList(ListView):
    template_name = 'hours/index.html'
    context_object_name = "hours_list"
    queryset = Hours.objects.all().order_by("fullname")

    def get_context_data(self, **kwargs):
        context = super(HoursList, self).get_context_data(**kwargs)
        context['announcement'] = Announcement.objects.all().order_by("-datetime")
        return context

网址.py:

from django.conf.urls import url, include
from views import EventsDisplay, HoursList
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^events/$', EventsDisplay.as_view()),
    url(r'^events/success$', views.success, name='success'),
    url(r'^hours/$', HoursList.as_view()),
    url(r'^about/$', views.about, name='about'),
]
4

2 回答 2

0

当您在 中遇到验证错误时SignUpForm,您的SignUp(request)函数确实会拾取form对象中的错误,但您返回的页面 ( events/success.html) 与返回的页面GET( ) 不同events/index.html

我假设它events/success.html没有您提供的相同的 html 代码,这似乎是用于events/index.html.

您的SignUp(request)函数应如下所示:

def SignUp(request):
    if request.method=='POST':
        form = SignUpForm(request.POST or None)
        if form.is_valid():
            instance = form.save(commit=False)
            fullname = form.cleaned_data.get("fullname")
            instance.fullname = fullname
            instance.ip = get_ip(request)
            instance.save()
        else: # INVALID FORM - WE HAVE VALIDATION ERRORS SO RETURN SAME PAGE.
            return render(request, "events/index.html", {"form": form})

    else:
        form = SignUpForm
    context = {
        "form": form,
    }
    return render(request, "events/success.html", context)
于 2016-12-04T03:59:23.547 回答
0

好的,在仔细审查了代码之后,我相信这里可以进行更多的重构。

首先,我看不到将基于类的视图和基于函数的视图混为一谈的意义。这些标准getpost要求可以这样完成:

from django.shortcuts import render
from django.views.generic import ListView, FormView
from django.views.generic.detail import SingleObjectMixin
from home.models import Events, Announcement, Hours, SignUps
from django import forms
from .forms import SignUpForm
from django.http import HttpResponseForbidden
from django.urls import reverse
from django.views import View
from ipware.ip import get_ip
from django.views.generic.edit import FormView

class EventsDisplay(ListView, FormView):
    template_name='events/index.html'
    context_object_name = "events_list"
    queryset = Events.objects.all().order_by("date")
    form_class = SignUpForm 
    success_url = "events/success.html"

    def get_context_data(self, **kwargs):
        context = super(EventsDisplay, self).get_context_data(**kwargs)
        context['announcement'] = Announcement.objects.all().order_by("-datetime")
        # No need to insert 'form' as Django  takes care of that
        # by utilising self.form_class
        return context

    def form_valid(self, form): 
        instance = form.save(commit=False) instance.save() 
        return super(EventsDisplay, self).form_valid(form)

基本上,我已将您的代码合并到一个基于类的视图中,该视图继承自ListView(针对您的get请求)和FormView(针对您的post请求)。

由于您的观点发生了这种变化,您urls现在应该成为:

from django.conf.urls import url, include
from views import EventsList, HoursList
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^events/$', EventsDisplay.as_view()),
    url(r'^hours/$', HoursList.as_view()),
    url(r'^about/$', views.about, name='about'),
]

最后,如果您必须在保存之前“刺激”您的模型变量(例如,插入 ip 地址),您应该将这种代码放在这样的表单中:

from django import forms
from .models import SignUps, Hours, Events
import datetime
from ipware.ip import get_ip
class SignUpForm(forms.ModelForm):
    fullname = forms.CharField(label="Full name", widget=forms.TextInput(attrs={'placeholder': 'Full name', 'class': 'form-control'}))

    class Meta:
        model = SignUps
        fields = ['eventname','fullname','ip']

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super(SignUpForm, self).__init__(*args, **kwargs)

    def clean_fullname(self):
        ...

    def save(self, commit=True):
        instance =  super(SignUpForm, self).save(commit=False)
        instance.fullname = fullname
        instance.ip = get_ip(self.request)
        if commit:
            instance.save()
        return instance
于 2016-12-04T05:03:32.023 回答