CreateView set foreign key from URL parameter I want to be able to create a lorum, using a ipsum_id (ForeignKey) that has been supplied in the URL. Using Django's class based views.

Given the following URL:

url(r'^lorem/create/ipsum/(?P&lt;ipsum_id&gt;\d+)/$', LoremCreateView.as_view(), name='create'),


I have the following view:

class LoremCreateView(CreateView):
    """ Allow a user to create a Lorem. """
    model = Lorem
    ...

    def get_context_data(self, **kwargs):
        """ Get context variables for rendering the template. """
        ipsum = get_object_or_404(Ipsum, pk=self.kwargs['ipsum_id'])
        kwargs['ipsum'] = ipsum
        return super().get_context_data(**kwargs)

    def form_valid(self, form):
        """ Save the form instance. """
        ipsum = get_object_or_404(Ipsum, pk=self.kwargs['ipsum_id'])
        form.instance.ipsum = ipsum
        return super().form_valid(form)


This works fine, however I don't like the fact I call get_object_or_404 twice.

Is there a better way of doing this?

It might be possible to override an appropriate method and set self.ipsum - not sure I like doing this either.

Also is get_object_or_404 appropriate here?
There's no need to add the ipsum instance to the template context unless it's used in the template. Adding things to self is the cleanest way.

Using get_object_or_404 is appropriate if we require the ipsum instance to exist in order to save a lorem.

You should end up with something like this:

# urls.py

from django.urls import path

urlpatterns = [
    path('lorem/create/ipsum/&lt;int:ipsum_id&gt;/', LoremCreateView.as_view(), name='create'),
]


&nbsp;

# views.py

class LoremCreateView(CreateView):
    model = Lorem

    def dispatch(self, request, *args, **kwargs):
        """
        Overridden so we can make sure the `Ipsum` instance exists
        before going any further.
        """
        self.ipsum = get_object_or_404(Ipsum, pk=kwargs['ipsum_id'])
        return super().dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        """
        Overridden to add the ipsum relation to the `Lorem` instance.
        """
        form.instance.ipsum = self.ipsum
        return super().form_valid(form)