DeclarativeFieldsMetaclass object argument after ** must be a mapping, not int - python

I am trying to pass kwargs to my forms.py file, when the form is loaded I get an error saying my car_id is not defined on my forms.py file. I know this is because of the below line of code but I do not know how to fix it.
form = SelectCarModelForm()
forms.py
def __init__(self, *args, **kwargs):
self.car_id = kwargs.pop('car_id', None)
super(SelectCarModelForm, self).__init__(*args, **kwargs)
self.fields['car_model'] = forms.ModelChoiceField(
empty_label = "Select a Model",
queryset = CarModel.objects.filter(model=car_id),
widget = Select(attrs={'class': 'span12 small-margin-top small-margin-bottom'}),
required=True
)
view
if request.method == "POST":
form = SelectCarModelForm(request.POST)
if form.is_valid():
model = form.cleaned_data['car_model']
# Go to the next form in the process.
return redirect('view_car')
# Initial form
else:
form = SelectCarModelForm()
return render(
request,
template_name = 'cars/forms/view_car_models.html',
dictionary = {
'form':form,
}
)

You either do this:
# pass a `car_id` value when instantiating the form
form = SelectCarModelForm(car_id=<some_value>)
and if that's not feasible, maybe this:
def __init__(self, *args, **kwargs):
self.car_id = kwargs.pop('car_id', None)
super(SelectCarModelForm, self).__init__(*args, **kwargs)
if self.car_id is not None:
self.fields['car_model'] = forms.ModelChoiceField(
empty_label = "Select a Model",
queryset = CarModel.objects.filter(model=car_id),
widget = Select(attrs={'class': 'span12 small-margin-top small-margin-bottom'}),
required=True
)
else:
self.fields['car_model'] = forms.ModelChoiceField(
empty_label = "Select a Model",
queryset = CarModel.objects.filter(model=<SOME-OTHER-CRITERIA),
widget = Select(attrs={'class': 'span12 small-margin-top small-margin-bottom'}),
required=True
)

Related

__init__() got multiple values for argument 'crescator'

I have a ModelForm and in a ModelChoiceField I need to filter objects by request.user. When data is submitted, I got the error "init() got multiple values for argument 'crescator' ". How can I repair that?
#My Form
class AdaugaPereche(forms.ModelForm):
boxa = forms.IntegerField(label="Boxa", min_value=1)
sezon = forms.CharField(label="Sezon reproducere", initial=datetime.now().year)
mascul = forms.ModelChoiceField(queryset=None, label="Mascul", empty_label="Alege mascul")
femela = forms.ModelChoiceField(queryset=None, label="Femela", empty_label="Alege femela")
serie_pui_1 = forms.TextInput()
serie_pui_2 = forms.TextInput()
culoare_pui_1 = forms.ModelChoiceField(queryset=None, label="Culoare pui 1", empty_label="Alege culoarea",
required=False)
culoare_pui_2 = forms.ModelChoiceField(queryset=None, label="Culoare pui 2", empty_label="Alege culoarea",
required=False)
data_imperechere = forms.DateInput()
primul_ou = forms.DateInput()
data_ecloziune = forms.DateInput()
data_inelare = forms.DateInput()
comentarii = forms.TextInput()
# Functie pentru filtrarea rezultatelor dupa crescator
def __init__(self, crescator, *args, **kwargs):
super(AdaugaPereche, self).__init__(*args, **kwargs)
self.fields['mascul'].queryset = Porumbei.objects.filter(crescator=crescator, sex="Mascul",
perechi_masculi__isnull=True)
self.fields['femela'].queryset = Porumbei.objects.filter(crescator=crescator, sex="Femelă",
perechi_femele__isnull=True)
self.fields['culoare_pui_1'].queryset = CuloriPorumbei.objects.filter(crescator=crescator)
self.fields['culoare_pui_2'].queryset = CuloriPorumbei.objects.filter(crescator=crescator)
class Meta:
model = Perechi
fields = "__all__"
#My view
def perechenoua(request):
if request.method == "POST":
form = AdaugaPereche(request.POST, crescator=request.user)
if form.is_valid():
obj = form.save(commit=False)
obj.crescator = request.user
obj.save()
return HttpResponseRedirect("/perechi/")
else:
form = AdaugaPereche(crescator=request.user)
context = {
'form': form
}
template = loader.get_template("adauga-pereche.html")
return HttpResponse(template.render(context, request))
May the problem be obj = form.save(commit=False) obj.crescator = request.user obj.save() ?
The __init__ function of the form signature takes as first parameter here crescator, but you pass request.POST as that parameter, and furthermore you also pass this as a named parameter. By reordening the parameter, this should work:
class AdaugaPereche(forms.ModelForm):
# ...
def __init__(self, *args, crescator=None, **kwargs):
super(AdaugaPereche, self).__init__(*args, **kwargs)
self.fields['mascul'].queryset = Porumbei.objects.filter(crescator=crescator, sex="Mascul",
perechi_masculi__isnull=True)
self.fields['femela'].queryset = Porumbei.objects.filter(crescator=crescator, sex="Femelă",
perechi_femele__isnull=True)
self.fields['culoare_pui_1'].queryset = CuloriPorumbei.objects.filter(crescator=crescator)
self.fields['culoare_pui_2'].queryset = CuloriPorumbei.objects.filter(crescator=crescator)
# ...

