Is any way to set success_url from urlconf parameter? - python

in urls.py:
url(r'^add/from?(?P<link>[a-zA-Z0-9/]+)$', PostAdd.as_view(), name='post_add'),
in views.py:
class PostAdd(CreateView):
model = Post
form_class = PostForm
template_name = 'post_add.html'
success_url = ????
def get_context_data(self, **kwargs):
context = super(PostAdd, self).get_context_data(**kwargs)
context['from'] = self.kwargs['link']
return context
I can pass link to the template, but I need to set success_url=link

You should override the get_success_url method on the view, rather than using the success_url attribute.
class PostAdd(CreateView):
def get_success_url(self):
# Grab 'link' here and return it:
return self.kwargs['link']

Related

django user update form not updating

I have a detailed user view that has a button for user updates. The user update form is inside a modal, for that, I am using a FormView ModelForm and a TbUser. I don't get how the form validation works but the fields are correct. When I update something for a user, I get an error, TbUser with username already exists, which means the code does not update the user but tries to add a new one. Also, I want to redirect to user-detail page after submit.
views.py
class UserUpdateView(LoginRequiredMixin, SuccessMessageMixin, FormView):
form_class = UserUpdateForm
template_name = 'users/modals/user_update_modal.html'
success_message = "User updated successfully."
def get_form_kwargs(self):
kw = super().get_form_kwargs()
kw['request'] = self.request
return kw
def form_valid(self, form):
obj = form.save(commit=False)
print(obj.username)
print('valid')
TbUser.objects.filter(id=self.request.user.id).update(username=obj.username, real_name=obj.real_name,
email=obj.email, cellphone=obj.cellphone,
department=obj.department, role=obj.role)
def form_invalid(self, form):
messages.error(self.request, form.errors)
# Where to redirect here? I want to
def get_success_url(self):
return reverse('user-detail', kwargs={'pk': self.formclass})
forms.py
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
def __init__(self, request, *args, **kwargs):
super().__init__(*args, **kwargs)
self.request = request
if request.user.customer:
self.fields['department'].queryset = TbDepartment.objects.filter(
customer=request.user.customer)
self.fields['role'].queryset = TbRole.objects.filter(
customer=request.user.customer)
class Meta:
model = TbUser
fields = ['username', 'real_name', 'email',
'cellphone', 'department', 'role']
urls.py
urlpatterns = [
path('users-list/', views.UsersListView.as_view(), name='users-list'),
path('user-detail/<str:pk>/',
views.UserDetailView.as_view(), name='user-detail'),
path('tb-user-update-form/<str:pk>/update/',
views.UserUpdateView.as_view(), name='tb-user-update-form'),
]
You need to override the get_object method to let it point to the object you want to update.
A FormView will construct a form *without looking for an object, you can use an UpdateView [Django-doc] to fetch the object with get_object, and then inject this in the form to update that object:
from django.views.generic import UpdateView
class UserUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
form_class = UserUpdateForm
template_name = 'users/modals/user_update_modal.html'
success_message = "User updated successfully."
def get_form_kwargs(self):
kw = super().get_form_kwargs()
kw['request'] = self.request
return kw
def get_object(self, *args, **kwargs):
return self.request.user
def form_invalid(self, form):
messages.error(self.request, form.errors)
return super().form_invalid(form)
def get_success_url(self):
return reverse('user-detail', kwargs={'pk': self.object.pk })

How to put 2 context_object_name for listView Django

I have developed a context within a context.
here's my views.py:
class AgentClientListView(OrganizerAndLoginRequiredMixin, generic.ListView):
template_name = "agents/agent_client_list.html"
context_object_name = "clients"
def get_queryset(self):
queryset = Client.objects.filter(agent_id=self.kwargs['pk'], agent__isnull=False).order_by('company_name')
return queryset
however I need to add another context_object_name: "agent"
what would I do?
thank you in advance
You need to ovveride get_context_data:
def get_context_data(self, *args, **kwargs):
context = super(AgentClientListView, self).get_context_data(*args, **kwargs)
context['agents'] = <Your agent query>
return context

How can I display form instance?

