Django request.POST not passed to form.data - django

I have a form, but request.POST is not passing data to my form. i.e. form.data is empty
my form
class DPStatusForm(forms.Form):
status = forms.ChoiceField(label="")
def __init__(self, excluded_choice=None, *args, **kwargs):
super().__init__(*args, **kwargs)
if excluded_choice:
status_choices = (
(s.value, s.label)
for s in DP.Status
if s.value != excluded_choice
)
else:
status_choices = ((s.value, s.label) for s in DP.Status)
self.fields["status"].choices = status_choices
view to receive form data
def update_status(request, id):
if request.method == "GET":
return redirect("my_app:show_dp", id)
p = get_object_or_404(DP, pk=id)
form = DPStatusForm(request.POST)
# debug statements
print(request.POST)
print(form.data)
# ...
With the 2 print statements, I can see that request.POST is present with status key populated, but form.data is empty:
# request.POST
<QueryDict: {'csrfmiddlewaretoken': ['xxx...], 'status': ['1']}>
# form.data
<MultiValueDict: {}>
Why is form.data not getting populated?

Check the value of excluded_choice. You're defining an extra positional argument to the form __init__ method which is intercepting the data you are trying to pass to the form.
The simplest solution I see would be to modify the form __init__ method slightly.
def __init__(self, *args, excluded_choice=None, **kwargs):
or pass the data as a key-word argument.
form = DPStatusForm(data=request.POST)
I think the first is preferable as it preserves the expected behavior of the form class.

Related

Send additional data to form initialisation

So I'm creating a form object using request.POST data, but want to initialise additional fields using other values.
This is what i tried, it isn't working:
#forms.py
class InputForm3(forms.Form):
url = forms.URLField(required=True)
db = forms.CharField(required=False)
wks = forms.CharField(required=True, initial="Sheet1")
table = forms.CharField(required=False, initial="test_table")
def __init__(self, wks, *args, **kwargs):
self.wks=wks
super().__init__(*args, **kwargs)
self.cleaned_data = None
def clean(self):
self.cleaned_data = super().clean()
print("FORM3 cleaned_data : ", self.cleaned_data)
#views.py
form3=InputForm3(wks="Sheet1", data= request.POST)
if form3.is_valid:
#remaining code
#output
FORM3 cleaned_data : {'url': 'https://randomurl.com', 'db': 'testdb', 'table': ''}
the fields 'url' and 'db' are present directly in request.POST, HOW DO I INITIALISE THE OTHER FIELDS PLEASE HELP!
Not sure of the context of why you'd want to do that.
But maybe you can try copying the form's data after you initialized the form with the request.POST data. You'll have access to modify the copied data. For example:
If you're using a function-based view:
def view_name(request):
form3 = InputForm3(request.POST)
if request.method == "POST":
form3 = InputForm3(data=request.POST) # removing wks from the parameter here...
# assigning the copied collection of data to the form's data so we can modify it
form3.data = form3.data.copy()
form3.data['wks'] = 'Sheet1' # or whatever name you wish to name that wk
if form3.is_valid():
# remaining code
...
If you're using a class-based view:
def post(self, request, *args, **kwargs):
form3 = InputForm3(data=request.POST)
form3.data = form3.data.copy()
form3.data['wks'] = 'Sheet1'
if form3.is_valid():
# remaining code
...
That worked for me.

Django Form Wizard Dynamic Form Not Saving Data

Currently Happening:
Dynamically generated form and form fields are being displayed.
Enter some data into the said fields, but self.get_all_cleaned_data() returns nothing.
Form returns to page 0 instead of submitting the form and using done()
What I want to happen:
- Data in fields to be retained and displayed when going back, or to the confirmation page
- Form to actually submit and use done() to process and save
The following the my forms.py
class OrderForm(forms.Form):
class Meta:
localized_fields = ('__all__',)
def __init__(self, *args, **kwargs):
self.fields = kwargs.pop('fields')
fields = self.fields
super(OrderForm, self).__init__(*args, **kwargs)
if not isinstance(fields, str):
for i in fields.fields.all():
widget = forms.TextInput()
_type = forms.CharField
if i.field_type == Field.TEXTAREA_FIELD:
widget = forms.Textarea
...
self.fields[i.name] = _type(**fields)
This is supposed to get Database created forms and field data and generate fields accordingly. For example:
Form A has fields:
Name (Regular Text Field)
Address (Textarea)
The above code will then generate fields for those.
The next block of code is from my views.py file
FORM_TEMPLATES = {
"0": 'order/details.html',
"1": 'order/details.html',
"2": 'order/details.html',
"3": 'order/details.html',
"4": 'order/details.html',
"confirm": 'order/confirm.html',
}
class Order(SessionWizardView):
form_list = [OrderForm]
def get_current_step_form(self, company, *args, **kwargs):
step_form = [Form.objects.all()]
step_form.append('Confirm')
return step_form
def get_context_data(self, form, **kwargs):
context = super(Order, self).get_context_data(form=form, **kwargs)
# Returns {}, but I want this to return all previous field values
context.update({
'all_data': self.get_all_cleaned_data(),
})
return context
def post(self, *args, **kwargs):
go_to_step = self.request.POST.get('wizard_goto_step', None)
form = self.get_form(data=self.request.POST)
current_index = self.get_step_index(self.steps.current)
goto_index = self.get_step_index(go_to_step)
if current_index > goto_index:
self.storage.set_step_data(self.steps.current,
self.process_step(form))
self.storage.set_step_files(self.steps.current,
self.process_step_files(form))
return super(Order, self).post(*args, **kwargs)
def get_form(self, step=None, data=None, files=None):
"""
Get the form and add to form_list
"""
form = super(Order, self).get_form(step, data, files)
company = ...
get_forms = self.get_current_step_form(company=company)
form_list_value = dict(self.form_list)['0']
while len(self.form_list.items()) < len(get_forms):
self.form_list.update({str(len(self.form_list.items())): form_list_value})
return form
def done(self, form_list, **kwargs):
return HttpResponse("View")
done() is a work in progress, but it doesn't even seem to reach that point, as it keeps going from (for example) Form 0-1-2-3-0-...
The confirm form will not have any field values form the previous pages and will only return {}
Any help would be appreciated,
Thanks

Pass logged user to model field django

I don't know how to get the username from the current user.
I have a edit form rendered with djano-crispy-forms:
class RecepcionForm(forms.ModelForm):
fecha_recepcion = forms.DateField(widget=DateInput())
def __init__(self,*args,**kwargs):
super(RecepcionForm,self).__init__(*args,**kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Field('id_proveedor',
'anio',
'mes',
'usuario',
readonly = True
),
Fieldset('',
'fecha_recepcion',
'num_archivos',
Submit('save','Grabar')
)
)
class Meta:
model = DetalleRecepcion
my views.py:
#login_required(login_url='/login/')
def RecepcionView(request):
idp = request.GET.get('i')
anio = request.GET.get('a')
mes = request.GET.get('m')
if request.method == 'POST':
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
form = RecepcionForm(request.POST, instance=r)
if form.is_valid():
form.save()
return HttpResponseRedirect('/monitor/')
else:
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
form = RecepcionForm(instance=r)
return render_to_response('recepcion.html',
{'form':form},
context_instance=RequestContext(request))
I need to fill the field usuario with the logged username.
I tried with form = request.user.username before the save of the form.
I am confused of this have to be done passed the value in the form definition or in the view.
If is possible to overwrite the retrieved value from the database and fill the field with the username in the form class.
Another question
How can I change the widget type in the form. The field id_proveedor is a foreign key and is rendered as a drop down box (select widget), but I need to show the value displayed in a label where the can't edit the value.
I tried with the readonly propertie, but the user is not capable to write in the select box, but is capable to select from the drop down.
How can change the widget or how can I disabled the drop dwon function from the select box
Thanks in advance
You can always pass whatever arguments or keyword arguments you need to a form class, you just have to remove them from the *args or **kwargs that are passed on when calling super(), otherwise Django will throw an exception because it's receiving an arg or kwarg it's not expecting:
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user') # notice the .pop()
super(MyForm, self).__init__(*args, **kwargs)
# views.py
def my_view(request):
# assuming the user is logged in
form = MyForm(user=request.user)
I came across the same as your problem and found a solution just now. I do not know whether this is the best solution or maybe I will have problem later.
def add_trip_event(request):
#form = Trip_EventForm()
#return render(request, 'trips/add_trip_event.html', {'form': form})
if request.method == "POST":
form = Trip_EventForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.trip_owner = Owner.objects.get(owner=request.user)
post.pub_date = timezone.now()
post.view = 0
post.save()
form.save_m2m()
return HttpResponseRedirect(reverse('trips:index'))
else:
form = Trip_EventForm()
return render(request, 'trips/add_trip_event.html', {'form': form})

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.

Form error int() argument must be a string or a number, not 'QueryDict'

Can someone help me out with the following error below and explain the issue? All I'm trying to do it populate a group with a query set, but upon submitting the form I get the following error...
*TypeError at /sms/addbatch
int() argument must be a string or a number, not 'QueryDict'*
views.py
def add_batch(request):
# If we had a POST then get the request post values.
if request.method == 'POST':
form = BatchForm(request.POST)
# Check we have valid data before saving trying to save.
if form.is_valid():
# Clean all data and add to var data.
data = form.cleaned_data
groups = data['group'].split(",")
for item in groups:
batch = Batch(content=data['message'],
group=Group.objects.get(pk=item),
user=request.user
)
form.py
class BatchForm(forms.ModelForm):
class Meta:
model = Batch
def __init__(self, user=None, *args, **kwargs):
super(BatchForm, self).__init__(*args,**kwargs)
if user is not None:
form_choices = Batch.objects.for_user_pending(user)
else:
form_choices = Batch.objects.all()
self.fields['group'] = forms.ModelMultipleChoiceField(
queryset=form_choices
)
models.py
class BatchManager(models.Manager):
def for_user_pending(self, user):
return self.get_query_set().filter(user=user, status="Pending")
You are passing request.POST as the user parameter to your form. Do this:
form = BatchForm(data=request.POST)
# first parameter ---v
def __init__(self, user=None, ...
# first parameter ---v
form = BatchForm(request.POST)