Validate django form with a list of values from multiple CheckboxSelectMultiple

Using Django2.0, I have set up a form which displays all of my model objects in a list with check boxes. When this is submitted, in my request dict it stores them as a list of IDs. How do i validate these within the form? The clean() method does not get called.
forms:
class SampleRunSearchForm(forms.ModelForm):
sample_run_id = forms.ModelChoiceField(
label='Sample Run',
queryset=SampleRun.objects.all(),
widget=forms.CheckboxSelectMultiple,
)
class Meta:
model = SampleRun
fields = ('sample_run_id',)
def __init__(self, *args, **kwargs):
super(SampleRunSearchForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Field('sample_run_id', css_class='sample-run-display',),
HTML('<br>'),
Submit('submit', 'Report samples', css_class='upload-btn')
)
self.helper.form_method = 'GET'
def clean_sample_run_id(self):
sr_id = self.cleaned_data.getlist('sample_run_id')
for sr in sr_id:
... do something to validate...
else:
raise(forms.ValidationError('Error'))
return(sr_id)
views:
class SearchSampleRun(View):
samplerunform = SampleRunSearchForm
template_name = 'results/samplerun_search_form.html'
def get(self, request, *args, **kwargs):
samplerunform = self.samplerunform()
if request.GET:
samplerunform = self.samplerunform(request.GET)
samplerunform.is_valid()
context = {'samplerunform': samplerunform}
return render(request, self.template_name, context)
It returns an error to my page that is it not a valid choice.
the clean() method will also execute, but clean_sample_run_id() doesn't work - do i need to iterate through each ID and pass it through the form seperately for validation?!

Filter Django ModelForm without validating it

I have a form which I would like to filter based on information passed by another form, but without validating it just yet:
forms.py:
class SampleRunSearchForm(forms.ModelForm):
class Meta:
model = SampleRun
fields = ('id',)
def __init__(self, sr_obj, *args, **kwargs):
super(SampleRunSearchForm, self).__init__(*args, **kwargs)
self.fields['id'] = forms.ChoiceField(required=True,
label='Sample:',
widget=forms.CheckboxSelectMultiple,
choices=((s.id, s) for s in sr_obj)
)
self.helper = FormHelper()
self.helper.layout = Layout(
Field('id', css_class='sample-run-display',),
Submit('submit', 'Report samples', css_class='upload-btn')
)
self.helper.form_method = 'POST'
views.py:
class SearchSampleRun(View):
samplerunform = SampleRunSearchForm
template_name = 'results/samplerun_search_form.html'
def get(self, request, *args, **kwargs):
self.run_obj = get_object_or_404(Run, id=kwargs['run_id'])
self.choice = kwargs['choice']
self.sample_run_obj = self.obtainCorrectSamples()
samplerunform = self.samplerunform(sr_obj=self.sample_run_obj)
context = {'samplerunform': samplerunform}
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
samplerunform = self.samplerunform(request.POST)
if samplerunform.is_valid():
HttpResponseRedirect(...somewhere to display information)
context = {}
return render(request, self.template_name, context)
The initial form (not shown) takes a charfield and redirects to my SearchSampleRun view with **kwargs. I want to filter my SampleRunSearchForm based on these kwargs and display a list of check boxes - filtered model object from the SampleRun model. This works, but when i click these buttons, and submit the form, it initialised again, and sr_obj is None, so the form field produces an error.
I have tried using:
sr_obj = kwargs.pop('sr_obj', None)
In my init() method, but these must be a way to dynamically filter a form queryset in order to display a subset of values, before validating, with a view to validating when this form is submitted?
Just add validation to the __init__ method and override id fields only if sr_objis not empty:
def __init__(self, sr_obj, *args, **kwargs):
super(SampleRunSearchForm, self).__init__(*args, **kwargs)
if sr_obj:
self.fields['id'] = forms.ChoiceField(required=True,
label='Sample:',
widget=forms.CheckboxSelectMultiple,
choices=((s.id, s) for s in sr_obj)
)
self.helper = FormHelper()
self.helper.layout = Layout(
Field('id', css_class='sample-run-display',),
Submit('submit', 'Report samples', css_class='upload-btn')
)
self.helper.form_method = 'POST'

