0

I have a set of related models in a Django 1.5 app: Events that have EventSessions, and EventSessionRegistrations that belong to EventSessions.

I'm struggling to create a class based generic view for a user-facing registration form, where a user registers to attend an EventSession. Specifically the problem is around excluding the field for which EventSession the registration is for from being rendered in the form, whilst still setting that value based on the context and/or URL.

I'll try to explain via a use-case first:

  1. User goes to '/events/foo/bar', where foo is the Event, and bar is the EventSession.
  2. At this URL, there is a link to register for the EventSession, leading to '/events/foo/bar/register/'. Form for the EventSessionRegistration model is displayed, but without selecting the EventSession in the UI, since that information is already "set" by the URL.
  3. After successful form submission, user is redirected to a static "Thanks"-page.

To acheive this, I have the following view code (lots of other imports etc excluded):

from django.views.generic.edit import CreateView

class RegistrationCreate(CreateView):
    form_class = SessionRegistrationForm
    success_url = '/thanks/'
    template_name = 'events/registration_create.html'

    def get_context_data(self, *args, **kwargs):
        """Set the context of which Event, and which EventSession.
           Return 404 if either Event or EventSession is not public."""
        context = super(RegistrationCreate, self).get_context_data(**kwargs)
        s = get_object_or_404(
            EventSession,
            event__slug=self.kwargs['event_slug'],
            event__is_public=True,
            slug=self.kwargs['session_slug'],
            is_public=True)
        context['session'] = s
        context['event'] = s.event
        return context

URL pattern for this view (included from a base urls.py):

url(r'^(?P<event_slug>[\w-]+)/(?P<session_slug>[\w-]+)/register/$',
    RegistrationCreate.as_view(), name="event_session_registration"),

In the ModelForm, I've tried to convert the ForeignKey session on EventSessionRegistration field (pointing to EventSession) to show a HiddenInput()-widget:

class SessionRegistrationForm(forms.ModelForm):

    class Meta:
        model = EventSessionRegistration
        widgets = {
            'session': HiddenInput()
        }

But I still don't know how to set the initial value of that field to the id of the 'session' value that I set in get_context_data. I've tried setting self.initial = {'session': s.id} inside get_context_data, but I'm guessing that the initial attribute is already used to construct the form at that point.

Any ideas on the best way to acheive this? What am I missing?

Emil
  • 1,949
  • 2
  • 16
  • 25
  • But if you're getting a `EventSession` from the database it *should* already have an `id` so that you could do this in your template `session.id`. – Henrik Andersson Jun 28 '13 at 09:42
  • @limelights Yup, I've been playing around with that, creating a hidden `` and adding session.id to that, but then I had to exclude the `session` field from the form, causing Django to ignore that field anyway when the form is posted... – Emil Jun 28 '13 at 09:42

1 Answers1

2

Right, I found this question, which deals with the same issue. I ended up with the following overridden post-function in the view, and manually outputting the session id in the template in a hidden field:

def post(self, request, *args, **kwargs):
    self.object = None
    evt_session = get_object_or_404(
        EventSession, pk=int(self.request.POST['session']))
    form_class = self.get_form_class()
    form = self.get_form(form_class)

    form.instance.session = evt_session

    if form.is_valid():
        return self.form_valid(form)
    else:
        return self.form_invalid(form)

Also, I found ccbv.co.uk, which is a great resource for finding out about all the methods and attributes in CBV:s, which gave guidance as to how the override should be structured.

Community
  • 1
  • 1
Emil
  • 1,949
  • 2
  • 16
  • 25