# Passing slug to CreateView

**URL:** <https://forum.djangoproject.com/t/passing-slug-to-createview/4287>\
**Category:** Forms & APIs\
**Created:** [September 10, 2020, 2:12pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287 "2020-09-10T14:12:18Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![iFunction](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ifunction/32/1941_2.png) [@iFunction](https://forum.djangoproject.com/u/iFunction)\
**Post date:** [September 10, 2020, 2:12pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/1 "2020-09-10T14:12:18Z")

</div>

I’m trying to refactor a view from a function based view to a class based view. This view is a comment on a post, so I’m not sure if I am using the right view. Intuitively, I expected CreateView to be the right one, but it doesn’t seem to pass the slug to it:

```auto
class ProjectCommentView(CreateView):
    template_name = 'Project/project_comment.html'
    form_class = ProjectCommentForm
    queryset = Project.objects.all()
    successurl = '/home/'

    def get_object(self):
        slug = self.kwargs.get("slug")
        return get_object_or_404(Project, slug=slug)

```

The above code results in all the links on the page this is included in, with NoReverseMatch for links in the page. How can I fix this?

---

<div class="post-metadata">

**Author:** ![Suttonium](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/suttonium/32/1264_2.png) [@Suttonium](https://forum.djangoproject.com/u/Suttonium)\
**Post date:** [September 10, 2020, 2:38pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/2 "2020-09-10T14:38:32Z")

</div>

This may sound odd, but what is your original function view doing? Are you creating the comment or are you trying to display the comment? Posting your original FBV may be beneficial so we can try and diagnose the issue.

---

<div class="post-metadata">

**Author:** ![iFunction](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ifunction/32/1941_2.png) [@iFunction](https://forum.djangoproject.com/u/iFunction)\
**Post date:** [September 10, 2020, 4:43pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/3 "2020-09-10T16:43:55Z")

</div>

Yes, no problem this is my original function, I was just trying to build it up slowly:

```
def project_comment_view(request, slug):
    obj = Project.objects.get(slug=slug)
    if request.method == 'POST':
        form = ProjectCommentForm(request.POST)
        form.instance.project = obj
        if form.is_valid():
            task_complete = form.cleaned_data['task_complete']
            category = form.cleaned_data['category']
            if task_complete is True:
                CategorySatisfied.objects.create(
                        project=obj, update_category=category)
                form.save()
                return redirect('project-list', 'my-projects')
    else:
        form = ProjectCommentForm()
    context = {
        'form': form,
        'object': obj,
    }
    return render(request, 'project/project_commnet.html', context)

```

and while I’m here, here is the form that goes with it if that helps, it uses crispyforms:

```
class ProjectCommentForm(forms.ModelForm):
    def __init__ (self, *args, **kwargs):
        super(). __init__ (*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_method = 'POST'
        self.helper.add_input(
            Submit(
                'Update',
                'Update',
                css_class='btn-primary'
            )
        )
    
    task_complete = forms.BooleanField(initial=False, required=False, label='Task Complete')

    class Meta:
        model = Comment
        fields = [
            'category',
            'comment',
        ]
```

---

<div class="post-metadata">

**Author:** ![Suttonium](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/suttonium/32/1264_2.png) [@Suttonium](https://forum.djangoproject.com/u/Suttonium)\
**Post date:** [September 10, 2020, 5:15pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/4 "2020-09-10T17:15:10Z")

</div>

Because of the extra logic you’re using for this function, you may want to just inherit from the `View` class that `CreateView` uses behind the scenes. You can use the `get(self, *args, **kwargs)` function replicate the function view.

---

<div class="post-metadata">

**Author:** ![iFunction](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ifunction/32/1941_2.png) [@iFunction](https://forum.djangoproject.com/u/iFunction)\
**Post date:** [September 10, 2020, 5:21pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/5 "2020-09-10T17:21:00Z")

</div>

Ok, thank you, that’s very useful, it was one of the things I thought maybe an issue. I’m gonna go away and try and write this from scratch.

---

<div class="post-metadata">

**Author:** ![Suttonium](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/suttonium/32/1264_2.png) [@Suttonium](https://forum.djangoproject.com/u/Suttonium)\
**Post date:** [September 10, 2020, 5:28pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/6 "2020-09-10T17:28:05Z")

</div>

Keep in mind that when using `**kwargs`, you can add the slug into the kwargs dictionary and `pop` it off the dictionary when it is needed.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 10, 2020, 5:41pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/7 "2020-09-10T17:41:22Z")

</div>

Actually, I think one of issues is not fully understanding what the CreateView is doing. You’re trying to use “get\_object” to get something other than the object you’re trying to create.

When I look at your FBV, your form is for an object of type Comment. But in your get\_object method you’re trying to retrieve a Project.

Likewise, you’re setting your queryset to a queryset for Projects.

A CreateView for a Comment is focused on a Comment. All the methods and attributes should be oriented on Comment.

If you need to retrieve ancillary data related to that Comment, you can override the form\_valid method. At that point in the flow, you know the form is valid and you can construct the rest of the fields for that model from any other sources of data you may need.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 10, 2020, 5:43pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/8 "2020-09-10T17:43:34Z")

</div>

The [Classy Class Based View web site](https://ccbv.co.uk/) might help you understand the flow of these CBVs better. See the [CreateView](https://ccbv.co.uk/projects/Django/3.0/django.views.generic.edit/CreateView/) for this specific case.

---

<div class="post-metadata">

**Author:** ![iFunction](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ifunction/32/1941_2.png) [@iFunction](https://forum.djangoproject.com/u/iFunction)\
**Post date:** [September 10, 2020, 5:51pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/9 "2020-09-10T17:51:29Z")

</div>

Yes, correct, but it can’t stand alone, so I thought the get object was to make the correct project available to comment on. I couldn’t work out another way to do that. The user looks through the list of projects that he has an update about clicks on the title of the project and then makes his comment. I kinda followed the human behaviour to work my logic. What would be a better way to do this?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 10, 2020, 5:59pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/10 "2020-09-10T17:59:53Z")

</div>

There are two different views involved here.

There’s a ListView, that would present the list of project with clickable links. Those links would direct you to the CreateView for creating the comment.

The links in the ListView could pass the slug - or could pass the primary key - of the project to be commented on as part of the URL in the link.

(This ListView followed by CreateView is a _very_ standard Django pattern. It also happens to be the pattern followed by the Polls application used in the [Django Tutorial](https://docs.djangoproject.com/en/3.1/intro/tutorial01/).)

Ken

---

<div class="post-metadata">

**Author:** ![iFunction](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ifunction/32/1941_2.png) [@iFunction](https://forum.djangoproject.com/u/iFunction)\
**Post date:** [September 10, 2020, 6:02pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/11 "2020-09-10T18:02:57Z")

</div>

Ah yes, I only found this forum because I literally just finished the django tutorial a couple of weeks ago for the second time to see what I’d learned in 2 years. Thank you for your input and prompt response also, let me take all that away and see where I get to.

---

<div class="post-metadata">

**Author:** ![iFunction](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ifunction/32/1941_2.png) [@iFunction](https://forum.djangoproject.com/u/iFunction)\
**Post date:** [September 30, 2020, 12:33pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/12 "2020-09-30T12:33:57Z")

</div>

Sorry, I have to come back to this, as I still can’t get this working in any form or fashion. What I want is a view that creates a comment on a Project that is already been created. The reason I was using the get\_object method was to get the project that the comment is on. How else do you get that link to the Project I mean how is it done in other blog sites?

So I have this:  
class Comment(CreateView):  
model = Update  
form\_class = ProjectCommentForm  
template\_name = ‘project/project\_comment.html’

url:  
`path('<slug:slug>/comment/', UpdateView.as_view(), name='comment')`

I’m really confused, it can’t be this complicated surely?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 30, 2020, 12:55pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/13 "2020-09-30T12:55:55Z")

</div>

One hook available to you for doing something like this is the `form_valid` method. You can query for the referenced `Project` in that method before the data from the form gets saved.  
I believe you can use the `form.instance` attribute to reference the `Comment` object being created to assign the reference to.  
(Assuming the field name in `Comment` is `project`, it would be something like:  
`form.instance.project = Project.objects.get(slug=self.kwargs['slug'])`  
I’m making some guesses here regarding names, so this is likely not exactly correct for what you need.)

Ken

---

<div class="post-metadata">

**Author:** ![iFunction](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ifunction/32/1941_2.png) [@iFunction](https://forum.djangoproject.com/u/iFunction)\
**Post date:** [September 30, 2020, 2:45pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/14 "2020-09-30T14:45:07Z")

</div>

Ok, It’s starting to look like what I want is just not possible with django. This all works if it is in a separate page, but it isn’t, the site I have is more like stack exchange where there is a comment form on the the post itself. I wanted to make this class based views to take advantage of using an UpdateView to be able to edit the comments. So the reason for using get\_object method was to have access to the project instance as it’s required to populate the project details as well as the comment form, similar to how stack exchange is done with the post at the top, then a form to give an answer and then all the other comments underneath. So the original point of my post here is back in that I’m getting noreversematch well it’s just for one button at the moment, but if I comment that out it just moves to the next one and so on. How this kind of thing usually done?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 30, 2020, 4:01pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/15 "2020-09-30T16:01:09Z")

</div>

> [@iFunction](#):
>
> This all works if it is in a separate page

Correct, that’s what you asked for in the previous question. You showed a CreateView in the absence of any additional information or clarification as to what you’re looking for.

Rephrasing things slightly then, it _now_ sounds like you also want to display some additional information on the same page as the comment form.  
That feature is implemented by overriding the [`get_context_data`](https://docs.djangoproject.com/en/3.1/topics/class-based-views/generic-display/#adding-extra-context) method, and adding whatever data you want displayed on that page. (Your template would then render that content however you choose.)

---

<div class="post-metadata">

**Author:** ![iFunction](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ifunction/32/1941_2.png) [@iFunction](https://forum.djangoproject.com/u/iFunction)\
**Post date:** [September 30, 2020, 5:47pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/16 "2020-09-30T17:47:16Z")

</div>

Right, now I understand, that _is_ what context is actually for. Context is a really tricky subject to understand.

Yes my written style is not good, I’ve been working on this site for a year, and it just went into production last month, I’m just trying to now refactor it using and learning best practices if I can, as I have another one to do and I don’t want that one to take a year. I’ll try to ask my questions better in future. Thankyou very much for your help though, I’m very glad I found this forum

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 30, 2020, 6:17pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/17 "2020-09-30T18:17:01Z")

</div>

While I can understand the confusion with the name “context”, conceptually, it’s probably easier than you may think it is. In the simplest terms, your context is the data being used to populate the variables in a template. Whenever you have a reference in a template such as `{{ xyz }}` the template rendering engine looks at the context to find `xyz`.

And please, don’t worry about your writing style - it’s really quite fine. It’s not that the questions aren’t well written, it’s only that they weren’t complete for where you were headed - and that’s not necessarily a bad thing. Sometimes breaking a larger problem into smaller easier-to-understand problems is quite beneficial toward understanding the whole. However, when you take that approach, you should recognize that the answers to questions may change as a result of adding in that additional functionality. (It doesn’t in this case - handling the POST form for linking the comment to the original object occurs separately and independently of the GET displaying that form with other data.)

Ken

---

<div class="post-metadata">

**Author:** ![iFunction](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ifunction/32/1941_2.png) [@iFunction](https://forum.djangoproject.com/u/iFunction)\
**Post date:** [October 6, 2020, 3:59pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/18 "2020-10-06T15:59:22Z")

</div>

Sorry about this, I’m nearly there, just stuck on one small thing now, on submit, the foreign key from the project is not added so the project the comment is connected to is blank. I have this so far:

```
class CommentView(CreateView):
    model = Comment
    form_class = ProjectCommnetForm
    template_name = 'project_portal/project_comment.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['project'] = Project.objects.get(slug=self.kwargs['slug'])
        return context
    
    def form_valid(self, form):
        form.instance.project_id = project.id
        return super(CommentView, self).form_valid(form)

```

I tried using form\_valid method in there, but it didn’t work, and looking on the [ccbv.co.uk](http://ccbv.co.uk) for createview, it does look like the get\_context\_data is supposed to deal with that, so without the form\_valid method, the project\_id is being returned as null, with the form\_valid() method, I get ‘project’ is not defined. What am I doing wrong here please?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [October 6, 2020, 4:18pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/19 "2020-10-06T16:18:49Z")

</div>

They’re two different functions that occur in two different steps of the lifecycle.

1. Display the original form - if you follow the sequence of execution for the `get` method, you’ll see it ends up calling `get_context_data` before rendering the form in the template.
2. Process the submitted form - the `post` method binds the data to the form and then calls `form_valid`. I’m not seeing where `get_context_data` is involved in this process.

In the same way that you have the following line in `get_context_data`:  
`context['project'] = Project.objects.get(slug=self.kwargs['slug'])`

you could do something like this in `form_valid`, assuming your `post` url is passing the slug in as a parameter on the post:  
`project = Project.objects.get(slug=self.kwargs['slug'])`

Another way of handling this would be to pass the current project.id value as a hidden field in the form, and just refer to that field in the `form_valid` method.

Always keep in mind that in the flow of events, a GET of a form is completely independent of a POST of that same form. Even if you’re using the same View class to handle both, they are different instances being created to handle each call. You can’t pass data between the GET and the POST through the instance of a View class.  
What that really means then is that to get data from the GET to the POST, it needs to be stored external to the class - in this case, when you’re talking about forms, one of the three common ways of doing it is through form variables. (The database and session data are the other two - neither of which are particularly appropriate in this case.)

---

<div class="post-metadata">

**Author:** ![iFunction](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ifunction/32/1941_2.png) [@iFunction](https://forum.djangoproject.com/u/iFunction)\
**Post date:** [October 6, 2020, 5:10pm UTC](https://forum.djangoproject.com/t/passing-slug-to-createview/4287/20 "2020-10-06T17:10:40Z")

</div>

Ok, just one last question, and if I still get errors, I’m sacking this off and sticking to the function based view, but for some reason, it’s now not redirecting back to the same page like it was, now it’s sending one of the form fields as an argument, but I can’t find how the createview redirects, my original FBV just went back to the same page which is the desired behaviour, I’m getting really confused, why is it sending one of the form fields as an argument?

[Next page](https://forum.djangoproject.com/t/passing-slug-to-createview/4287.md?page=2)
