简体   繁体   中英

Django class based generic views: setting a field to initial value based on context

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM