Prometheus
Prometheus

Reputation: 33625

Best practices on saving in a view, based on example code

I'm new to Django and looking for best practices on the code I just wrote (below). The code currently exists in my view.py and simply creates a new event. Being familiar with other languages it just 'smells bad' if you know what I mean. Could someone point out how they would do this simple task.

The only thing looking at my code again (and from reading the docs a little more), would be to move the request.user into the models.py save function.

Anything else which is a big newbie mistake below?

@login_required
def event_new(request):
    # If we had a POST then get the request post values.
    if request.method == 'POST':
        form = EventForm(request.POST)
        # Check we have valid data
        if form.is_valid():
            # If form has passed all validation checks then continue to save it.
            city = City.objects.get(name=form.cleaned_data['autocompleteCity'])
            category = form.cleaned_data['category']
            event = Event(
                name=form.cleaned_data['name'],
                details=form.cleaned_data['details'],
                date=form.cleaned_data['date'],
                start=form.cleaned_data['start'],
                end=form.cleaned_data['end'],
                category=category,
                city=city,
                user=request.user,
            )
            event.save()

            messages.add_message(request, messages.SUCCESS, 'Event has been created.')
            return HttpResponseRedirect('/events/invite/')
        else:
            messages.add_message(request, messages.ERROR, 'Error')
            context = {'form': form}
            return render_to_response('events/event_edit.html', context, context_instance=RequestContext(request))
    else:
        form = EventForm

    context = {'form': form}
    return render_to_response('events/event_edit.html', context, context_instance=RequestContext(request))

Upvotes: 1

Views: 270

Answers (2)

bikeshedder
bikeshedder

Reputation: 7487

You should read about create forms from models. The ModelForm class will save you from copying the fields from the form to the model.

Apart from that this view looks pretty normal to me.

You can even get rid of some of the boilerplate code (if request.method == "POST", if form.is_valid(), etc.) with the generic FormView or CreateView. Since you seam to have some special form handling it might not be of any use for you, but it might be worth a look.

This code is not 100% complete (your special logic for cities is missing) but apart from that should be pretty complete and give you an idea how generic views could be used.

forms.py

from django.forms import ModelForm

class EventForm(ModelForm):

    def __init__(self, user, **kwargs):
        self.user = user
        super(EventForm, self).__init__(**kwargs)

    class Meta:
        model = Event

    def save(self, commit=True):
        event = super(EventForm, self).save(commit=False)
        event.user = self.user
        if commit:
            event.save()

views.py

from django.views.generic.edit import CreateView

class EventCreate(CreateView):
    model = Event
    form_class = EventForm
    template = "events/event_edit.html"
    success_url = "/events/invite/" # XXX use reverse()

    def get_form(form_class):
        return form_class(self.request.user, **self.get_form_kwargs())

    def form_valid(form):
        form.user = self.request.user

        messages.success(request, 'Event has been created.')
        super(EventCreate, self).form_valid(form)

    def form_invalid(form):
        messages.error(request, 'Error')
        super(EventCreate, self).form_invalid(form)

urls.py

url(r'event/add/$', EventCreate.as_view(), name='event_create'),

Upvotes: 4

markdsievers
markdsievers

Reputation: 7309

I think this looks great. You have followed the conventions from the docs nicely.

Moving request.user to a model would certainly be an anti pattern - a views function is to serve in the request/response loop, so access this property here makes sense. Models know nothing of requests/responses, so it's correct keep these decoupled from any view behavior.

Only thing that I noticed was creating a category variable out only to be used in construction of the Event, very minor.

Upvotes: 1

Related Questions