I'm having a strange problem where I can't seem to set the initial value of one of the fields in my forms in django.
My model field is:
section = models.CharField(max_length=255, choices=(('Application', 'Application'),('Properly Made', 'Properly Made'), ('Changes Application', 'Changes Application'), ('Changes Approval', 'Changes Approval'), ('Changes Withdrawal', 'Changes Withdrawal'), ('Changes Extension', 'Changes Extension')))
My form code is:
class FeeChargeForm(forms.ModelForm):
class Meta:
model = FeeCharge
# exclude = [] # uncomment this line and specify any field to exclude it from the form
def __init__(self, *args, **kwargs):
super(FeeChargeForm, self).__init__(*args, **kwargs)
self.fields['received_date'] = forms.DateField(('%d/%m/%Y',), widget=forms.DateTimeInput(format='%d/%m/%Y', attrs={'class': 'date'}))
self.fields['comments'].widget.attrs['class']='html'
self.fields['infrastructure_comments'].widget.attrs['class']='html'
My view code is:
form = FeeChargeForm(request.POST or None)
form.fields['section'].initial = section
Where section is a url var passed to the function. I've tried:
form.fields['section'].initial = [(section,section)]
With no luck either :(
Any ideas what I'm doing wrong or is there a better way to set the default value (before a form submit) of this choice field from a url var?
Thanks in advance!
Update: It seems to be something to do with the URL variable.. If I use:
form.fields['section'].initial = "Changes Approval"
It works np.. If I HttpResponse(section) it's outputs correctly tho.
The problem is use request.POST and initial={'section': section_instance.id}) together. This happens because the values of request.POST always override the values of parameter initial, so we have to put it separated. My solution was to use this way.
In views.py:
if request.method == "POST":
form=FeeChargeForm(request.POST)
else:
form=FeeChargeForm()
In forms.py:
class FeeChargeForm(ModelForm):
section_instance = ... #get instance desired from Model
name= ModelChoiceField(queryset=OtherModel.objects.all(), initial={'section': section_instance.id})
---------- or ----------
In views.py:
if request.method == "POST":
form=FeeChargeForm(request.POST)
else:
section_instance = ... #get instance desired from Model
form=FeeChargeForm(initial={'section': section_instance.id})
In forms.py:
class FeeChargeForm(ModelForm):
name= ModelChoiceField(queryset=OtherModel.objects.all())
UPDATE
Try escaping your url. The following SO answer and article should be helpful:
How to percent-encode URL parameters in Python?
http://www.saltycrane.com/blog/2008/10/how-escape-percent-encode-url-python/
Try setting the initial value for that field as follows and see if that works:
form = FeeChargeForm(initial={'section': section})
I assume you're going to be doing a lot of other things when the user posts the form, so you could separate the POST form from the standard form using something like:
if request.method == 'POST':
form = FeeChargeForm(request.POST)
form = FeeChargeForm(initial={'section': section})
Related
So, How can I update some Model Fields automatic, without the user having to input the values?
In Models:
class Url(models.Model):
long_url = models.CharField("Long Url",max_length=600)
short_url = models.CharField("Short Url",max_length=7)
visits = models.IntegerField("Site Visits",null=True)
creator = models.ForeignKey(CurtItUser,on_delete=models.CASCADE,null=True)
def __str__(self):
return self.short_url
In Views:
def home(request):
"""Main Page, Random Code Gen, Appendage Of New Data To The DB"""
global res,final_url
if request.method == 'POST':
form = UrlForm(request.POST)
if form.is_valid():
res = "".join(random.choices(string.ascii_uppercase,k=7))
final_url = f"127.0.0.1:8000/link/{res}"
form.save()
redirect(...)
else:
form = UrlForm
return render(...)
Sow how can for exapmle set from my view the value of short_url to final_url ???
You can get the data you need from the form.
you need to get the specific instance first, then you can use that instance to save values from the form.
And do not forget to save!
url_instance = get_object_or_404(Url, pk=pk)
url_instance.short_url = form.cleaned_data['short_url']
url_instance.long_url = form.cleaned_data['long_url']
url_instance.visits = form.cleaned_data['visits']
url_instance.save()
You can find more detailed infromations in the Django Documentation.
I have a website contact form that generates a dropdown box of "names" that are defined in another model "Data". The contact form runs off the model "Quote". As such, I use a ForeignKey reference to populate the "Data" information within the "Quote"-driven form.
However, the next step is to move this data to more python code (i.e., for calculations and placement in an email). But, when I request.POST "name" in the quote views file, I receive an ID (i.e., 1) instead of the actual string value for "name." I have read this is how ForeignKey inherently transfers data.
Like how I returned the actual string version of "name" in the quote dropdown box, how do I get the actual string version of "name" in a data request.POST / data_dictionary assignment? I have seen similar questions, but I am not completely sure of the simplest answer.
models.py (Original one)
class Data(models.Model):
name = models.CharField(max_length=100, null=True)
def __str__(self):
return self.name
models.py (The one tied to the form)
class Quote(models.Model):
name = models.ForeignKey(Data, on_delete=models.CASCADE)
def __str__(self):
return str(self.name)
views.py
def quote_req(request):
submitted = False
if request.method == 'POST':
form = QuoteForm(request.POST, request.FILES)
name = request.POST['name']
if form.is_valid():
data_dict = {
'name_': str(name),
inputdictionary = data_dict
forms.py
class QuoteForm(ModelForm):
helper = FormHelper()
helper.form_show_labels = False
required_css_class = 'required'
class Meta:
model = Quote
fields = ['name',]
Variable Assignment
▼ Local vars
Variable Value
name '1'
Respective Error (I need the actual string value of "name")
IndexError at /quote/
list index out of range
The solution was in tandem with what #dirkgroten mentioned in the comments. I have to add the form.cleaned_data method after the if form.is_valid statement. No other files need to be modified.
views.py
def quote_req(request):
submitted = False
if request.method == 'POST':
form = QuoteForm(request.POST, request.FILES)
name = request.POST['name']
if form.is_valid():
name = form.cleaned_data['name']
data_dict = {
'name_': str(name),
inputdictionary = data_dict
In django, how can I make a selectible formField to access the db for every time it is being calld?
Right now the line :
status = forms.ChoiceField(choices=FormsTools.StatusesToTuples(Status.objects.all()))
is executed once django is loaded and not every time the form is being showed.
How can I make the field dynamic ? so every time the form is being showed the selectible field will have values from db?
UPDATE:
POST data:
.
status: u'4'
.
.
in the Model, the field looks like this: status = models.IntegerField()
The View:
def edit_call(request, call_id):
c = Call.objects.get(id=call_id)
if request.POST:
form = CallForm(request.POST, instance=c)
print form.errors
if form.is_valid():
form.save()
return HttpResponseRedirect('/ViewCalls/')
else:
form = CallForm(instance=c)
args = {}
args.update(csrf(request))
args["form"] = form
args["id"] = call_id
t = get_template('edit_call.html')
cont = RequestContext(request, args)
html = t.render(cont)
return HttpResponse(html)
The form:
simple as:
class CallForm (forms.ModelForm):
employee_id = forms.ModelChoiceField(queryset=Employee.objects.all())
status = forms.ModelChoiceField(queryset=Status.objects.all())
class Meta():
model = Call
You need to call the contructor each time you load the form to update the choices. So the form should be:
class CallForm(forms.ModelForm):
...
status = forms.ChoiceField()
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=None,
empty_permitted=False):
super(CallForm, self).__init__(data, files, auto_id, prefix, initial, error_class,
label_suffix, empty_permitted)
self.fields['status'].choices = FormsTools.StatusesToTuples(Status.objects.all())
Have you looked at forms.ModelChoiceField?
UPDATED ANSWER FOLLOWING UPDATED QUESTION:
You now need to get your models and your forms to match:
Your model has an IntegerField, your form has a ModelChoiceField. The latter returns a pk string, not an integer ID.
Given that you're using a modelform, why not just let it do the work of creating the fields for you?
class CallForm(forms.ModelForm):
class Meta:
model = Call
fields = ('employee', 'status') # assuming these are what the field names are
I have a form with wtform, I want to add a new form JobItemForm to my form JobForm using append_entry. JobItemForm has selectField named company. I add choice field data via model like this
form.jobs[0].company.choices = company_list
now I use append_entry without any choices and I recieve an error. So how can I call append_entry with some initial data?
class JobItemForm(Form):
company = SelectField(_('company'), description=_('new company"'))
title = TextField(_('title'), [validators.Length(min=4, max=250)])
date_from = DateField(_("date_from"), format='%Y-%m-%d')
date_to = DateField(_("date_to"), format='%Y-%m-%d')
description = TextAreaField(_('description'))
class JobForm(Form):
jobs = FieldList(FormField(JobItemForm), min_entries=3)
add_job = SubmitField(_('Add job'))
some thing like this
#mod.route('/edit/', methods=['GET', 'POST'])
#login_required
def edit_job():
"""
edit job
"""
company_list = Company.Company_list()
form_title = "Edit job Form"
if request.method != 'POST':
form = JobForm()
form.jobs[0].company.choices = company_list
return render('form.html', form=form, form_title=form_title)
form = JobForm(request.form)
if form.add_job.data:
new_item_job = form.jobs.append_entry()
new_item_job.company.choices = company_list
return render('form.html', form=form, form_title=form_title)
form.validate
if form.errors != dict():
return render('form.html', form=form, form_title=form_title)
# save data
flash(_("Edit successfully!"))
return render('registration/succesful.html')
There is a better way to do this:
form.jobs[0].company.choices = company_list
Wtforms has extensions for GAE,Django and SQLAlchemy which supports orm backed form fields. Documentation of extensions.
For sqlalchemy, it works like this:
from wtforms.ext.sqlalchemy.fields import QuerySelectField
def fill_field():
return Model.query
myfield = QuerySelectField(query_factory=fill_field)
This snippet of code automatically fills the choices for you from the database model.
(I do not have you actual error so I am just guessing here)
The reason you are getting no choices error after add_job because you are filling choices only when it is a GET request. You need to add choices after a Post request too like this:
def your_view():
form = YourForm()
form.fieldname.choices = choice_list
# Here comes your code for GET and POST request both
I have a Model as follows:
class TankJournal(models.Model):
user = models.ForeignKey(User)
tank = models.ForeignKey(TankProfile)
ts = models.IntegerField(max_length=15)
title = models.CharField(max_length=50)
body = models.TextField()
I also have a model form for the above model as follows:
class JournalForm(ModelForm):
tank = forms.IntegerField(widget=forms.HiddenInput())
class Meta:
model = TankJournal
exclude = ('user','ts')
I want to know how to set the default value for that tank hidden field. Here is my function to show/save the form so far:
def addJournal(request, id=0):
if not request.user.is_authenticated():
return HttpResponseRedirect('/')
# checking if they own the tank
from django.contrib.auth.models import User
user = User.objects.get(pk=request.session['id'])
if request.method == 'POST':
form = JournalForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
# setting the user and ts
from time import time
obj.ts = int(time())
obj.user = user
obj.tank = TankProfile.objects.get(pk=form.cleaned_data['tank_id'])
# saving the test
obj.save()
else:
form = JournalForm()
try:
tank = TankProfile.objects.get(user=user, id=id)
except TankProfile.DoesNotExist:
return HttpResponseRedirect('/error/')
You can use Form.initial, which is explained here.
You have two options either populate the value when calling form constructor:
form = JournalForm(initial={'tank': 123})
or set the value in the form definition:
tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123)
Other solution: Set initial after creating the form:
form.fields['tank'].initial = 123
If you are creating modelform from POST values initial can be assigned this way:
form = SomeModelForm(request.POST, initial={"option": "10"})
https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#providing-initial-values
I had this other solution (I'm posting it in case someone else as me is using the following method from the model):
class onlyUserIsActiveField(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(onlyUserIsActiveField, self).__init__(*args, **kwargs)
self.fields['is_active'].initial = False
class Meta:
model = User
fields = ['is_active']
labels = {'is_active': 'Is Active'}
widgets = {
'is_active': forms.CheckboxInput( attrs={
'class': 'form-control bootstrap-switch',
'data-size': 'mini',
'data-on-color': 'success',
'data-on-text': 'Active',
'data-off-color': 'danger',
'data-off-text': 'Inactive',
'name': 'is_active',
})
}
The initial is definded on the __init__ function as self.fields['is_active'].initial = False
As explained in Django docs, initial is not default.
The initial value of a field is intended to be displayed in an HTML . But if the user delete this value, and finally send back a blank value for this field, the initial value is lost. So you do not obtain what is expected by a default behaviour.
The default behaviour is : the value that validation process will take if data argument do not contain any value for the field.
To implement that, a straightforward way is to combine initial and clean_<field>():
class JournalForm(ModelForm):
tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123)
(...)
def clean_tank(self):
if not self['tank'].html_name in self.data:
return self.fields['tank'].initial
return self.cleaned_data['tank']
If you want to add initial value and post other value you have to add the following :
or None after request.POST
form = JournalForm(request.POST or None,initial={'tank': 123})
If you want to add files or images also
form = JournalForm(request.POST or None,request.FILES or None,initial={'tank': 123})
I hope this can help you:
form.instance.updatedby = form.cleaned_data['updatedby'] = request.user.id
I also encountered the need to set default values in the form during development. My solution is
initial={"":""}
form=ArticleModel(request.POST)
if form.has_changed():
data = {i: form.cleaned_data[i] for i in form.changed_data}
data.update({key: val for key, val in init_praram.items() if key not in form.changed_data})
use form.has_changed ,if form.fields is required you can use this method
How I added the initial to the form:
I read #Sergey Golovchenko answer.
So I just added it to the form in if request.method == 'POST':.
But that's not where you place it, if you want to see what value it got before posting the form.
You need to put it in the form where the else is.
Example here from views.py
def myForm(request):
kontext = {}
if request.method == 'POST':
# You might want to use clean_data instead of initial here. I found something on a stack overflow question, and you add clean data to the Forms.py, if you want to change the post data. https://stackoverflow.com/questions/36711229/django-forms-clean-data
form = myModelForm(request.POST, initial={'user': request.user})
if form.is_valid():
form.save()
return redirect('/')
else:
# you need to put initial here, if you want to see the value before you post it
form = myModelForm(initial={'user': request.user})
kontext['form'] = form
return render(request, 'app1/my_form.html', kontext)