Pankaj Jackson
Pankaj Jackson

Reputation: 3751

How to get created object in CreateView

Here I am using CreateView to create item and after that i am redirecting user to update other fields of currently created object.

Here my code:

Views.py

class DynamicCreate(CreateView):
    model = Dynamic
    form_class = DynamicForm
    template_name = 'book/dynamic_create.html'

    def form_valid(self, form):
        book = form.save(commit=False)
        book.user = User.objects.get(pk=(self.request.user.pk))
        book.save()
        return reverse('book:dynamicupdate', args=(self.object.id))


Urls.py

url(r'^book/create/$', views.DynamicCreate.as_view(), name='dynamiccreate'),
url(r'^book/delete/(?P<pk>[\w]+)/$', views.DynamicDelete.as_view(), name='dynamicdelete'),
url(r'^book/update/(?P<pk>[\w]+)/$', views.DynamicUpdate.as_view(), name='dynamicupdate'),

But Here I am getting error:

Exception Type:     AttributeError
Exception Value:    'NoneType' object has no attribute 'id'

I go through other previously asked question like This, But I don't know What I am missing here. My CreateView is able to create/save data in Table but it is not able to redirect me to update View Page.

Upvotes: 4

Views: 4701

Answers (5)

BKO
BKO

Reputation: 141

By defining get_absolute_url in model you can redirect to "book:dynamicupdate" with pk of created/updated instance.

models.py

from django.db import models
from django.urls import reverse


class Dynamic(models.Model):
    ...

    def get_absolute_url(self):
        return reverse("book:dynamicupdate", kwargs={"pk": self.pk})

urls.py

app_name = 'book'
urlpatterns = [
    path('/path/<int:pk>/', views.YourUpdateView.as_view(), name='dynamicupdate'),
]

See https://docs.djangoproject.com/en/4.2/topics/class-based-views/generic-editing/#model-forms

Upvotes: 0

openHBP
openHBP

Reputation: 691

As explained by solarissmoke 'form_valid' must return a response object not a url!

I would then write:

class DynamicCreate(CreateView):
    model = Dynamic
    form_class = DynamicForm
    template_name = 'book/dynamic_create.html'
    success_url = reverse("dynamic_list")

    def form_valid(self, form):
        # Catch an instance of the object
        book = form.save(commit=False)
        book.user_id = self.request.user.id
        book.save()
        self.success_url = reverse('book:dynamic_detail', args=[str(book.id)])
        return super(DynamicCreate, self).form_valid(form)

Note: book.user.id = self.request.user.id instead of the user instance

Even cleaner, add get_absolute_url in model.py

def get_absolute_url(self):
    return reverse('dynamic_detail', args=[str(self.id)])

And refer to this function in the view:

class DynamicCreate(CreateView):
    model = Dynamic
    form_class = DynamicForm
    template_name = 'book/dynamic_create.html'
    success_url = reverse("book_list")

    def form_valid(self, form):
        # Catch an instance of the object
        book = form.save(commit=False)
        book.user_id = self.request.user.id
        book.save()
        self.success_url = self.model.get_absolute_url(book)
        return super(DynamicCreate, self).form_valid(form)

Upvotes: 1

Dashdrum
Dashdrum

Reputation: 667

The form_valid method inherited from ModelFormMixin includes logic to set self.object to the newly created object, but your overriding method uses the book variable instead. Changing the args to reference book as mentioned above works fine.

Another option would be to replace the book variable with self.object, if only to follow the example set by the default method.

Upvotes: 3

Pankaj Jackson
Pankaj Jackson

Reputation: 3751

I Fixed it by changing from return reverse('book:dynamicupdate', args=(self.object.id)) to return redirect('book:dynamicupdate', book.id)

reverse need ViewName not url so i changed reverse to redirect and here my object was book so i replaced self.object with book

Thanks @Daniel Roseman for help

Upvotes: 1

wobbily_col
wobbily_col

Reputation: 11878

Try changing that line to:

return reverse('book:dynamicupdate', args=(book.id))

self.object is not defined anywhere in your code.

Upvotes: 0

Related Questions