Django dynamic ModelChoiceField field - python

Trying to pass in a variable to help with the queryset that ModelChoiceField requires. Getting error TypeError: __init__() takes at least 2 arguments (1 given) and I'm not sure why. See code below.
forms.py
class uploadForm(forms.Form):
def __init__(self, trainer, *args, **kwargs):
super(uploadForm, self).__init__(trainer, *args, **kwargs)
self.fields["client"] = forms.ModelChoiceField(
queryset=Trainee.objects.filter(trainer=trainer),
widget=forms.Select(attrs={'class': 'signup-form-input'})
)
views.py
uploadForm = uploadForm(trainer)

You are getting this exception because following code line is wrong:
super(uploadForm, self).__init__(trainer, *args, **kwargs)
In init method. It should be just
super(uploadForm, self).__init__(*args, **kwargs)
as in super class's constructor trainer is not an argument.
Anyways, the way you are doing is wrong! you should implement your form class as below:
forms.py:
class UploadForm(forms.Form):
def __init__(self, *args, **kwargs):
super(UploadForm, self).__init__(*args, **kwargs)
self.fields["client"] = forms.ModelChoiceField(
queryset=Trainee.objects.filter(trainer=kwargs['trainer']),
widget=forms.Select(
attrs={
'class': 'signup-form-input'
}
))
views.py:
uploadform = UploadForm(trainer=trainer)
One more note: If trainer is not a field in your form then popup trainer before to call super class constructor as:
class UploadForm(forms.Form):
def __init__(self, *args, **kwargs):
trainer = kwargs.pop('trainer', None)
super(UploadForm, self).__init__(*args, **kwargs)
self.fields["client"] = forms.ModelChoiceField(
queryset=Trainee.objects.filter(trainer=trainer),
widget=forms.Select(
attrs={
'class': 'signup-form-input'
}
))
views.py is as I given in my answer.

Related

Stuck in passing and catching kwargs

Python 3.5.2
Could you help me understand how parameters are transmitted to the method.
Just in case: this is Django but the question seems to be just about Python.
As far as I can catch from the Django's documentation: if I pass form_kwargs to a formset like this, several forms will be created. And in the form I expect to catch the parameter in **kwargs.
class MyArticleForm(ArticleForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(MyArticleForm, self).__init__(*args, **kwargs)
formset = ArticleFormSet(form_kwargs={'user': user})
Well, this is not working:
File "/home/michael/workspace/formsets/general/forms.py", line 15, in __init__
self.user = kwargs.pop('user')
KeyError: 'user'
If I step in the debugger: kwargs definitely doesn't contain any 'user'. And args is an empty tuple.
But this works:
class MyArticleForm(ArticleForm):
def __init__(self, user=None, *args, **kwargs):
pass
And this works:
class MyArticleForm(ArticleForm):
def __init__(self, user, *args, **kwargs):
pass
Well, I can't understand how can I catch this parameter in using kwargs?
///////////
ADDED LATER
ArticleFormSet = formset_factory(MyArticleForm)
def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False,
can_delete=False, max_num=None, validate_max=False,
min_num=None, validate_min=False):
pass
class BaseFormSet(object):
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, form_kwargs=None):
...
self.form_kwargs = form_kwargs or {}
....

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)

django: subclass FormView twice and override form_class

Im trying to build a FormView for an app that needs to be subclassed afterwards. Sadly I was not able to set the formclass by the subclass.
My Code:
class EventCreateView(FormView):
template_name='Events/add_event_form.html'
success_url = reverse_lazy('events_list')
form_class = None # replaced by __init__ function
def __init__(self, *args, **kwargs):
self.form_class=EventForm
return super(EventCreateView, self).__init__(*args, **kwargs)
#other functions, not shown here ..
class TrainingCreateView(EventCreateView):
def __init__(self, *args, **kwargs):
self.form_class=TrainingForm
return super(TrainingCreateView, self).__init__(*args, **kwargs)
urls.py:
urlpatterns = patterns('',
url(r'event/event/add/$', EventCreateView.as_view(), name='event_add'),
url(r'event/training/add/$', TrainingCreateView.as_view(), name='training_add'),
)
What am I doing wrong?
Try this instead:
class EventCreateView(FormView):
template_name='Events/add_event_form.html'
success_url = reverse_lazy('events_list')
form_class = EventForm
...
class TrainingCreateView(EventCreateView):
form_class = TrainingForm
This doesn't work for the TrainingCreateView because the __init__ view does the following
It sets self.form_class = TrainingForm
super(TrainingCreateView, self).__init__(*args, **kwargs) calls the __init__ of EventCreateView ...
Which sets self.formclass = EventForm
You can get around this by changing the order of your __init_ method. Note that the method doesn't have to return anything.
class TrainingCreateView(EventCreateView):
def __init__(self, *args, **kwargs):
super(TrainingCreateView, self).__init__(*args, **kwargs)
self.form_class = TrainingForm
However, from the code you've written, it is not clear why you need to set self.form_class in the __init__ method, rather than just setting it as a class attribute. If you need to set it dynamically, a better option might be to override get_form_class instead.

