how to access session variable inside form class - django

Hi i have a session variable city, how to access it inside form class.
Something like this
class LonginForm(forms.Form):
current_city=request.city

A Form has by default no access to the request object, but you can make a constructor that takes it into account, and processes it. For example:
class LonginForm(forms.Form):
def __init__(self, *args, request=None, **kwargs):
super(LonginForm, self).__init__(*args, **kwargs)
self.request = request # perhaps you want to set the request in the Form
if request is not None:
current_city=request.city
In the related views, you then need to pass the request object, like:
def some_view(request):
my_form = LonginForm(request=request)
# ...
# return Http Response
Or in a class-based view:
from django.views.generic.edit import FormView
class LonginView(FormView):
template_name = 'template.html'
form_class = LonginForm
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(LonginView, self).get_form_kwargs(*args, **kwargs)
kwargs['request'] = self.request
return kwargs

Related

Redirect to url from "post-only" view

I have the following setup for a combination of a DetailView and a FormView:
class EventBookView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
view = EventBookBaseView.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = EventBookFormView.as_view()
return view(request, *args, **kwargs)
class EventBookBaseView(DetailView):
template_name = "event_book.html"
model= Event
context_object_name = 'event'
class EventBookFormView(SingleObjectMixin, FormView):
template_name = "event_book.html"
form_class = PersonalInfoForm
model = Event
context_object_name = 'event'
def post(self , request , *args , **kwargs):
#do stuff
...
return redirect('user_bookings')
Unfortunately, the redirect to the url with the name 'user_bookings' is not working. How can I redirect to that url?
thanks!
You can use success_url, when Form is properly processed then view is redirected.
eg.
class MyFormView(FormView):
success_url = reverse_lazy('user_bookings')
EDIT: changed reverse to reverse_lazy
A POST method should not return a redirection.
If you need so, try to use HttpResponseRedirect.
Like:
return HttpResponseRedirect('/user_bookings/')

django SetPasswordForm and AdminPasswordChangeForm

hi im trying to use the above forms - but i get
__init__() takes at least 2 arguments (1 given)
i get to the form that it should show but it never save me the new password
i also needed to change the:
def __init__(self, user, *args, **kwargs):
self.user = user
super(AdminPasswordChangeForm, self).__init__(*args, **kwargs)
to:
def __init__(self, *args, **kwargs):
super(AdminPasswordChangeForm, self).__init__(*args, **kwargs)
since it doesnt get a user arg.
any ideas why?
thx
============================ edit =============================================
class set(FormView):
model = User
form_class = AdminPasswordChangeForm
template_name = 'set.html'
def dispatch(self, request, *args, **kwargs):
return super(set, self).dispatch(request, *args, **kwargs)
def get_form_kwargs(self):
kwargs = super(set, self).get_form_kwargs()
kwargs['user_to_update'] = the user
return kwargs
the init:
def __init__(self, *args, **kwargs):
self.user = kwargs['user_to_update']
kwargs.pop('user_to_update')
super(AdminPasswordChangeForm, self).__init__(*args, **kwargs)
Use the existing form. Overide the view's get_form_kwargs method to pass the expected arguments to the form, instead of changing the __init__ method, which will break other things.
In order to save the password, you need to override the form_valid method and call form.save().
For create and update views, you don't always need to override form_valid, because the default behaviour is to save the form and redirect. For FormView, the default behaviour is simply to redirect, so you do have to override it to get it to do anything useful.
class SetPasswordView(FormView):
form_class = AdminPasswordChangeForm
template_name = 'set.html'
success_url = '/thanks/'
def get_form_kwargs(self):
kwargs = super(set, self).get_form_kwargs()
kwargs['user_to_update'] = the user
return kwargs
def form_valid(self, form):
form.save()
return super(SetPasswordView, self).form_valid(form)

Django class based views: variable across classes

I have a mixin called GroupAwareMixin in a mixins.py file:
class GroupAwareMixin(object):
group = None
def get_group(self):
self.group = self.bridge.get_group()
def dispatch(self, request, *args, **kwargs):
if not self.group:
self.get_group()
In the views.py file I have the following ListView which inherits from the above GroupAwareMixin:
class ChatListView(LoginRequiredMixin, GroupAwareMixin, ListView):
model = Chat
template_name = 'chat/home.html'
Further I have a Chat class in my views.py file, where I would like to access the group variable from the GroupAwareMixin class above. How I am able to access the group variable in the Chat class?
class Chat(ws.WS, ChatListView):
def on_message(self, websocket, msg):
slug = self.group
I tried to inherit from ChatListView, but the self.group in the Chat class is None.
The LoginRequiredMixin defines the following:
class LoginRequiredMixin(AccessMixin):
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated():
if self.raise_exception:
raise PermissionDenied # return a forbidden response
else:
return redirect_to_login(request.get_full_path(),
self.get_login_url(),
self.get_redirect_field_name())
return super(LoginRequiredMixin, self).dispatch(
request, *args, **kwargs)

