Unexpected Keyword argument using formset_factory - django

I'm working on a project in which a teacher can add marks to his students, I want to use formset_factory so the teacher can add many marks at the same time, but I want a teacher to see only his students, and not the students who are not in his class.
I got it when using a single form, but when I try to use the formset_factory, I get this error:
init() got an unexpected keyword argument 'request'
This is my working code
in views:
class AddNotaBlock(FormView):
template_name='notas/insertar_nota.html'
form_class= NotaCreateFormTeacher
success_url= reverse_lazy('home')
def get_form_kwargs(self):
""" Passes the request object to the form class.
This is necessary to only display members that belong to a given user"""
kwargs = super(AddNotaBlock, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
in forms:
class NotaCreateFormTeacher(ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(NotaCreateFormTeacher, self).__init__(*args, **kwargs)
usuario=self.request.user
profe=Teacher_profile.objects.get(profesor=usuario)
colegio=profe.colegio
self.fields['Username'].queryset = Student_profile.objects.filter(
colegio=colegio)
class Meta:
model = Nota
fields = ('Username', 'nota', 'colegio')
widgets= {'colegio':HiddenInput()}
formset=formset_factory(NotaCreateFormTeacher, extra=2)
when I use:
form_class= NotaCreateFormTeacher
Everything works (but only a form is displayed)
If I use:
form_class=formset
I get the unexpected keyword argument error:
init() got an unexpected keyword argument 'request'
What I'm I doing wrong?
Thanks for helping.

You pass this as form_kwargs=… parameter [Django-doc], so:
class AddNotaBlock(FormView):
template_name = 'notas/insertar_nota.html'
form_class = formset
success_url = reverse_lazy('home')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.setdefault('form_kwargs', {})['request'] = self.request
return kwargs

Related

UpdateIssueForm.__init__() missing 1 required keyword-only argument: 'pk'

I tried making an update view using class-based views. I have not known how to pass this kwarg['pk'] to the view. I have ended up with an error. Here is the view and the form
View
class UpdateTeacherIssueView(LoginRequiredMixin,UpdateView):
model = TeacherIssue
form_class = UpdateTeacherIssueForm
template_name = 'crud_forms/edit_teacher_issue.html'
success_url = reverse_lazy('view_student') #To be changed
def get_form_kwargs(self):
kwargs = super(UpdateTeacherIssueView, self).get_form_kwargs()
kwargs['school'] = self.request.user.school
kwargs['issuer'] = self.request.user
#kwargs['pk'] = self.request.id
return kwargs
The form
class UpdateTeacherIssueForm(forms.ModelForm):
"""Edit TeacherIssue Form"""
def __init__(self,*args, pk, school,issuer, **kwargs):
super(TeacherIssueForm, self).__init__(*args, **kwargs)
self.fields['issuer'].initial = issuer
self.fields['book_id'].queryset = Books.objects.filter(school=school,no_of_books=1).select_related('subject')
self.fields['borrower_teacher'].initial = pk
class Meta:
model = TeacherIssue
fields = ['issuer','book_id','borrower_teacher','issue_date']
widgets = {
'borrower_teacher':forms.TextInput(attrs={"class":'form-control','type':'hidden'}),
"issue_date":forms.TextInput(attrs={"class":"form-control"}),
'issuer':forms.TextInput(attrs={"class":'form-control','type':'hidden'}),
'book_id':Select2Widget(attrs={'data-placeholder': 'Select Book','data-width': '100%'},)
}
This is the error message
UpdateTeacherIssueForm.init() missing 1 required positional
argument: 'pk'
your init function in ModelForm is not good:
def __init__(self, pk, school,issuer,*args, **kwargs):
super(UpdateTeacherIssueForm, self).__init__(*args, **kwargs)
self.fields['issuer'].initial = issuer
self.fields['book_id'].queryset = Books.objects.filter(school=school,no_of_books=1).select_related('subject')
self.fields['borrower_teacher'].initial = pk
*args and **kwargs have to be placed at end of arguments function.
and In call of super you have to set the name of your current class.
You have to uncomment the kwargs['pk'] = self.request.id
Not sure if it is the problem: you do not show any error.

django unable to pass request to form while using formset. Produces `__init__() got an unexpected keyword argument 'request'`

#forms.py
class RequestModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
super(RequestModelForm, self).__init__(*args, **kwargs)
class BusinessForm(RequestModelForm):
class Meta:
model = Business
fields = ('title', 'stitle', 'gstin', 'address')
def clean_gstin(self):
user = self.request.user
gstin = self.cleaned_data['gstin'].upper()
if Business.objects.filter(owner=user, gstin=gstin).exists():
raise ValidationError("A Business with that GSTIN already exists")
return gstin
#views.py
class BaseFormView(FormView):
def get_form_kwargs(self):
kwargs = super(BaseFormView, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.save()
return super(BaseFormView, self).form_valid(form)
class Meta:
abstract = True
class BusinessCreateView(BaseFormView):
BusinessFormSet = formset_factory(BusinessForm, extra=3)
form_class = BusinessFormSet
success_url = '/dashboard'
template_name = "business/business_create_form.html"
Everything works well if I set extra=1 for the formset_factory. But when extra = 2 or something greater than 1, the error is thrown: __init__() got an unexpected keyword argument 'request'
I have identified the problem here. Since I'm popping request inside the __init__ function of RequestModelForm(which is called multiple times when extra is set to more than 1). And there is no request since it is already been popped.
I tried doing self.request = kwargs.get("request") instead of self.request = kwargs.pop("request"). But this throws another error
'BusinessForm' object has no attribute 'request'.
How to overcome this? Any Help?
You would need to pass the extra kwarg request to the form, but the BusinessFormSet needs to have this information explicitly. Overwriting the get_form_kwargs method in the FormView doesn't work in the way you've described because it'll pass all these as kwargs to what you have defined as form_class.
See https://docs.djangoproject.com/en/2.1/topics/forms/formsets/#passing-custom-parameters-to-formset-forms
For example probably what would work is:
class BaseFormView(FormView):
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['form_kwargs'] = {'request': self.request}
return kwargs
...

Django 1.11 pass kwarg to modelform field

I would like to pass a kwarg to set a modelform field but im struggling to figure out how to do it.
My URL is as follows:
url(r'^tent/create/(?P<munc>\d+)',views.TentCreate.as_view(),name='tent_create'),
My view is simply:
class TentCreate(CreateView):
model = Tent
form_class = TentForm
And my form:
class TentForm(ModelForm):
class Meta:
model = Tent
exclude =('asfo','niho')
def __init__(self, *args, **kwargs):
super(TentForm, self).__init__(*args, **kwargs)
self.fields['primary'].queryset = Mark.objects.filter(munc=self.kwargs['munc'])
from the model:
class Tent(models.Model):
primary = models.ForeignKey(Mark,on_delete=models.CASCADE)
I can render the form fine without overriding def __init, with no filtering applied to the 'primary' field.
However attempting to use the def __init code I've described above to pass the munc kwarg to the form field is resulting in the following error:
"'TentForm' object has no attribute 'kwargs'"
I've been going around in circles trying to work through this so I would be really appreciative if anyone is able to provide me some guidance to solve this. This is my first Django project so I'm learning how I go so I assume I have made some fundamental error somewhere here!
Try overriding get_form_kwargs method:
views.py
class TentCreate(CreateView):
model = Tent
form_class = TentForm
def get_form_kwargs(self):
kwargs = super(TentCreate, self).get_form_kwargs()
kwargs.update({'munc': self.kwargs['munc']})
return kwargs
forms.py
class TentForm(ModelForm):
class Meta:
model = Tent
exclude =('asfo','niho')
def __init__(self, *args, **kwargs):
munc = kwargs.pop('munc')
super(TentForm, self).__init__(*args, **kwargs)
self.fields['primary'].queryset = Mark.objects.filter(munc=munc)
class TentCreate(CreateView):
form_class = TentForm
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
kwargs = self.get_form_kwargs()
print(kwargs, self.kwargs)
kwargs.update(self.kwargs)
return form_class(**kwargs)
forms.py
class TentForm(ModelForm):
class Meta:
model = Tent
exclude =('asfo','niho')
def __init__(self, *args, **kwargs):
munc=self.kwargs['munc']
super(TentForm, self).__init__(*args, **kwargs)
self.fields['primary'].queryset = Mark.objects.filter(munc=munc)
you must pop munc before call super(TentForm, self).__init__(*args, **kwargs)

set variable into queryset of forms.py from my generic view or url

I want to set a dynamic variable into queryset of forms.py , I used __init__ to pass the dynamic variable , I think the code in forms.py is correct, the problem is how to pass the variable in views?
forms.py :
class ContainerForm(forms.ModelForm):
vehicle=forms.ModelChoiceField(required=False,queryset=Vehicle.objects.all(),widget=forms.Select(attrs={'class':'form-control'}))
def __init__(self, *args, **kwargs):
vehicle_id = kwargs.pop('vehicle_id',None)
super(ContainerForm, self).__init__(*args, **kwargs)
if vehicle_id:
self.fields['vehicle'].queryset = Vehicle.objects.filter(id=vehicle_id)
views.py
class ContainerCreate(CreateView):
form_class = ContainerForm(id= vehicle_id)
template_name = 'vehicule_app/container_form.html'
the error said :
Exception Value:'ContainerForm' object is not callable
If you want to use the vehicle_id from the URL, then you can exclude the field from the model form:
class ContainerForm(forms.ModelForm):
class Meta:
model = Container
exclude = ['vehicle']
You can then fetch the parameter from self.kwargs, and set the value on the form's instance in get_form_kwargs:
class ContainerCreate(CreateView):
form_class = ContainerForm
template_name = 'vehicule_app/container_form.html'
def get_form_kwargs(self):
kwargs = super(ContainerCreate, self).get_form_kwargs()
if kwargs['instance'] is None:
kwargs['instance'] = Container()
kwargs['instance'].vehicle_id = self.kwargs['pk'] # Fetch the vehicle_id from the URL
return kwargs
Note that the above code will not validate the id from the URL. The user could change it to any value they like.
If you want to keep the vehicle field in the form but with a single choice, then override the __init__ method and set the queryset.
class ContainerForm(forms.ModelForm):
class Meta:
model = Container
def __init__(self, *args, **kwargs):
vehicle_id = kwargs.pop('vehicle_id')
self.fields['vehicle'].queryset = Vehicle.objects.filter(id=vehicle_id)
Then in the get_form_kwargs method, add vehicle_id to kwargs instead:
class ContainerCreate(CreateView):
form_class = ContainerForm
template_name = 'vehicule_app/container_form.html'
def get_form_kwargs(self):
kwargs = super(ContainerCreate, self).get_form_kwargs()
kwargs['vehicle_id'] = self.kwargs['pk']
return kwargs

Django ModelForms __init__ kwargs create and update

I'm trying to get the request.user into a ModelForm. I feel like I've tried all permutations of this from overloading the
__init__
argument (per Django form, request.post and initial) to trying to pass it as a kwargs (per Django form __init__() got multiple values for keyword argument). I
It does seem like the kwargs is the best approach but I'm totally stymied by it.
Here's the ModelForm:
class DistListForm(ModelForm):
members = ModelMultipleChoiceField(queryset=Company.objects.none())
class Meta:
model = DistList
fields = ['name', 'description', 'members', 'is_private']
def __init__(self, *args, **kwargs):
super(DistListForm, self).__init__(*args, **kwargs)
user = kwargs.pop('user', None)
up = UserProfile.objects.get(user=user)
/.. etc ../
Here's how the create function currently works:
def distlistcreate(request):
user = {'user': request.user}
form = DistListForm(**user)
if request.method == 'POST':
form = DistListForm(request.POST)
if form.is_valid():
distlist = form.save(commit=False)
distlist.creator = request.user
distlist.save()
form.save_m2m()
return HttpResponseRedirect(reverse('distlistsmy'))
return render(request, 'distlistcreate.html',{'form':form})
which throws a TypeError: init() got an unexpected keyword argument 'user'. The update method is equally unhelpful:
def distlistupdate(request, object_id):
distlist = get_object_or_404(DistList, id=object_id)
form = DistListForm(user=request.user, instance=distlist)
if request.method == 'POST':
form = DistListForm(request.POST, user=request.user)
It also throws the same error.
I've been banging my head against this wall for two hours now. What is the correct way to pass a keyword argument into a ModelForm?
This is Django 1.6.1 if that makes a difference.
You have to pop the user argument before call super() so it will no conflict wit the default arguments of ModelForm
class DistListForm(ModelForm):
members = ModelMultipleChoiceField(queryset=Company.objects.none())
class Meta:
model = DistList
fields = ['name', 'description', 'members', 'is_private']
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(DistListForm, self).__init__(*args, **kwargs)
user_profile = UserProfile.objects.get(user=user)
Just did exactly this yesterday, on Django 1.5, and I am able to do:
def __init__(self, user, *args, **kwargs):
on my ModelForm. Then I just use user without having to pop it from the kwargs.