Django: Filter ModelChoiceField by user

I have a model along with a ModelForm based on that model. The ModelForm contains a ModelMultipleChoice field, which I specify in the subclass of my ModelForm:
class TransactionForm(ModelForm):
class Meta:
model = Transaction
def __init__(self, *args, **kwargs):
super(TransactionForm, self).__init__(*args, **kwargs)
self.fields['category'] = forms.ModelChoiceField(queryset=Category.objects.filter(user=user))
As you can see, I need to filter the Category queryset by user. In other words, users should only see their own categories on the drop down. But how can I do this when user, or more specifically, request.user, is not available in a Model instance?
Edit: Adding my subclass of the CBV:
class TransUpdateView(UpdateView):
form_class = TransactionForm
model = Transaction
template_name = 'trans_form.html'
success_url='/view_trans/'
def get_context_data(self, **kwargs):
context = super(TransUpdateView, self).get_context_data(**kwargs)
context['action'] = 'update'
return context
I tried form_class = TransactionForm(user=request.user) and I'm getting a NameError saying that request was not found.
You can pass request.user to form init in view:
def some_view(request):
form = TransactionForm(user=request.user)
and add user parameter to form __init__ method (or pop it from kwargs in form):
class TransactionForm(ModelForm):
class Meta:
model = Transaction
# def __init__(self, *args, **kwargs):
# user = kwargs.pop('user', User.objects.get(pk_of_default_user))
def __init__(self, user, *args, **kwargs):
super(TransactionForm, self).__init__(*args, **kwargs)
self.fields['category'] = forms.ModelChoiceField(
queryset=Category.objects.filter(user=user))
update: in class based views you can add extra parameter to form init in get_form_kwargs:
class TransUpdateView(UpdateView):
#...
def get_form_kwargs(self):
kwargs = super(YourView, self).get_form_kwargs()
kwargs.update({'user': self.request.user})
return kwargs

Context processor in forms.py

context_processor.py:
def max_min(request):
"""
some code. request required, because I need
calculate some information about each user
"""
return {'max': max, 'min':max}
forms.py:
class MaxMin(forms.Form):
my_field = forms.IntegerField(
min_value=min, max_value=max, required=True,
widget=forms.NumberInput(attrs={'class':'form-control',
'required': 'true'}))
So, I have code in context_processor.py (it uses on all pages of site), that I want use in my forms.py. But I dont know, how to import and use it. max_min needs request, but in forms.py I dont have it.
Yes, I know, I can use {{min}} and {{max}} in forms html, without forms.py, but then I need to check in code, whats values I got through POST.
Thanks.
UPDATE:
class MAxMin(forms.Form):
def __init__(self, req, *args, **kwargs):
super(MAxMin, self).__init__(*args, **kwargs)
self.request = req
def mymethod(self):
return max_min(self.request)
my_field = forms.IntegerField(
min_value=mymethod(), required=True,
widget=forms.NumberInput(attrs={'class':'form-control',
'required': 'true'}))
What about injecting request at the time of instantiation?
#views.py
form = MyForm(request)
#forms.py
def __init__(self, req, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.request = req
#somewhere in your form's body
max_min(self.request)
UPDATE
Well, your situation appears to be different from what I've expected.
Consider this approach:
class MAxMin(forms.Form):
my_field = forms.IntegerField(required=True,
widget=forms.NumberInput(attrs={'class':'form-control',
'required': 'true'}))
def __init__(self, req, *args, **kwargs):
super(MAxMin, self).__init__(*args, **kwargs)
self.fields['my_field'].min_value = max_min(req)

Categories

Resources