I'm trying to implement a form that is used to update information that has previously been posted by a user. Unfortunately, I am getting a TypeError: 'str' object is not callable.
I was looking for solutions online but could not find any - my guess is that the error has something to do with the fact that I am trying to prefill the value of a Select Field but I might be wrong.
views.py
#users.route('/<int:query_id>/update', methods=['GET', 'POST'])
#login_required
def update_query(query_id):
query = Model.query.get_or_404(query_id)
if query.author != current_user:
abort(403)
form = QueryForm()
if form.validate_on_submit():
query.property_type = form.property_type.data
query.property_type_details = form.property_type_details.data
db.session.commit()
return redirect(url_for('users.user_profile', username=current_user.username))
elif request.method == 'GET':
form.property_type = query.property_type
form.property_type_details = query.property_type_details
return render_template('users/update-query.html', form=form)
forms.py
class QueryForm(FlaskForm):
submit = SubmitField('Send')
property_type = SelectField(u'Type', choices=[('House', 'House'), ('Apartment', 'Apartment')])
property_type_details = SelectField(u'Detail', choices=[('Something', 'Something'),('SomethingElse', 'SomethingElse')])
template
<form method='POST' class="query-form" action="" enctype="multipart/form-data">
{{form.hidden_tag()}}
<h4 class="text-center">Info</h4>
<div class="form-row">
<div class="form-group col-md-4">
{{form.property_type.label}}
{{form.property_type(class="form-control")}}
</div>
<div class="form-group col-md-4">
{{form.property_type_details.label}}
{{form.property_type_details(class="form-control")}}
</div>
</div>
</form>
Most recent call and error
File "/Users/1/Desktop/Code/Project/Name/main/templates/users/update-query.html", line 33, in block "content"
{{form.property_type_details(class="form-control")}}
TypeError: 'str' object is not callable
Pre-filling both form fields means setting the data attribute for both field instances. 1
Currently, instances of both fields are overridden by values retrieved from the database.
The block pre-filling both fields when updated as below addresses errors with rendering both fields pre-filled in the template.
elif request.method == 'GET':
form.property_type.data = query.property_type
form.property_type_details.data = query.property_type_details
Related
I am creating a multi-choice quiz app, I have created a view which shows the question and 4 option. I have given radio button to each option but is giving me this error:
MultiValueDictKeyError at /quiz/2/11/ 'choice'
views.py
def question_detail(request,question_id,quiz_id):
q = Quiz.objects.get(pk=quiz_id)
que = Question.objects.get(pk=question_id)
ans = que.answer_set.all()
selected_choice = que.answer_set.get(pk=request.POST['choice'])
if selected_choice is True:
come = que.rank
came = come + 1
later_question = q.question_set.get(rank=came)
return render(request,'app/question_detail.html',{'que':que , 'later_question':later_question, 'ans':ans})
else:
come = que.rank
later_question = q.question_set.get(rank=come)
return render(request, 'app/question_detail.html', {'que': que, 'later_question': later_question, 'ans': ans})
question_detail.html
<form action="{% 'app:detail' quiz_id=quiz.id question_id=que.id %}" method="post">
{% csrf_token %}
{% for choice in que.answer_set.all %}
<input type="radio" name="choice" id="choice{{forloop.counter}}" value="{{choice.id}}">
<label for="choice{{forloop.counter}}">{{choice.answer}}</label>
{% endfor %}
</form>
Okay like I said in my comment, you're most likely getting that error because the POST object will be empty during a normal GET request. So you should wrap everything that's meant to happen after a request in an IF block:
if request.method === 'POST':
selected_choice = que.answer_set.get(pk=request.POST['choice'])
# Every other post-submit task
You should always check for the POST method in your views if you're expecting form data. Others have answered this more in-depth before so I would just direct you there:
What does request.method == "POST" mean in Django?
it is probably too late again for me to find out what is wrong. I am having a simple form forms.py:
class ImportPortfolioForm(forms.Form):
file = forms.FileField(required=True)
price_per_share = forms.BooleanField('Price per Share', required=False, initial=True,
help_text="If not checked, total cost is expected in Price column.")
this is html:
<form method="post" action="" class="wide" class="form-horizontal" enctype="multipart/form-data">
<div class="col-md-6">
{% csrf_token %}
{% bootstrap_form form %}
<button type="submit" class="btn btn-primary">Import</button>
</div>
</form>
and this is views.py:
if request.method == 'POST':
form = ImportPortfolioForm(request.POST, request.FILES)
if form.is_valid():
data = form.cleaned_data
# work with file ...
else:
form = ImportPortfolioForm()
I am getting error if I try to load form url:
TypeError: __init__() got multiple values for keyword argument 'required'
If I remove required like this:
class ImportPortfolioForm(forms.Form):
file = forms.FileField(required=True)
price_per_share = forms.BooleanField('Price per Share', initial=True,
help_text="If not checked, total cost is expected in Price column.")
I can load form url. If I add file and send form, it claims field price per share is required:
I do not know why this behaviour happens. I guess request.POST in form initialization somehow adds required=True to the form. But I do not know why it does so or why I can not overwrite it in a form. Any ideas?
...
price_per_share = forms.BooleanField('Price per Share', required=False, initial=True)
Only model fields accept a label as the first positional argument. Form fields require you to use the label keyword. required is the first argument for form fields, so you're passing it both as a positional argument and as a keyword argument.
Generally you'd only use keyword arguments in form fields. The keyword you're probably looking for is label:
price_per_share = forms.BooleanField(label='Price per Share', required=False, initial=True)
I have three forms in three tabs respectively in a template.
I fill in the first tab, submit, fill in the second form, submit, fill in the third form, submit.
Is there a way to keep the data in each form after saving? I need to show them all together.
No, when I save the second form I lose my data on the first form.
input.html: template
<form class="tab-pane fade in active" id="demographics" method="post" >
<input type="hidden" name="form_id" value="demographics">
{%crispy frm%}
</form>
<form class="tab-pane fade" id="diagnosis" method="post">
<input type="hidden" name="form_id" value="diagnosis">
{%crispy frm_d%}
</form>
<form class="tab-pane fade" id="a_b_sickle" method="post">
<input type="hidden" name="form_id" value="a_b_sickle">
{%crispy frm_a_b_s%}
</form>
views.py
def input(request):
context = RequestContext(request)
if request.method == 'POST':
submitted = request.POST.get('form_id', '')
print submitted
if submitted == 'demographics':
# Get the Form1 instance
my_demographics = DemographicForm(request.POST)
#my_diagnosis = DiagnosisForm()
if my_demographics.is_valid():
my_demographics_object= my_demographics.save()
my_diagnosis=DiagnosisForm({'patient': my_demographics_object.patient_id, 'diagnosis_option': 'b-thalassaemia syndromes'})
my_a_b_sickle=A_b_sickle_thalForm({'patient': my_demographics_object.patient_id})
else:
my_diagnosis=DiagnosisForm()
my_a_b_sickle = A_b_sickle_thalForm()
elif submitted == 'diagnosis':
my_diagnosis = DiagnosisForm(request.POST)
my_demographics = DemographicForm()
my_a_b_sickle = A_b_sickle_thalForm()
if my_diagnosis.is_valid():
my_diagnosis_object=my_diagnosis.save()
my_a_b_sickle =A_b_sickle_thalForm({'patient': my_diagnosis_object.patient})
else:
my_demographics = DemographicForm()
my_a_b_sickle = A_b_sickle_thalForm()
elif submitted == 'a_b_sickle':
my_a_b_sickle = A_b_sickle_thalForm(request.POST)
my_demographics = DemographicForm()
my_diagnosis = DiagnosisForm()
if my_a_b_sickle.is_valid():
my_a_b_sickle.save()
else:
raise ValueError('No form specified !')
else:
my_demographics = DemographicForm()
my_diagnosis = DiagnosisForm()
my_a_b_sickle= A_b_sickle_thalForm()
return render(request,'input.html', {'frm':my_demographics, 'frm_d': my_diagnosis, 'frm_a_b_s': my_a_b_sickle})
Any ideas please?
You can either submit them using ajax or send them back filled in your context. If you can get the saved objects between request by any association they have you can try:
For the second way you can try something like this:
my_demographics = DemographicForm(my_demographic_object)
my_diagnosis = DiagnosisForm(my_diagnosis_object)
my_a_b_sickle= A_b_sickle_thalForm(my_a_b_sickle)
return render(request,'input.html', {'frm':my_demographics, 'frm_d': my_diagnosis, 'frm_a_b_s': my_a_b_sickle})
In fact, with that you can even make that work as an update form with a little extra using the 'instance' attribute of ModelForm.
I am new to django forms and Crispy Forms. I have some simple forms in a little forum Im developing. I think I don't need to use the %crispy% tag. I only need the form|crispy filter. However, I don't know why they don't render the error messages.
Also, if I want to customize the error messages (they must be in spanish), do I need to use the %crispy% tag or is it possible to do this with the |crispy filter?
Anyway, here is one of my forms:
from django import forms
from django.forms import Textarea
class FormNuevoVideo(forms.Form):
url = forms.URLField(initial='http://', max_length=250)
titulo = forms.CharField(max_length=150)
descripcion = forms.CharField(
help_text="...",
widget=Textarea(attrs={'rows': 3, 'data-maxlength': 500}))
Here is the view:
#login_required
def nuevo_video(request, slug):
template = 'videos/nuevo.html'
tema = Temas.objects.get(slug=slug)
if request.method == 'POST':
form = FormNuevoVideo(request.POST)
if form.is_valid():
...
nuevo_video.save()
return redirect('videos:videos_tema', slug=tema.slug, queryset='recientes')
else:
return redirect('videos:nuevo_video', slug=tema.slug) #this same view.
else:
form_nuevo_video = FormNuevoVideo()
context = {'form_nuevo_video': form_nuevo_video, 'tema': tema}
return render(request, template, context)
And in the HTML:
{% block form %}
<form action = "{% url 'videos:nuevo_video' tema.slug %}" method = "post">
{% csrf_token %}
{{form_nuevo_video|crispy}}
<input class = "btn pull-right" type = "submit" value ="enviar"/>
</form>
{% endblock form %}
So, lets say, when someone tries to submit a video with a title of more than 150 characters, it doesn't display the error. I am sure I am missing something simple. Also, I'd like to customize the error messages so that they are in spanish. Thanks in advance.
Argh. Hey all, i have a muy simple django question:
And argh, i'm sorry, i've read and read, and I am sure this is covered somewhere super-obviously, but i haven't found it!
How do i edit/update a model using django? Like, the data values? Not the model fields?
Here is my code! (I'm using a home-brew version of stuff!)
Here is the urls:
url(r'^editStory/(?P<id>\d+)$',
StoryModelView.as_view(
context_object_name='form',
template_name ='stories/editStory.html',
success_template= 'stories/editStorySuccess.html'
),
{},
'editStory'
),
Here is the view:
def get(self,request,id=None):
form = self.getForm(request,id)
return self.renderValidations(form)
def getForm(self, request,id):
if id:
return self.getModelById(request,id)
return StoryForm()
def getModelById(self,request,id):
theStory = get_object_or_404(Story, pk=id)
if theStory.user != request.user:
raise HttpResponseForbidden()
return StoryForm(theStory)
def renderValidations(self,form):
if self.context_object_name:
contextName = self.context_object_name
else:
contextName = 'form'
if self.template_name:
return render_to_response(self.template_name,{contextName:form})
else :
return render_to_response('stories/addStory.html',{contextName:form})
def getPostForm(self,request,id):
if id:
theStory = self.idHelper(request,id)
return StoryForm(request.POST,theStory)
return StoryForm(request.POST)
def processForm(self,form,request):
theStory = form.save(commit=False)
theStory.user = request.user
return theStory
Here is the template code:
{% block content %}
<h3>Edit story</h3>
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
<input type="submit" value="Submit"/>
</form>
{% endblock %}
try as i might, i either:
get an error
get nothing
i get an error with the code as-displayed, caused by this line
{% for field in form %}
and with the error of:
Caught AttributeError while rendering: 'Story' object has no attribute 'get'
or i get nothing - no data at all - if i change my "getModelById" method to read:
def getModelById(self,request,id):
theStory = get_object_or_404(StoryForm, pk=id)
if theStory.user != request.user:
raise HttpResponseForbidden()
return theStory
StoryForm is one of those "ModelForm" things, and its model is "Story".
SO! The question:
how do i fix this code to make it work? What have i done wrong?
You don't show what your class is inheriting from, but it seems like you're just using a standard single object display view. Instead, you should use one of the editing mixins that are provided for this purpose.
Without knowing what your model looks like, are you looking for something along the lines of
s = Story.objects.get(some criteria)
s.user = <some user>
s.save()
?
Sorry, I find your question a little vague.
Upon rereading, one thing jumped out at me:
You can't do a query (get, filter, or any variation on these) on a model-- you have to do it on an object manager, like objects.
So, as above, in your case, Story.objects.get_object_or_404 should solve your error.