Django: 'ImproperlyConfigured at' after form POST using CreateView - python

I want to add data to my database from form (which is CreateView). Unfortunately after posting I got
'ImproperlyConfigured at/persons/new/'
I was trying to edit my urls.py, but I think I missed something.
My views.py
class PersonListView(ListView):
model = Person
template_name = 'app/home.html'
context_object_name = 'users'
class PersonCreateView(CreateView):
model = Person
fields = ['name','surname']
My urls.py in project
*imports*
urlpatterns = [
path('admin/',admin.site.urls),
path('persons/', include('app.urls')),
]
My urls.py in app
*imports*
urlpatterns = [
path('',PersonListView.as_view(),name='persons),
path('new/',PersonCreateView.as_view(),name='person-create),
]
After submit my form, data are added to database but I got error like above.

Short answer: you should specify a success_url [Django-doc] attribute in your view, or override form_valid [Django-doc].
In a CreateView [Django-doc] (well most views with a FormMixin [Django-doc]), you need to specify what needs to happen when the form has been processed succesfully.
By default a ModelFormMixin [Django-doc] will first save the object [GitHub]:
def form_valid(self, form):
"""If the form is valid, save the associated model."""
self.object = form.save()
return super().form_valid(form)
and then the underlying FormMixin will redirect to the success_url [GitHub]:
def form_valid(self, form):
"""If the form is valid, redirect to the supplied URL."""
return HttpResponseRedirect(self.get_success_url())
The get_success_url will retrieve the success_url attribute [GitHub], and raise, as you noticed, an ImproperlyConfigured error if that one is missing:
def get_success_url(self):
"""Return the URL to redirect to after processing a valid form."""
if not self.success_url:
raise ImproperlyConfigured("No URL to redirect to. Provide a success_url.")
return str(self.success_url) # success_url may be lazy
In you view, you thus can specify a success_url, for example with reverse_lazy [Django-doc]:
from django.urls import reverse_lazy
class PersonCreateView(CreateView):
model = Person
fields = ['name','surname']
success_url = reverse_lazy('persons')
Here persons is the name of the path(..) to which we redirect. Redirecting is typically the preferred way to handle a successful form: it is part of the Post/Redirect/Get architectural pattern [wiki]. If you would render a page for the POST request, then a user that refreshes the page on the browser, will resend the same data to the server, and thus might actually create a second object.
Another option is to override form_valid, and do something else after calling the super().form_valid(form) (since that will save the object to the database).

Related

How to redirect user from registration page to profile if user is already registered?

I am using Django class-based views for my project and trying to redirect user from registration view if he is already authenticated. I've done it already with LoginView and it was pretty simple and looked just like adding few lines of code:
class Login(LoginView):
authentication_form = CustomAuthenticationForm
redirect_authenticated_user = True
LOGIN_REDIRECT_URL = "core:profile"
So after going to url for login, user ends up at his profile url. Absolutely simple and works perfectly.
However, there is no CBV for registration and therefore CreateView should be used, which doesn`t have any attributes for checking if user is authenticated.
The one method of doing something similar is UserPassesTestMixin, but it only gives me 403 Forbidden if user is authenticated, not redirect.
Here is my current registration view:
class Registration(UserPassesTestMixin, CreateView):
form_class = RegistrationForm
template_name = "registration/user_form.html"
success_url = reverse_lazy("core:profile")
def test_func(self):
return self.request.user.is_anonymous
def form_valid(self, form):
print(self.kwargs)
self.object = form.save(commit=True)
self.object.is_active = True
self.object.save()
login(self.request, self.object, backend="core.auth_backend.AuthBackend")
return HttpResponseRedirect(self.success_url)
Maybe somebody have done it already?
Would be very grateful for every advice!
In your Registration class, add a get method and remove your test_func:
def get(self,request,*args,**kwargs):
if self.request.user.is_authenticated:
return HttpResponseRedirect('redirect_url')
return super().get(request,*args,**kwargs)

Dynamic URL routing for a class-based view

I want to turn a function view into a class-based view.
Here is the View & URL path that I have right now.
View:
def customer(request, pk):
customer = Customer.objects.get(id=pk)
return render(request, 'accounts/customer.html)
URL Path:
path('customer/<str:pk>/, views.customer, name='customer')
What would the proper syntax be to turn this view into a class-based view.
I am mainly curious about how to access the primary key here using a class-based view.
Thanks!
You can use Detail View.
in your views.py
from django.views.generic.detail import DetailView
from .models import Customer
class CustomerDetails(DetailView):
model = Customer
template_name = 'customerdetail.html' #deafaults to customer_detail.html
in urls.py
path('customer/<int:pk>', views.CustomerDetails.as_view(), name='customer')
the context that will be passed to customerdetail.html template will have the default name 'object'. access the fields of customer instance by {{object.<field_name>}}.
You can override the attributes and methods of DetailView.
for moreinfo : DetailView
If you want more control in your view you can use generic View
from django.views.generic.detail import View
from .models import Customer
class CustomerDetails(View):
def get(self, *args, **kwargs):
customer = Customer.objects.get(id=kwargs['pk'])
return render(self.request, 'accounts/customer.html)
urls.py
path('customer/<int:pk>', views.CustomerDetails.as_view(), name='customer')
arguments found in the url are stored in **kwargs

How the form_Valid function works in django?

What is this form object on the return line,is it the form object recieved by the submission of a form ? . and since we are returning it with return super().form_valid(form).
can it be accessed like context variables ? from the template represented by the success_url .also form_valid points to success_url , since were doing super() , shouldnt it point to the success_url of the parent class. but why does it go to the success_url of ContactView.
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm
success_url = '/thanks/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
form.send_email()
return super().form_valid(form)
What is this form object on the return line?
form is the ContactForm instance that Django constructed to validate the POST request. You can thus for example obtain cleaned data from the form with:
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm
success_url = '/thanks/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
form.send_email()
print(form.cleaned_data)
return super().form_valid(form)
The FormView will thus construct a ContactForm with request.POST and request.FILES, and check form.is_valid(). If it is, it will call form_valid with this form instance.
since were doing super(), shouldnt it point to the success_url of the parent class.
No. super() is a proxy-object that will move up the MRO and thus call the parent method, but that parent method is implemented as [GitHub]:
def form_valid(self, form):
"""If the form is valid, redirect to the supplied URL."""
return HttpResponseRedirect(self.get_success_url())
The self object is however still a ContactView object, so self.get_success_url() will return the success_url.
Often however, reverse_lazy [Django-doc] is used. That way you can provide the name of the view, and Django can automatically calculate the URL:
from django.urls import reverse_lazy
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm
success_url = reverse_lazy('name-of-thanks-view')

how can I render a view only when a certain field is True? - Django

I have created detailed views for the posts in my Django-based blog using the DetailView generic class and everything works fine so far. The problem, however, is that I have a field in my post model that is used to set the status of the posts (active, inactive, blocked) and I only want to render the detailed views when the status is active. If anyone knows of a way to achieve this, please let me know and I ask that you be as detailed as possible.
views.py
from .models import Post
from django.views.generic import DetailView
class PostDetailView(DetailView):
model = Post
context_object_name = 'post'
template_name = 'blog/post-detail.html'
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['title'] = Post.objects.filter(slug=self.object.slug).first()
return context
In your DetailView you can filter the queryset, for example you can filter with:
from django.views.generic import DetailView
class PostDetailView(DetailView):
queryset = Post.objects.filter(active=True)
# …
The DetailView will retrieve the element based on the primary key and/or slug on the queryset, so if the element is not in the filtered queryset, then you will retrieve a 404 error.
Here we assume that the Post model has an active field:
class Post(models.Model):
# …
active = models.BooleanField()
# …
Given the field and values are different, you should of course filter the queryset accordingly.

My user profile update view (class based view) returns a 404

I have a UserProfile model that I want to let people update if they wish to.
views.py
from django.views.generic.edit import CreateView, UpdateView
class UserProfileUpdateView(UpdateView):
model = UserProfile
form_class = UserProfileForm
template_name = "preferences.html"
success_url = "/profile/"
def get_context_data(self, *args, **kwargs):
context = super(UserProfileUpdateView, self).get_context_data(*args, **kwargs)
return context
urls.py
from profiles import views
from profiles.views import UserProfileCreateView, UserProfileUpdateView
urlpatterns = [url(r'^profile/(?P<pk>\d+)$/edit', UserProfileUpdateView.as_view(), name='update_profile'),]
Now my problem is that when I try to go to http://127.0.0.1:8000/profile/someusername/edit I get a 404. I don't understand exactly what's happening with the pk in the urlpatterns. What url pattern should I use to see the page where I can update the profile? Or is there something wrong here?
I
You have an $ in the middle of your regex, which makes no sense because that is the terminator character. Remove it.

Categories

Resources