django: how to access current request user in ModelForm?

In my implementation of ModelForm, I would like to perform different types of validation checks based on whether current user is superuser. How can I access the current request user?
If you're using Class Based Views (CBVs) then passing an extra argument in the form constructor (e.g. in get_forms_class) or in form_class will not work, as <form> object is not callable will be shown.
The solution for CBVs is to use get_form_kwargs(), e.g.:
views.py:
class MyUpdateView(UpdateView):
model = MyModel
form_class = MyForm
# Sending user object to the form, to verify which fields to display/remove (depending on group)
def get_form_kwargs(self):
kwargs = super(MyUpdateView, self).get_form_kwargs()
kwargs.update({'user': self.request.user})
return kwargs
forms.py:
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user') # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole
super(MyForm, self).__init__(*args, **kwargs)
# If the user does not belong to a certain group, remove the field
if not self.user.groups.filter(name__iexact='mygroup').exists():
del self.fields['confidential']
you can pass the user object as an extra argument in the form constructor.
e.g.
f = MyForm(user=request.user)
and the constructor will look like:
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user',None)
super(MyForm, self).__init__(*args, **kwargs)
and then use user in the clean_XX forms as you wish
My small addition,
I had a requirement where one of the model choice fields of the form is dependent on the request.user, and it took a while to take my head around.
The idea is that
you need to have a __init__ method in the model form class,
and you access the request or other parameters from the arguments of the __init__ method,
then you need to call the super constructor to new up the form class
and then you set the queryset of the required field
code sample
class CsvUploadForm(forms.Form):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(CsvUploadForm, self).__init__(*args, **kwargs)
self.fields['lists'].queryset = List.objects.filter(user=user)
lists = forms.ModelChoiceField(queryset=None, widget=forms.Select, required=True)
as you can see, the lists variable is dependent on the current user, which is available via request object, so we set the queryset of the field as null, and its assigned dynamically from the constructor later.
Take a look into the order of the statements in the above code
you can pass the user variable like this from the view file
form = CsvUploadForm(user=request.user)
or with other POST, FILE data like below
form = CsvUploadForm(request.POST, request.FILES, user=request.user)
You may reference the user object using the instance attribute within the instance it self.
Ex; self.instance.user
class StatusForm(ModelForm):
# def __init__(self, *args, **kwargs):
# self.user = kwargs.pop('user', None)
# super(StatusForm, self).__init__(*args, **kwargs)
class Meta:
model = Status
fields = [
'user',
'content',
'image'
]
def clean_content(self):
content = self.cleaned_data.get("content", None)
if len(content) > 240:
raise ValidationError(f"Hey {self.instance.user.username}, the content is too long")
return content
This worked for me, when I am not sending form in context explicitly in get_context_data:
views.py
class MyView(FormView):
model = MyModel
form_class = MyForm
def get_form_kwargs(self):
kwargs = super(MyView, self).get_form_kwargs()
kwargs.update({'user': self.request.user})
return kwargs
form.py
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(MyForm, self).__init__(*args, **kwargs)
if not self.user.groups.filter(name__iexact='t1_group').exists():
del self.fields['test_obj']
When sending form explicitly in get_context_data we can use and this is forms.Form :
views.py
class MyView(FormView):
model = MyModel
form_class = MyForm
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['form'] = self.form_class(self.request.user)
return context
forms.py
class MyForm(forms.Form):
def __init__(self, user,*args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
if not user.groups.filter(name__iexact='t1_group').exists():
del self.fields['test_obj']

Passing a user, request to forms

How would I pass a user object or a request to my form for validation?
For example, I want to be able to do something like this --
class Form(forms.Form):
...
def clean(self)
user = request.user # how to get request.user here?
user = User # how to pass the actual User object?
Thank you.
Just pass it into the constructor and store it as an instance variable:
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
super(MyForm, self).__init__(*args, **kwargs)
def clean(self):
print self.request.user
...
In your view:
form = MyForm(..., request=request)
And if using a class-based view (a CreateView in this example):
class MyCreateView(CreateView):
...
def get_form_kwargs(self):
kwargs = super(MyCreateView, self).get_form_kwargs()
kwargs.update({'request': self.request})
return kwargs