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
Related
I am trying to create a dynamic choice field. I have a view that creates a list of tuples. The first value of the tuple is the primary key of the object ServiceWriter while the second value is the name of the ServiceWriter. The list then gets passed into the form class. When I make the selection and submit the page the form is decided to be not valid and the following form error is printed in the shell: "Select a valid choice. (First value of tuple. ie 1,2,3..) is not one of the available choices."
forms.py
class CreateAdvancedRO(forms.Form):
service_writer = forms.ChoiceField()
def __init__(self, writer_choices, *args, **kwargs):
super(CreateAdvancedRO, self).__init__(*args, **kwargs)
self.fields['service_writer'].choices = writer_choices
self.helper = FormHelper()
self.helper.form_id = 'id-create-advanced-ro'
self.helper.form_method = 'post'
self.helper.add_input(Submit('submit', 'Open Repair Order'))
Note: I am not using a ModelForm.
views.py
class CreateAdvancedRO(View):
form_class = CreateAdvancedRO
writer_form = CreateServiceWriter
add_line_form = AddJobLine
def post(self, request):
writer_choices = []
form = self.form_class(writer_choices, request.POST)
print(form.errors)
if form.is_valid():
'''Do something'''
else:
writer_choices = []
try:
writers = ServiceWriter.objects.filter(user=request.user)
for writer in writers:
writer_choices.append((str(writer.id), writer.name))
except ObjectDoesNotExist:
pass
form = self.form_class(writer_choices, request.POST)
writer_form = self.writer_form()
add_line_form = self.add_line_form()
return render(request, 'free/advanced_create.html', {'form': form, 'writer_form': wri
'add_line_form': add_line_form})
I have tried both of the following in the view:
writer_choices.append((str(writer.id), writer.name)) and
writer_choices.append((writer.id, writer.name))
Here is the ServiceWriter model, just in case.
class ServiceWriter(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=20, blank=False)
def __str__(self):
return str(self.name)
Any thoughts?
Thanks for the help.
It looks like you're trying to validate the form against an empty list of choices. Have you tried populating writer_choices before instantiating or attempting to validate the form?
I am using django to digitalise a form. This form is a little bit complex, and there are a lot of fields in it. I was wondering if Django could do form.cleaned_data[] for all fields, in stead of declaring variables like obj.fieldname = form.cleaned_data['fieldname'] for each field apart.
I tried it with a forloop in the views.py, but that won't work
This is the forloop I'm talking about:
def get_form_naw(request):
if request.method == 'POST':
form = Form1(request.POST)
if form.is_valid():
for x in Model1():
formname = x.name
o = Model1()
o.formname = form.cleaned_data[formname]
o.save()
else:
form = Form1
return render(request, 'folder/home.html', context=locals())
I'm using a mysql database. My forms are declared like this:
forms.py
class Form1(forms.ModelForm):
class Meta:
model = Model1
exclude = ('id')
You shouldn't have to loop through the fields. You are using a model form, so you should just save the form:
if form.is_valid():
obj = form.save()
...
If you really need to set fields dynamically, you can use setattr.
fieldname = 'username'
value = 'my_user'
setattr(obj, fieldname, value)
you can get the instance of the data before saving like this:
if form.is_valid():
obj = form.save(commit=False) #get instance without saving
# do your thing
obj.save() #save into database
According to my very little knowledge, whenever we make a form, it extracts the form from a table and saves it to the same table.
for example:
class ExampleForm(forms.Form):
class Meta:
model=Example
Here the ExampleForm is formed from Example model and once submitted it is saved back to Example model.
What i want is, I want to develop a form from a table and save it to another table?
Is this possible?
Why do i want this?
Because, i am creating a form, that contains only checkboxes and labels of these checkboxes are retrieved from a table, but i want to save the user input into a different table
models.py
class Offer(models.Model):
package = models.ForeignKey(Package)
discount = models.CharField(max_length=120,null=True,blank=True)
transportation = models.CharField(max_length=120,null=True,blank=True)
nextTrip = models.CharField(max_length=120,null=True,blank=True)
rewardPoints = models.IntegerField(max_length=3,null=True,blank=True)
refferals = models.CharField(max_length=3, choices=REFERRAL_CHOICES)
def __str__(self):
return self.package.packageTitle
Offer model is used to create the form, but once the data is submitted, it should be saved in OfferRequest model
class OfferRequest(models.Model):
offerReq = models.ForeignKey(Offer,null=True)
userReq = models.ForeignKey(User)
discountReq = models.BooleanField(default=False)
transportationReq = models.BooleanField(default=False)
nextTripReq = models.BooleanField(default=False)
rewardPointsReq = models.BooleanField(default=False)
refferalsReq = models.BooleanField(default=False)
def __str__(self):
return self.discountReq
forms.py
class OfferRequestForm(forms.ModelForm):
discountReq = forms.BooleanField(required=False,label="Discount")
transportationReq = forms.BooleanField(required=False,label="Transportation")
nextTripReq = forms.BooleanField(required=False,label="Next Trip")
rewardPointsReq = forms.BooleanField(required=False,label="Reward Points")
refferalsReq = forms.BooleanField(required=False,label="Refferals")
class Meta:
model = OfferRequest
fields = ("discountReq","transportationReq","nextTripReq","rewardPointsReq","refferalsReq")
Since i am making the form from OfferRequest, it is rendered as shown below:
() discount
() transportation
() nextTrip
() refferals
() rewardPoints
but what i want is :
() discount : 3%
() transportation :FREE
() nextTrip :20%
() refferals : Yes
() rewardPoints : 200
The above form output can be rendered if the form is derived from Offer model, because the different offers are defined in the Offer model
Now when this form (derived from Offer) is submitted, i want it to get saved in OfferRequest
Trying my best to explain, do ask if something not clear.
If you want to add Offer's values to the field labels of the OfferRequestForm then you should override the __init__() method:
class OfferRequestForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
offer = kwargs.pop('offer')
super(OfferRequestForm, self).__init__(*args, **kwargs)
for field in offer._meta.fields:
field_name = field.name
form_field_name = field_name + 'Req'
if form_field_name in self.fields:
self.fields[form_field_name].label += \
u': %s' % getattr(offer, field_name)
So now you have to pass the offer argument to the OfferRequestForm's constructor:
def offer_req(request, offer_id):
offer = get_object_or_404(Offer, pk=offer_id)
if request.method == 'POST':
form = OfferRequestForm(request.POST, offer=offer)
if form.is_valid():
offer_request = form.save(commit=False)
offer_request.offerReq = offer
offer_request.userReq = request.user
offer_request.save()
return redirect(offer_request)
else:
form = OfferRequestForm(offer=offer)
return render(request, 'offer_req.html', {'form': form})
I have created a model Student which extends from the Django User and is a foreign key to another model while it has an integer field called year. What i'm trying to do is to save a form, which has 2 fields. The one is the course id and the another one is the the integer field year. When I'm clicking submit, i'm getting an error Cannot assign "u'2'": "Student.course" must be a "Course" instance.
models.py
class Student(models.Model):
user = models.OneToOneField(User)
course = models.ForeignKey(Course)
year = models.IntegerField(validators=[MinValueValidator(1),
MaxValueValidator(7)])
view.py
def step3(request):
user = request.user
if request.method == 'POST':
form = SelectCourseYear(request.POST)
if form.is_valid():
form.save()
return render_to_response("registration/complete.html", RequestContext(request))
else:
form = SelectCourseYear()
return render(request, 'registration/step3.html',)
forms.py
class SelectCourseYear(forms.ModelForm):
course = forms.CharField()
year = forms.IntegerField(required=True)
class Meta:
model = Student
fields = ['user', 'course', 'year']
You dont need to redefine fields in the ModelForm if you've already mentioned them in the fields attribute. So your form should look like this -
class SelectCourseYear(forms.ModelForm):
class Meta:
model = Student
fields = ['course', 'year'] # removing user. we'll handle that in view
And we can handle the form with ease in the view -
def step3(request):
user = request.user
if request.method == 'POST':
form = SelectCourseYear(request.POST)
if form.is_valid():
student = form.save(commit=False)
# commit=False tells Django that "Don't send this to database yet.
# I have more things I want to do with it."
student.user = request.user # Set the user object here
student.save() # Now you can send it to DB
return render_to_response("registration/complete.html", RequestContext(request))
else:
form = SelectCourseYear()
return render(request, 'registration/step3.html',)
course has to be an instance of a Course model, not just the primary key of the instance. You can still accept an id in the form as a text input, but you're going to need to retrieve the actual course instance and assign the value.
You'll need to verify that the course id is valid, so putting that code into the clean method isn't a bad idea. Notice also how the course field is excluded here? Otherwise the form will expect it to be present. You also don't need to re-define the year field, as the ModelForm will inherit that field from the Student model.
# forms.py
class SelectCourseYear(forms.ModelForm):
class Meta:
model = Student
exclude = ['user', 'course']
course_id = forms.IntegerField()
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(SelectCourseYear, self).__init__(*args, **kwargs)
def clean_course_id(self):
course_id = self.cleaned_data.get('course_id')
try:
self.course = Course.objects.get(pk=course_id)
except Course.DoesNotExist:
raise forms.ValidationError('Sorry, that course id is not valid.')
return course_id
def save(self, commit=True):
instance = super(SelectCourseYear, self).save(commit=False)
instance.course = self.course
instance.user = self.user
if commit:
instance.save()
return instance
# views.py
def step3(request):
if request.method == 'POST':
form = SelectCourseYear(request.POST or None, user=request.user)
if form.is_valid():
form.save()
return render_to_response("registration/complete.html",
RequestContext(request))
return render(request, 'registration/step3.html',)
Now, when you call .save() on the model, the course field will be assigned an instance of Course
I have a django app that into the model has a json field looks like this
from json_field import JSONField
from django.db import models
class C(models.Model):
name = models.CharField(max_length=255)
jf = JSONField(null=False)
There is a form that display this as follow
class Edit(forms.Form):
name = forms.CharField()
def __init__(self, *args, **kwargs):
if 'extra' in kwargs:
extra = kwargs.pop('extra')
super(Edit, self).__init__(*args, **kwargs)
for k, v in extra.iteritems():
self.fields['%s' % k] = v
else:
super(Edit, self).__init__(*args, **kwargs)
The view will load the json field jf and send it to the Form as initial data, as well
will send all the necessary fields as extra.
def edit_model(request, pk):
obj = get_object_or_404(models.C, pk=pk)
initial = model_to_dict(obj)
form = Edit(request.POST or None, initial=initial, extra=initial['jf'])
if request.method == 'POST':
if form.is_valid():
.....
# what is the best practice here ?
# intersect cleaned data with the jf fields ?!
# have an external entity that does this ?!
# is anything built into django that can help
thanks!
If I understood you can try this custom widget's form of django It does JSON to formfields and formfields -> JSON after save