How can I pass the form with an actual filled profile informations (like ProfileUpdateForm(instance=x) in function views).
I did it this way and have no idea how to pass an actual profile instance to the form. Something like UpdateView, but in my DetailView class
class ProfileDetailView(FormMixin, DetailView):
model = Profile
context_object_name = 'profile'
template_name = 'profiles/myprofile.html'
form_class = ProfileUpdateForm
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
form.save()
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy('profiles:profile', kwargs={'pk': self.get_object().pk})
If you want to update an instance of a model you should use UpdateView [Django docs]:
from django.urls import reverse
from django.views.generic.edit import UpdateView
class ProfileDetailView(UpdateView):
model = Profile
context_object_name = 'profile'
template_name = 'profiles/myprofile.html'
form_class = ProfileUpdateForm
def get_success_url(self):
# Use `reverse` instead of `reverse_lazy`. You will get an error otherwise!
return reverse('profiles:profile', kwargs={'pk': self.get_object().pk})
Also if there is any need to pass a keyword argument to the form (here instance, although I would suggest to stick with UpdateView) you should override get_form_kwargs:
class MyView(SomeGenericView):
...
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['some_kwarg'] = 'Some value'
# Your use case implies below line
# kwargs['instance'] = self.get_object()
return kwargs

Pass context data from generic.DetailView

How can i pass the context data which is coming from a forms.py to my views class which is using generic detailView, i need to pass forms.py to my product detail page.
Here is the code for my view class
class ProductView(generic.DetailView):
model = Product
cart_product_form = CartAddProductForm()
context = {'cart_product_form': cart_product_form}
template_name = 'shopping/product.html'
query_pk_and_slug = True
Please let me know if this is incorrect
Override get_context_data, and add the form to the context before returning it.
class ProductView(generic.DetailView):
model = Product
template_name = 'shopping/product.html'
query_pk_and_slug = True
def get_context_data(self, **kwargs):
context = super(ProductView, self).get_context_data(**kwargs)
cart_product_form = CartAddProductForm()
context['cart_product_form'] = cart_product_form
return context

How can I return regular response in override get method, Django

I try to use class based views in Django. And I have such problem: I define a base class for a blog (BlogBaseView) and two other classes, that inherit it.
And in the second class(BlogIndexView) I want to make the search by get request, so I have override get method. It works, but if I don't make get request, it returns HttpResponse, however I want to return usual context (which BlogIndexView retunes without override get method).
What can I do?
class BlogBaseView(View):
def get_context_data(self, **kwargs):
context = super(BlogBaseView, self).get_context_data(**kwargs)
blog_categories = []
categories = BlogCategory.objects.all()
for category in categories:
blog_categories.append(tuple([category, category.get_number_of_category_items]))
context['name_page'] = 'blog'
context['tags'] = Tag.objects.all()
context['blog_categories'] = blog_categories
return context
class BlogIndexView(BlogBaseView, ListView):
queryset = Post.objects.all().order_by('-date_create')
template_name = 'index_blog.html'
context_object_name = 'posts'
def get(self, request):
if request.GET.get('tag'):
context = {
'posts' : Post.objects.filter(tags__name__in=[request.GET.get('tag')])
}
return render(request, self.template_name, context)
return HttpResponse('result')
class BlogFullPostView(BlogBaseView, DetailView):
model = Post
template_name = 'full_post.html'
pk_url_kwarg = 'post_id'
context_object_name = 'post'
Thanks!
ListView class also has a get_context_data method, so you should override that instead of get method. Using super you'll get access to BlogBaseView.get_context_data and then you can extended the result.
Here's how:
class BlogIndexView(BlogBaseView, ListView):
queryset = Post.objects.all().order_by('-date_create')
template_name = 'index_blog.html'
context_object_name = 'posts'
def get_context_data(self, **kwargs):
# use the (super) force Luke
context = super(BlogIndexView, self).get_context_data(**kwargs)
if self.request.GET.get('tag'):
context['posts'] = Post.objects.filter(tags__name__in=[self.request.GET.get('tag')])
return context
If you are overriding ListView then it's not a good idea to override the get method, as you will lose a lot of the ListView functionality.
In this case, it would be a better idea to override get_queryset, and do the search there.
def get_queryset(self):
queryset = super(BlogIndexView, self). get_queryset()
if request.GET.get('tag'):
queryset = queryset.filter(tags__name=request.GET['tag'])
return queryset

Categories