2016-12-04 2 views
1

Je crée un site web qui montre des événements en utilisant un ListView et chaque événement a un formulaire d'inscription.Django - Le formulaire ne sauvegarde pas

Les erreurs de validation de formulaire s'affichent toutes, mais après la soumission réussie du formulaire, cela m'amène simplement à la page de réussite et le formulaire n'est pas enregistré dans la base de données.

Quand je soumets le formulaire par admin et non la forme, il me donne une erreur: NameError à/admin/home/inscriptions/ajouter/ nom global « fullname » est pas défini avec retraçage à: instance.fullname = nom complet dans forms.py.

Une autre erreur si je supprimer complètement cette ligne est: NameError à/admin/home/signups/ajouter/ nom global 'demande' est pas définie avec retraçage à instance.ip = get_ip (demande) forms.py .

forms.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 

événements/index.html corps principal:

<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 est juste une page HTML vide qui dit "succès":

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

views.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 

urls.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'), 
] 

Répondre

1

Bon alors après avoir examiné le code un peu juste, je crois qu'il pourrait y avoir beaucoup plus refactoring fait ici. Tout d'abord, je ne vois pas l'intérêt de mélanger les vues basées sur les classes et une vue basée sur les fonctions. Ces demandes standards get et post peut se faire comme ceci:

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) 

Fondamentalement, j'ai fusionné votre code dans une vue unique sur la base de classe qui hérite de ListView (pour vos get demandes) et FormView (pour vos post demandes) .

En raison de ce changement de votre point de vue, votre urls devrait maintenant devenir:

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'), 
] 

Enfin, si vous devez « prod » vos variables du modèle avant d'enregistrer (par exemple.insérer l'adresse IP), vous devez placer ce genre de code dans la forme comme ceci:

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 
+0

Lorsque je soumets le formulaire, il me donne une erreur: AttributeError at/events/ L'objet 'EventsDisplay' n'a pas d'attribut 'object_list'. Traceback va à: context = super (EventsDisplay, self) .get_context_data (** kwargs) dans views.py –

+0

Au lieu d'utiliser 'object_list' dans votre code html, utilisez maintenant' events_list'. Le 'context_object_name' vous permet d'utiliser un nom plus spécifique dans les templates plutôt que d'utiliser un nom général et sans signification comme' object_list'. –

+0

La même erreur se produit toujours. –

0

Lorsque vous cliquez sur une erreur de validation dans SignUpForm, votre fonction SignUp(request) ne vous chercher les erreurs dans l'objet form mais vous retournez une autre page (events/success.html) de ce que votre GET renvoie (events/index.html).

Je suppose que events/success.html n'a pas le même code html que celui que vous avez fourni qui semble être events/index.html.

Votre fonction SignUp(request) devrait ressembler à ceci:

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) 
+0

Je viens de changer pour des événements/index.html mais quand je fais cela, les éléments du ListView ne se présentent pas si mon index.html ne montre essentiellement que la barre de navigation et le pied de page. –

+0

Pouvez-vous fournir à la fois votre index et vos fichiers html de succès? –

+0

Je viens de mettre à jour la question pour inclure le corps entier de l'index.html à l'exclusion de la barre de navigation et du pied de page. Ma page de succès.html est vide et dit simplement "succès". –