I'm little confused about which of the following functions called the other one
is
___init____(self,*args,**kwargs) called get_forms_kwargs(self)
or
get_forms_kwargs(self) called ___init____()
as I made the following mixin:
class RequestformattachMixin(object):
def get_form_kwargs(self):
kwargs=super().get_form_kwargs()
kwargs['request']=self.request
print(kwargs)
return kwargs
and removed the get_forms_kwargs(self) from the CBV in view.py and instead updated the CBV to let it inherit from the mixin
class LoginView(NextUrlMixin,RequestformattachMixin,FormView):
form_class = login_page
template_name = 'login.html'
success_url = '/'
and didn't call the get_forms_kwargs(self) in CBV and it's working with no errors.
please need an explanation for that.
Related
Let's say I want to use the LoginRequiredMixin and a UserPermissionMixin created by myself and apply them to all the views in an app. This is just an example, I might also have mixins that add some context or do other stuff.
I could do it manually, for example this view:
class MyCreateView(LoginRequiredMixin, UserPermissionMixin, CreateView)
But, since I have many views and I might have other specific mixins for some views, this gets messy and hard to manage.
One solution that came to mind would be to create new classes for the generic views:
class DecoratedCreateView(LoginRequiredMixin, UserPermissionMixin, CreateView):
pass
class DecoratedDetailView(LoginRequiredMixin, UserPermissionMixin, DetailView):
pass
class DecoratedUpdateView(LoginRequiredMixin, UserPermissionMixin, UpdateView):
pass
class DecoratedDeleteView(LoginRequiredMixin, UserPermissionMixin, DeleteView):
pass
and then, use these as my generic views:
class MyCreateView(DecoratedCreateView)
Is this a good approach? Do I have to add any methods in the classes above or do I just leave them blank and it'll work as expected?
Is there any other way to achieve this, maybe in urls.py ?
Your approach is good. I've been doing so for some projects with a slight difference:
myapp/views/generic.py
from django.views.generic import (
CreateView as BaseCreateView,
DetailView as BaseDetailView,
UpdateView as BaseUpdateView,
DeleteView as BaseDeleteView,
)
__all__ = ['MyappMixin', 'CreateView', 'DetailView', 'UpdateView', 'DeleteView']
class MyappMixin(LoginRequiredMixin, UserpermissionMixin):
pass
class CreateView(MyappMixin, BaseCreateView):
pass
class DetailView(MyappMixin, BaseDetailView):
pass
class UpdateView(MyappMixin, BaseUpdateView):
pass
class DeleteView(MyappMixin, BaseDeleteView):
pass
myapp/views/base.py
from .generic import CreateView
class MyCreateView(CreateView):
pass
It works fine, without much hassle, and allows you to easily skip the mixin exceptionally if needed.
According to the usecase, another solution might be to use middlewares or context processors.
class MyMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
is_in_myapp = request.resolver_match.app_name == 'myapp'
if is_in_myapp and not request.user.is_authenticated:
response = HttpResponse("Permission denied", status=403)
else:
response = self.get_response(request)
return response
I have written a Class based view which acts as a base view for several other class based views. So the other class based views is just subclassing the base view, but the subclassed views are not getting the effect of the get_context_data or form_valid functions, so the context variables set in the base view is not getting sent to the template when requests are executing using the view subclassing the base view, they are only being sent when the base view itself it used.
Class based view:
class PortfolioNewBase(CreateView):
url_name = ''
post_req = False
def form_valid(self, form):
self.post_req = True
return super(PortfolioNewBase, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(PortfolioNewBase, self).get_context_data(**kwargs)
context['profile_id'] = self.kwargs['profile_id']
context['post_req'] = self.post_req
return super(PortfolioNewBase, self).get_context_data(**kwargs)
def get_success_url(self):
return reverse(self.url_name, args=self.kwargs['profile_id'])
When creating a new class based view which is one of the views that will be using this code it does not get access to the "profile_id" or "post_req" variables for some reason, it does not get sent to the template, but if you only use the base view written above that view will send the variables so that they are available in the view.
Code for one of the class based views using this base view written above:
class PortfolioNewDividend(PortfolioNewBase):
model = Dividend
form_class = DividendForm
template_name = 'plan/portfolio/new/new_dividend.html'
url_name = 'plan:investment-info-dividends-new'
The form works and everything, but the variables in the get_context_data in the parent is apparently not being inherited for some reason which is kind of the point here and the form_valid function is not being run either, the value of the post_req on POST requests done by the PortfolioNewDividend class based view still has the value False.
Why is the PortfolioNewDividend not running the get_context_data and form_valid functions when a request is executed with that view but the functions run if you use the base clase (written above) only ?
One super call too many in there. Change as follows:
def get_context_data(self, **kwargs):
context = super(PortfolioNewBase, self).get_context_data(**kwargs)
context['profile_id'] = self.kwargs['profile_id']
context['post_req'] = self.post_req
return context # You must actually return the modified context!
I have a django create view and I want to call the __init__ of the form class and I don't know how to do that.
class PersonCreateView(CreateView):
model = Person
form_class = PersonForm
In the form class I made some logic to redefine the queryset of some combos. My problem is that I don't know how to call the __init__ method, or any other method, of the PersonForm
Thanks in advance for any help.
You shouldn't call it yourself. You can override get_form_kwargs to provide extra arguments to pass to the form instantiation.
class PersonCreateView(CreateView):
model = Person
form_class = PersonForm
def get_form_kwargs(self, *args, **kwargs):
form_kwargs = super(PersonCreateView, self).get_form_kwargs(*args, **kwargs)
form_kwargs['my_extra_queryset_param'] = get_my_extra_queryset()
return form_kwargs
The init method is actually called automatically by the class when a new instance of the object is instantiated.
Consider the following example:
class House():
__init__(self,x,y):
self.x = x
self.y = y
self.z = x*y
To call init, we just do the following:
h = House(5,7)
This will create the object and automatically invoke the init function. It works the same way for django views.
I see Daniel beat me to an answer, perhaps his is more what you're looking for. Anyways, hope this helps a little at least!
I would like to dynamically change the form_class of an UpdateView CBV in Django 1.6.
I've tried to do this using the get_context_data(), but that didn't help since the form is already initialized. So it will need to happen during __init__, I guess.
Here's what I've tried on __init__:
class UpdatePersonView(generic.UpdateView):
model = Person
form_class = ""
def __init__(self, *args, **kwargs):
super(UpdatePersonView, self).__init__(*args, **kwargs)
person = Person.objects.get(id=self.get_object().id)
if not person.somefield:
self.form_class = OneFormClass
elif person.somefield:
self.form_class = SomeOtherFormClass
I'm stuck with a 'UpdatePersonView' object has no attribute 'kwargs' error message when executing person = Person.objects.get(id=self.get_object().id).
When manually specifying the id (e.g. id=9), then the setup works.
How can I get the args/kwargs inside the init method that I'm overriding? Particularly I would need access to the pk.
You should simply override get_form_class.
(Also I'm not sure why you're querying for person: that object is the same is self.get_object() already, so there's no point getting the ID of that then querying again.)
def get_form_class(self):
if self.object.somefield:
return OneFormClass
else:
return SomeOtherFormClass
I'm trying to get two parameters out of the URL to add to my context.
This is the URL:
url(r'^company/(?P<company>[\w\-\_]+)/?/(?P<program>[\w\-\_]+)/?$', RegistrationView.as_view(),
name='test'),
The view:
class RegistrationView(RegistrationMixin, BaseCreateView):
form_class = AppUserIntroducerCreateForm
template_name = "registration/register_introducer.html"
slug_field = 'company'
def get_context_data(self, *args, **kwargs):
context = super(RegistrationIntroducerView, self).get_context_data(**kwargs)
print(self.get_slug_field())
context['company'] = ??????
context['program'] = ??????
return context
I have tried everything to get the values self.company, kwargs['company'] etc, what I'm I doing wrong here?
Here is SO reference for you .
context = super(RegistrationView, self).get_context_data(**kwargs)
print(self.get_slug_field())
context['company'] = self.kwargs['company']
context['program'] = self.kwargs['program']
Try this
self.kwargs['company']
self.kwargs['program']
The as_view class method of the base class (View) is a closure around a pretty simple view function that accepts the arguments defined in urls.py. It then assigns them as a dictionary to self.kwargs attribute of the view class. Therefore what you need to do in order to access this data is:
self.kwargs['company']
Also, if you inherited your RegistrationView from CreateView instead of BaseCreateView, you'd get SingleObjectTemplateResponseMixin mixed in with your view and the slug_field (along with model or queryset) would be used by get_object method to fetch the desired company. Furthermore, the context variable company containing the Company instance would be already set for you and you would not have to set it yourself.