Passing arguments to a form obtained by 'getattr()' - python

I'm creating a view which loads differents forms according to an argument given using the getattr() function:
form = getattr(forms, service.form)
but in the form I need my username to filter my files, so I have this:
class MyForm(forms.Form):
filename = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple)
K = forms.CharField(label='K', max_length=1)
fullOut = forms.CharField(label='fullOut', max_length=1)
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.user = kwargs.pop('user', None)
self.fields['filename'].queryset = userFile.objects.filter(self.user)
The problem is that I don't know how to pass the 'request.user' in my getattr() funtion. I know that if it was static it should be something like:
form = MyForm(user=request.user)
But I have tried somethings like:
form = getattr(forms, service.form, user=request.user)
And it doesn't work.I'm trying this but any idea of how list user files in a form will be welcomed.
Thanks in advance.

This doesn't have anything to do with you using getattr, the problem is in your __init__ method. You need to pop user before calling super().
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super(MyForm, self).__init__(*args, **kwargs)
You should instantiate the form as you usually do:
form = MyForm(user=request.user)
It doesn't matter whether MyForm is declared in the same module:
class MyForm(forms.Form):
my_field = forms.CharField()
form = MyForm(user=request.user)
or if you get the form class dynamically using getattr
MyForm = getattr(forms, service.form)
form = MyForm(user=request.user)

Related

How do I pass arguments to django forms?

I want to filter form fields querysets based on the user selected. Therefore, I want to pass user as argument to the form in order to filter fields querysets in the form's __init__ method. When I pass any arguments to the form I get the following error.
class UserDetailView(LoginRequiredMixin, FormMixin, DetailView):
model = TbUser
form_class = TbPeopleEntranceRightForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
form = TbPeopleEntranceRightForm(user=self.object)
context['form'] = form
return context
__init__() got an unexpected keyword argument 'user'
how do I pass the argument correctly, and how I get it in the __init__ form method?
Update:
class TbPeopleEntranceRightForm(forms.ModelForm):
def __init__(self, user, **kwargs):
super().__init__(**kwargs)
print(user)
# Use `self.user` here or in some other methods.
__init__() missing 1 required positional argument: 'user'
don't do it in get_context_data, it's made for something else.
Use get_form_kwargs instead:
class UserDetailView(LoginRequiredMixin, FormMixin, DetailView):
model = TbUser
form_class = TbPeopleEntranceRightForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["user"] = self.object
return kwargs
And in your forms.py:
def __init__(self, user=None, *args, **kwargs):
self.user = user
super().__init__(*args, **kwargs)
You need to add the parameter to the form's __init__ method:
class TbPeopleEntranceRightForm(forms.ModelForm):
...
def __init__(self, user=None, **kwargs):
super().__init__(**kwargs)
self.user = user
# Use `self.user` here or in some other methods.
Also, the correct way to then pass the user argument to the form is to override get_form_kwargs in the view, like #MojixCoder showed.

How to pass in variable into Django Form?

I've been reading lots of questions like this on stackoverflow but none seem to work. All I want to do is make a filtered form dropdown. I'm not sure how do go about doing it. I get the error that main is not defined... but I'm sure that's because it's not initialized or something? I'm very confused lol.
My form code looks like this:
class AssignForm(ModelForm):
class Meta():
model = Address
fields = ['overseer','publisher', 'status']
def __init__(self, *args, **kwargs,):
super(AssignForm, self).__init__(*args, **kwargs)
self.fields['publisher'].queryset = Publisher.objects.filter(service_group=main)
Here is my View:
def assignment(request, pk_a):
assign = Address.objects.get(id=pk_a)
num = request.user.overseer.publisher_set.first()
main = num.service_group.id
print(main)
I would like to use the variable: main inside my form dropdown so I can limit the dropdown relative to the overseer. How can this be accomplished? Thanks!
form = AssignForm(main, request.POST, instance=assign)
context = {'form':form,}
return render(request, 'sms/assign.html', context )
Change your form to
class AssignForm(ModelForm):
class Meta():
model = Address
fields = ['overseer','publisher', 'status']
def __init__(self, main, *args, **kwargs,):
super(AssignForm, self).__init__(*args, **kwargs)
self.fields['publisher'].queryset = Publisher.objects.filter(service_group=main)
and change your Form instantiation in views to
form = AssignForm(main, request.POST, instance=assign)

Django form with ModelMultipleChoiceField rendered empty

