No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model
Solution 1
The best way to do this is to add a method get_success_url
on the create view and use that to redirect back to the detail view. In the create view you have the object after it is saved, like so
class LawyerReviewCreate(CreateView):
def get_success_url(self):
return reverse('lawyer_detail', kwargs={'lawyer_slug': self.object.lawyer_slug})
This will then automatically send the user back to the detail view if the form is valid.
Also, make sure your kwargs is using the correct key, it would appear that you are using review_slug in some cases and lawyer_slug in other cases
Solution 2
We can follow Django’s suggestion and add a "get_absolute_url" to our model. It sets a canonical URL for an object so even if the structure of your URLs changes in the future, the reference to the specific object is the same. In short, you should add a get_absolute_url() method to each model you write.
def get_absolute_url(self): # new
return reverse('lawyer_detail', args=[str(self.id)])
This should solve your problem
Related videos on Youtube
user2901792
Updated on September 16, 2022Comments
-
user2901792 over 1 year
I am using CreateView to build a form. The CreateView is called from the DetailView. Once the form is submitted, I want for the validated, submitted data to be returned back to the initial DetailView.
The DetailView calls up the CreateView just fine. The form works as expected until it is submitted. Then, I get this error: No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model.
I tried using this solution, but it kicks out the same error. I tried passing the data and redirecting through the URL that calls the CreateView. I still get the same error.
Can someone please tell me how to redirect the CreateView back to the original DetailView (and passing back the validated data?
models.py
class Lawyer(models.Model): name = models.CharField(max_length=100, default='') practice_area = models.CharField(max_length=100, default='') address = models.CharField(max_length=255, default='') city = models.CharField(max_length=50, default='') state = models.CharField(max_length=2, default='') zipcode = models.CharField(max_length=10, default='') telephone = models.CharField(max_length=15, default='') years_practice = models.IntegerField(default=10) objects = models.Manager() lawyer_slug = models.SlugField(default='') def get_absolute_url(self): return reverse('lawyer_detail', kwargs={'lawyer_slug': self.lawyer_slug}) def __str__(self): return self.name class Review(models.Model): RATING_CHOICES = ( (0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), ) lawyer = models.ForeignKey(Lawyer, null=True) review_created = models.DateTimeField('Date of Review', auto_now_add=True) reviewer_name = models.CharField(max_length=55, default='') reviewer_city = models.CharField(max_length=55, default='') reviewer_state = models.CharField(max_length=2, default='') email = models.EmailField(default='') rating = models.IntegerField(default=1, choices=RATING_CHOICES) review_comment = models.TextField(default='') review_slug = models.SlugField(default='') def get_absolute_url(self): return reverse('lawyer_createreview', kwargs={'review_slug': self.review_slug}) def __str__(self): return self.review_slug
views.py
class LawyerDetail(DetailView): model = Lawyer template = 'lawyer_detail.html' context_object_name = 'lawyer' def get_object(self): lawyer_slug = Lawyer.objects.get( lawyer_slug=self.kwargs.get('lawyer_slug') ) return lawyer_slug def get_context_data(self, **kwargs): context = super(LawyerDetail, self).get_context_data(**kwargs) context['lawyer_reviews'] = self.object.review_set.all() return context class LawyerReviewCreate(CreateView): model = Review form_class = ReviewForm def get_form_kwargs(self, **kwargs): kwargs = super(LawyerReviewCreate, self).get_form_kwargs() redirect = self.request.GET.get('next') if redirect: if 'initial' in kwargs.keys(): kwargs['initial'].update({'next': redirect}) else: kwargs['initial'] = {'next': redirect} return kwargs def form_invalid(self, form): import pdb;pdb.set_trace() # debug example return super(LawyerReviewCreate, self).form_invalid(form) def form_valid(self, form): redirect = form.cleaned_data.get('next') if redirect: self.success_url = redirect return super(LawyerReviewCreate, self).form_valid(form)
urls.py
url(r'^lawyers/(?P<lawyer_slug>[\w-]+)/$', LawyerDetail.as_view(), name='lawyer_detail'), url(r'^lawyers/(?P<lawyer_slug>[\w-]+)/createreview/$', LawyerReviewCreate.as_view(), name='lawyer_createreview'),
template.html (calls CreateView and part that displays the returned data)
<div class="review_buttom_wrapper"> <a href="{% url 'lawyer_createreview' lawyer.lawyer_slug %}?next={% url 'lawyer_detail' lawyer.lawyer_slug %}"> <button class="review_button"> <strong>Review</strong> {{ lawyer.name }} </button> </a> </div> {% for review in lawyer_reviews %} <div style="padding-left: 15px; padding-right: 15px; overflow:auto;"> <div class="review-masthead"> <div class="medium-3 columns"> <p class="posttime">{{ review.review_created|timesince }} ago </p> <p class="review-title">{{ review.user_name }} <span class="location">{{ review.lawyer.city }}, {{ review.lawyer.state }}</span></p> </div> <div class="medium-7 columns"> <p>{{ review.review_comment }}</p> </div> <div class="medium-2 columns"> <div class="user_rating"> Rating </div> <div class="rating_number"> {{ review.rating }} </div> </div> </div> {% endfor %}
forms.py
RATING_CHOICES = ( (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), ) class ReviewForm(forms.ModelForm): reviewer_name = forms.CharField(widget = forms.TextInput(attrs={'class': 'review_input_box', 'placeholder': 'Your name'})) reviewer_city = forms.CharField(widget = forms.TextInput(attrs={'class': 'review_input_box', 'placeholder': 'Your city'})) reviewer_state = forms.CharField(widget = forms.TextInput(attrs={'class': 'review_input_box', 'placeholder': 'Your state'})) rating = forms.ChoiceField(choices = RATING_CHOICES, label="", initial='', widget = forms.Select(attrs={'class': 'review_selector'}), required=True) email = forms.EmailField(widget = forms.TextInput(attrs={'class': 'review_input_box', 'placeholder': '[email protected]'})) review_comment = forms.CharField(widget = forms.Textarea(attrs={'class': 'review_input_box', 'placeholder': 'What would you like to say?'})) class Meta: model = Review fields = ['reviewer_name', 'reviewer_city', 'reviewer_state', 'rating', 'email', 'review_comment'] Traceback: File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/views/generic/edit.py" in get_success_url 190. url = self.object.get_absolute_url() File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/ralph/fathers/models.py" in get_absolute_url 142. return reverse('lawyer_createreview', kwargs={'lawyer_slug': self.lawyer_slug}) During handling of the above exception ('Review' object has no attribute 'lawyer_slug'), another exception occurred: File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response 149. response = self.process_exception_by_middleware(e, request) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response 147. response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/views/generic/base.py" in view 68. return self.dispatch(request, *args, **kwargs) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/views/generic/base.py" in dispatch 88. return handler(request, *args, **kwargs) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/views/generic/edit.py" in post 256. return super(BaseCreateView, self).post(request, *args, **kwargs) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/views/generic/edit.py" in post 222. return self.form_valid(form) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/ralph/fathers/views.py" in form_valid 165. return super(LawyerReviewCreate, self).form_valid(form) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/views/generic/edit.py" in form_valid 202. return super(ModelFormMixin, self).form_valid(form) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/views/generic/edit.py" in form_valid 108. return HttpResponseRedirect(self.get_success_url()) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/views/generic/edit.py" in get_success_url 193. "No URL to redirect to. Either provide a url or define" Exception Type: ImproperlyConfigured at /xxxxxxx/xxxxxxx/xxxxxxx-xxxxxx/createreview/ Exception Value: No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model.
Traceback after changing get_absolute_url on Review model
Traceback: File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response 149. response = self.process_exception_by_middleware(e, request) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response 147. response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/contrib/admin/sites.py" in wrapper 265. return self.admin_view(view, cacheable)(*args, **kwargs) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/utils/decorators.py" in _wrapped_view 149. response = view_func(request, *args, **kwargs) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/views/decorators/cache.py" in _wrapped_view_func 57. response = view_func(request, *args, **kwargs) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/contrib/admin/sites.py" in inner 244. return view(request, *args, **kwargs) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/contrib/contenttypes/views.py" in shortcut 31. absurl = get_absolute_url() File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/xxxxx/xxxxxxx/models.py" in get_absolute_url 142. return reverse('lawyer_createreview', kwargs={'review_slug': self.review_slug}) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/core/urlresolvers.py" in reverse 600. return force_text(iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))) File "/xxxx/xxxxxxxxxx/xxxx/xxxxxxxxxxxx/lib/python3.5/site-packages/django/core/urlresolvers.py" in _reverse_with_prefix 508. (lookup_view_s, args, kwargs, len(patterns), patterns)) Exception Type: NoReverseMatch at /admin/r/14/1/ Exception Value: Reverse for 'lawyer_createreview' with arguments '()' and keyword arguments '{'review_slug': 'michael-ferrin'}' not found. 1 pattern(s) tried: ['fathers/lawyers/(?P<lawyer_slug>[\\w-]+)/createreview/$']
-
Klaus D. over 7 yearsPlease add the full error traceback to your question!
-
Klaus D. over 7 yearsYour parameters in
reverse
inside ofReview.get_absolute_url()
are faulty. They look like they are forLawyer
. -
user2901792 over 7 yearsChanged the parameters. Getting new error. Please see new traceback. The new url does not seem to be routing back to the original DetailView from CreateView after form submission.
-
solarissmoke over 7 yearsYou are passing
review_slug
parameter inget_absolute_url
, but the URL definition for that URL has no such parameter in it (it only has alawyer_slug
).
-
-
Sayyor Y about 3 yearsDon't forget to
from django.urls import reverse
. Also, the first argument of reverse should be the name of the view specified in urls.py.