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

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.

Related

Unexpected Keyword argument using formset_factory

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

ModelForm object has no attribute 'fields'

I am using a django (3.0) ModelMultipleChoice field for a form. I am trying to modify the queryset to make some restrictions on it.
here is the views :
def nouvelle_tache(request,id_livrable):
livrable=Livrable.objects.get(pk=id_livrable)
projet = livrable.projet
if request.method == "POST":
form = NouvelleTache(request.POST,projet=projet)
tache = form.save(commit=False)
tache.livrable = livrable
tache.id_tache = livrable.id_derniere_tache() + Decimal(0.01)
tache.save()
form.save_m2m()
etat = Temps_etat_tache(etat=form.cleaned_data['etat_initial'],tache=tache)
etat.save()
return redirect('tache',tache.pk)
else:
form = NouvelleTache(projet=projet)
return render(request, 'application_gestion_projets_AMVALOR/nouvelle_tache.html', locals())
And the forms :
class NouvelleTache(forms.ModelForm):
def __init__(self, *args, **kwargs):
projet = kwargs.pop('projet', None)
queryset = Utilisateur.objects.all()
for utilisateur in projet.utilisateurs:
queryset = queryset.exclude(pk=utilisateur.pk)
self.fields['ressources'].queryset = queryset
super(NouvelleTache, self).__init__(*args, **kwargs)
ressources= forms.ModelMultipleChoiceField(queryset=Utilisateur.objects.all() ,widget =forms.CheckboxSelectMultiple )
etat_initial = forms.ModelChoiceField(queryset=Etat_tache.objects.none())
class Meta:
model = Tache
fields = ['libelle']
I have the followig error : 'NouvelleTache' object has no attribute 'fields'
I don't understand why because many other users seems to have similar code and it works.
Any help would be appreciate.
super(NouvelleTache, self).__init__(*args, **kwargs)
needs to be executed first, as the fields are set in the super class:
def __init__(self, *args, **kwargs):
projet = kwargs.pop('projet', None)
queryset = Utilisateur.objects.all()
for utilisateur in projet.utilisateurs:
queryset = queryset.exclude(pk=utilisateur.pk)
super(NouvelleTache, self).__init__(*args, **kwargs)
self.fields['ressources'].queryset = queryset

how to get url parameter in modelform

I have one model name is cityform
i want to get url parmeter in this CityFrom hwo can i do this?
here is my url
path('state/city/<int:id>/', City.as_view(), name="city")
http://localhost:8000/country/state/city/3/
here is my form
class
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CityFrom,self).__init__(*args, **kwargs)
print(args)
print(kwargs)
self.fields['state'] = forms.ModelChoiceField(
empty_label = 'Select',
queryset = State.objects.all()
)
class Meta:
model = City
fields = ('state', 'name')
in this form i want to access id = 3
here is my view
from django.views import View
class City(View):
def get(self, request, *args, **kwargs):
Forms = CityFrom()
return render(request, 'albums/add.html', {'Forms': Forms})
Pass url parameter as keyword argument from views.py as following.
form = CityFrom(id=kwargs.get("id"))
To get the id in your forms.py, use following code in your form's __init__ method.
self.id = kwargs.get('id')
Your form should look like this.
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.id = kwargs.get('id')
super(CityFrom,self).__init__(*args, **kwargs)
self.fields['state'] = forms.ModelChoiceField(
empty_label = 'Select',
queryset = State.objects.all()
)
class Meta:
model = City
fields = ('state', 'name')
* Call super after getting the id in your form as above. Here order of calling super is important.
Try
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.id = kwargs.pop('id')
super(CityFrom,self).__init__(*args, **kwargs)

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
...

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