I have trouble setting up a form with a ModelMultipleChoiceField where the queryset depends on the user. My goal is to implement an export function.
My view looks like this:
class ExportView(FormView):
template_name = 'ExportTemplate.html'
def get(self, request, *args, **kwargs):
self.form_class = ExportForm(user = request.user)
return render(request, self.template_name, {'form': self.form_class})
def get_success_url(self):
return '/addrbook/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
return super().form_valid(form)
form:
class ExportForm(forms.Form):
def __init__(self, user, *args, **kwargs):
usersContacts = ContactManager().getAllUsersContacts()
self.contactList = forms.ModelMultipleChoiceField(queryset = usersContacts[str(user)])
print(usersContacts[str(user)])
super(ExportForm, self).__init__(*args, **kwargs)
I verified that the queryset is not empty, it contains a list of model objects.
My template looks like this:
<form method="post">{% csrf_token %}
{{ form }}
<input type="submit">
</form>
the only thing that gets rendered is the submit button.
Another thing that left me completely unsure of python basics is that this code:
class ExportForm(forms.Form):
contactList = forms.ModelMultipleChoiceField(queryset = [])
def __init__(self, user, *args, **kwargs):
usersContacts = ContactManager().getAllUsersContacts()
self.contactList.queryset = usersContacts[str(user)]
print(usersContacts[str(user)])
super(ExportForm, self).__init__(*args, **kwargs)
returned the runtime error:
'ExportForm' object has no attribute 'contactList'
How is it possible? the contactList member is part of the ExportForm class definition and 'self' should point to an object of that class.
Could someone explain to me why the form field is rendered empty and/or point me to a better way to pass the user to the form?
Edit: here are the changes i made to the answer to get it working, although i now stumbled upon a different problem(the field expects a queryset, and not a list of model objects):
View:
class ExportView(FormView):
template_name = 'ExportTemplate.html'
form_class = ExportForm
def get_form_kwargs(self):
kwargs = super(ExportView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
form:
class ExportForm(forms.Form):
contactList = forms.ModelMultipleChoiceField(queryset = Contact.objects.none())
def __init__(self, *args, **kwargs):
user = kwargs['user']
kwargs.pop('user', None)
super(ExportForm, self).__init__(*args, **kwargs)
usersContacts = ContactManager().getAllUsersContacts()
self.fields['contactList'].queryset = usersContacts[str(user)]
print(self.fields['contactList'].queryset)
First of all, you should pass the user to the form every time you instantiate it, not just in the get method. The way to do this with FormView is to override get_form_kwargs.
def get_form_kwargs(self):
kwargs = super(ExportForm, self).get_form_kwargs()
kwargs[user] = self.request.user
return kwargs
You can then remove your get() method.
Then, in your form class, you should use the none() method instead of an empty list to get an empty queryset. In the __init__ method you can pop the user from kwargs, and then call super() before you edit the fields. You edit the contactList field via self.fields instead of self.contactList. Note that the recommended style for field names in Django is contact_list instead of contactList.
class ExportForm(forms.Form):
contactList = forms.ModelMultipleChoiceField(queryset=YourModel.objects.none())
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(ExportForm, self).__init__(*args, **kwargs)
usersContacts = ContactManager().getAllUsersContacts()
self.fields['contactList'].queryset = usersContacts[str(user)]
You haven't shown the ContactManager() code, but using str(user) as the dictionary key looks fragile. It would probably be better to use user.pk or user.username instead.

Python - Django - Pass Argument To Form Clean Method

I am trying to pass a variable to a ModelForm clean method using __init__ arguments but have had no success so far - I looked at various posts on StackOverflow but none seemed to help.
My code is the following:
forms.py
class property_booking_form(forms.ModelForm):
check_in_date = forms.DateField(widget=SelectDateWidget)
check_out_date = forms.DateField(widget=SelectDateWidget)
class Meta:
model = Properties_bookings
fields = ['check_in_date', 'check_out_date']
def __init__(self, property_id):
self.property_id = property_id
super(property_booking_form, self).__init__(self, property_id)
def clean(self):
check_in_date = self.cleaned_data.get('check_in_date')
check_out_date = self.cleaned_data.get('check_out_date')
property_min_nights = Properties.objects.get(id=self.property_id).property_minimum_nights
...
views.py
def view(request):
...
if request.method == 'POST':
booking_form = property_booking_form(request.POST, property_id=property_id)
if booking_form.is_valid():
...
else:
booking_form = property_booking_form(property_id=property_id)
return render(...)
This raises the following error:
'property_booking_form' object has no attribute 'get'
Which seems to be related to the widget as per the error description:
Exception Location:
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/forms/widgets.py in value_from_datadict, line 1058
The form works fine without the overriding __init__.
Does anyone know what would be the underlying cause of this issue?
Thanks.
Your __init__ method should accept *args and **kwargs, you should pass these when you call the superclass' __init__ method, rather than self and property_id.
def __init__(self, property_id, *args, **kwargs):
self.property_id = property_id
super(property_booking_form, self).__init__(*args, **kwargs)
You also need to change the way you instantiate the form in the view, since property_id is the first argument. For example:
if request.method == 'POST':
booking_form = property_booking_form(property_id=property_id, data=request.POST)
Alternatively, you can remove property_id from the signature, and pop it from kwargs. In this case, no changes to the views are required.
def __init__(self, *args, **kwargs):
self.property_id = kwargs.pop('property_id')
super(property_booking_form, self).__init__(*args, **kwargs)
This has been solved by amending __init__ as follows:
def __init__(self, *args, **kwargs):
self.property_id = kwargs.pop('property_id', None)
super(property_booking_form, self).__init__(*args, **kwargs)

Django pass User instance to Forms when form is created

I have a Django form and l would like to pass a user instance when the form is created
First Approach
This is where l create the form and pass the instance of the user:
form = QuestionForm(request.user, request.POST)
And inside the QuestionForm
def __init__(self, user, *args, **kwargs):
super(QuestionForm, self).__init__(*args, **kwargs)
self.data = user
log.info(self)
Study.objects.filter(owner = self.data.id))
Second Approach
This is where l create the form and pass the request:
form = QuestionForm ( ..., request=request)
And inside the QuestionForm
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
super(MyForm, self).__init__(*args, **kwargs)
ref = forms.ModelChoiceField(queryset=Study.objects.filter(owner = self.request.user.id))
Now l am getting an error that self is not define and as such l cannot get the user id to query the Study class
Any help would be much appreciated
If you do this code in field declaration section like
class QuestionForm(forms.Form):
ref = forms.ModelChoiceField(queryset=Study.objects.filter(owner=...)
then it will not work because it still doesn't have self variable.
You can do this in init method like this
class QuestionForm(forms.Form):
ref = forms.ModelChoiceField()
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['ref'].queryset = Study.objects.filter(owner=request.user)

Categories

Resources