Required field django WizardView ModelForm

I have two step of my WizardView process based ModelForm. I don't understand why, when I valide the second step django says me that a previous field are required. I try to send data between step like that:
forms.py
class RequestForm1(forms.ModelForm):
class Meta:
model = Product
fields = ('title', 'product_class', )
class RequestForm2(forms.ModelForm):
class Meta:
model = Product
fields = ( 'dimension_x', )
views.py
class RequestView(SessionWizardView):
instance = None
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
def get_form_initial(self, step):
current_step = self.storage.current_step
if current_step == 'step2':
prev_data = self.storage.get_step_data('step1')
print(prev_data)
title = prev_data.get('step1-title', '')
product_class = prev_data.get('step1-product_class', '')
return self.initial_dict.get(step, {
'title': title,
'product_class': product_class
})
return self.initial_dict.get(step, {})
def done( self, form_list, **kwargs ):
self.instance.save()
return HttpResponseRedirect('/catalogue/request/')
Please find below my solution
forms.py
class RequestForm1(forms.ModelForm):
class Meta:
model = Product
fields = ('title', 'product_class', )
class RequestForm2(forms.ModelForm):
class Meta:
model = Product
fields = ( 'title', 'product_class', 'dimension_x', )
widgets = {
'title': forms.HiddenInput(),
'product_class': forms.HiddenInput()
}
views.py
class RequestView(SessionWizardView):
instance = None
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
def get_form_instance( self, step ):
if self.instance is None:
self.instance = Product()
return self.instance
def get_form(self, step=None, data=None, files=None):
form = super(RequestView, self).get_form(step, data, files)
if step == 'step2':
prev_data = self.storage.get_step_data('step1')
title = prev_data.get('step1-title', '')
product_class = prev_data.get('step1-product_class', '')
form.fields['title'].initial = title
form.fields['product_class'].initial = product_class
return form
def done(self, form_list, **kwargs):
self.instance.save()
return HttpResponseRedirect('/catalogue/request/success')

Django, change username form

I'm trying to create a modelform to allow users to change their username. I'm trying to do this using FormView instead of UpdateView because I want to include other forms (user management functionality) in this view eventually.
Relevant forms.py:
class FormHorizontalModelForm(forms.ModelForm)
def __init__(self, *args, **kwargs):
super(FormHorizontalModelForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
class PlayerRenameForm(FormHorizontalModelForm):
def __init__(self, user, *args, **kwargs):
super(PlayerRenameForm, self).__init__(*args, **kwargs)
self.helper.add_input(Submit('change_username', 'Change Username'))
class Meta:
model = User
fields = ('username',)
def save(self):
pass # I figured this might be saving the object since this is inherited off ModelForm
def form_valid(self, form):
self.change_username(new_username = self.cleaned_data['username'])
# self.send_email(new_username = self.cleaned_data['username'])
def change_username(self, new_username):
player = Player.objects.get(user = self.instance)
self.instance.username = new_username
self.instance.save()
player.changed_username = True
player.save()
views.py
class AccountView(UserAuthenticationMixin, FormView):
template_name = 'game/profile.html'
success_url = '/accounts/'
form_class = PlayerRenameForm
form_class_two = CrispyPasswordSetForm
form_class_three = CrispyPasswordChangeForm
def get_context_data(self, **kwargs):
context = super(AccountView, self).get_context_data(**kwargs)
if 'form' not in context:
context['form'] = self.form_class(user = self.request.user, data = (self.request.POST or None))
if 'password_set_form' not in context:
context['password_set_form'] = self.form_class_two(user = self.request.user, data = (self.request.POST or None))
if 'password_change_form' not in context:
context['password_change_form'] = self.form_class_three(user = self.request.user, data = (self.request.POST or None))
return context
def form_invalid(self, **kwargs):
return self.render_to_response(self.get_context_data(**kwargs))
def get_form(self, form_class):
return form_class(user = self.request.user, **self.get_form_kwargs())
def post(self, request, *args, **kwargs):
if 'change_username' in request.POST:
form = self.form_class(user = request.user, instance = request.user, data = self.request.POST)
form_name = 'form'
elif 'set_password' in request.POST:
form = self.form_class_two(user = request.user, data = self.request.POST)
form_name = 'password_set_form'
elif 'change_password' in request.POST:
form = self.form_class_three(user = request.user, data = self.request.POST)
form_name = 'password_change_form'
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(**{form_name: form})
The form returns valid, and returns to success_url. I know for a fact that it is passing into the correct part of the post function since I have stripped away the other parts to ensure that was working.

Categories