Merry Christmas!!!!I work with flask sqlalchemy and wtf. I could create new and would display in info.html But when I try to edit the form there is no changes in database So it is not working. So I wonder where is issues?
app.py
#With this route I can add new form in database
#app.route('/contact', methods=['GET', 'POST'])
def contact():
form = LoginForm(request.form)
if request.method == 'POST':
if form.validate()== True:
contact = Contacts()
# populate the model
form.populate_obj(contact)
db.session.add(contact)
db.session.commit()
# Contact commited to database
# RETURN TO INFO.HTML
return redirect(url_for('info'))
else:
#If the form does not have all fields that are required
return render_template('contact.html', form=form)
# This is the part for edit which is not working
# so I query and populate it but no change none in
# database none in info.html
#app.route('/edit/<int:id>', methods=['POST'])
def edit(id=None):
user = Contacts.query.get_or_404(id)
form = LoginForm(request.form,obj=user)
# check the validate and then populate the obj
if form.validate_on_submit()== True:
#populate it
form.populate_obj(user)
db.session.commit()
return redirect(url_for('info'))
else:
#If the form does not have all fields that are required
return render_template('edit.html', id=id )
#app.route('/edit/<int:id>', methods=['GET'])
def profile(id=None):
user = Contacts.query.get_or_404(id)
form = LoginForm(request.form, obj=user)
return render_template('edit.html',form=form, id =id)
# this route to html that should show all info
#app.route('/info', methods=['GET', 'POST'])
def info():
#query all
info = Contacts.query.all()
return render_template('info.html', contact=info)
model.py
# model with table name Contacts
class Contacts(db.Model):
__tablename__ = "Contacts"
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(50))
email = db.Column(db.String(50))
age = db.Column(db.Integer)
form.py
# this is the form wtf
Class LoginForm(Form):
name = StringField("Name", [validators.Required("Please enter your name.")])
email = StringField("Email", [validators.Required("Please enter your email address."), validators.Email("Please enter valid email address.")])
age = IntegerField("age", [validators.Required("Please enter your age.")])
submit = SubmitField("Submit")
info.html
# it should display all updated form But it wont??
{% extends "layout.html" %}
{% block content %}
<h2>show the info</h2>
{% for contact in contact %} # Maybe this is also Problem?
<strong>name:</strong> {{ contact.name}} <br>
<strong>email:</strong> {{ contact.email }} <br>
<strong>age:</strong> {{ contact.age}} <br>
<br>
{% endfor %}
{% endblock %}
You don't have to readd a Object, when you get it per query. The Queryobject is bound to the session. So you only need to commit the changes and not to add them again.
so this should be the corrected code snippet
user = Contacts.query.get_or_404(id)
form = LoginForm(request.form,obj=user)
# check the validate and then populate the obj
if form.validate()== True:
# populate it
form.populate_obj(user)
db.session.commit()
I tried your code on my machine. With little modification in code I was able to update database.
Please find updated chunk below:
#app.route('/edit/<int:id>', methods=['POST'])
def submit(id=None):
user = Contacts.query.get_or_404(id)
form = LoginForm(request.form,obj=user)
#return render_template('edit.html', form=form, id=1 )
if form.validate() == True:
form.populate_obj(user)
db.session.commit()
return redirect(url_for('info'))
else:
return redirect(url_for(edit, id=id))
#app.route('/edit/<int:id>', methods=['GET'])
def edit(id=None):
user = Contacts.query.get_or_404(id)
form = LoginForm(request.form,obj=user)
return render_template('edit.html', form=form, id=id )
I know this is an older question, but I'm referencing from Why doesn't my WTForms-JSON form update correctly?.
Essentially, you need to initialize the Form first then check to see if it was submitted or not:
form = FormBuilder()
if not form.is_submitted():
form = FormBuilder.populate_obj(obj)
else:
form = FormBuilder() # will populate from submitted data
if form.validate_on_submit():
It helped me when having the same issues.
Related
How to realize checking 'name' for current user in forms.py in ValidationError('Same name already added, change name').
views.py
#login_required
def main_page(request):
form = URL_listForm(request.POST)
if request.method == "POST":
if form.is_valid():
name = form.cleaned_data['name']
if URL_list.objects.filter(user=request.user, name=name).exists():
return HttpResponse('Same name already added, change name')
new_post = form.save(commit=False)
new_post.user = request.user
new_post.save()
return HttpResponse("Data added")
return render(request, 'link/main.html', {'form': form})
If you want validate in database
#-------ADDED CODE
data_tmp = """SELECT count(*) from jobtest WHERE link = %s""", (line)
data_tmp = cur.fetchall()
#-------END ADDED CODE
if (data_tmp == 0 ) :
Not exist
add form with name
<input type="text" id="projectName" size="40" placeholder="Spot your project files">
<input type="button" id="spotButton" value="Spot">
when press post button and action to api you can get value in input field using request.form['Name']
if you want send data from server code to html
return render_template('index.html', data=userinfo)
and render as
{% userinfo %}
Good day everyone.
I am trying to build a form which queries the database based on user data inputs and then returns the results in a new page. but I don't know exactly how to do it and I am getting errors. I've looked for a solution but couldn't find any. Please help me if you know any solutions.
Thanks in advance.
Here are my codes:
forms.py
class AttendanceForm(forms.Form):
course = forms.CharField(max_length=50)
department = forms.CharField(max_length=10)
semester = forms.IntegerField()
views.py
class AttendanceForm(generic.FormView):
form_class = CrsAttForm
template_name = 'office/crsatt_form.html'
success_url = reverse_lazy('office:members_list')
class MembersList(generic.ListView):
template_name = "office/crs_att.html"
context_object_name = 'members'
def get_queryset(self):
return Members.objects.all()
# I know I should use .filter method but how could I set the parameters to data received from the form
urls.py
url(r'^CourseAttendanceForm/$', views.AttendanceForm.as_view(), name='courseattendance'),
url(r'^CourseAttendanceForm/Results/$',views.MembersList.as_view(), name='memebrs_list'),
I think that it will be easier for you to use function based views for this one.
You can do it like this:
views.py
def form_page(request):
form = AttendanceForm()
# you get to this "if" if the form has been filled by the user
if request.method == "POST":
form = AttendanceForm(request.POST)
if form.is_valid():
course = request.POST['course']
department = request.POST['department']
semester = request.POST['semester']
members = Member.objects.filter(#here you do your filters as you already have the course, department and semester variables)
context = {'members': members}
return render(request, 'second_page.html', context)
# if the form hasn't been filled by the user you display the form
context = {'form': form}
return render(request, 'form_page.html', context)
form_page.html
<form method="post" action="{% url 'form_page' %}">
{% csrf_token %}
{{ form }}
<button type="submit">Search!</button>
</form>
urls.py
path('form_page/', views.form_page, name='form_page')
second_page.html
{% for member in members %}
# here you display whatever you want to
{% endfor %}
Hi Djangonauts,
I am integrating stripe in my in my project. I do not want users to enter their email in their stripe payment form. Instead I want the email they registered on my site as their checkout email. I have the below form. When this form renders. It asks for users.
Name:,
Email:,
Billing Address:,
Credit Card Details:,
Can I change email from
email = request.POST['stripeEmail']
to
If user.is_authenticated:
email = request.user.email
I am aware that by doing this anonymous users will not be able to checkout and I am ok with that. I can add #loginrequired() decorator before the function
I have Order history view
#login_required()
def orderHistory(request):
if request.user.is_authenticated:
email = str(request.user.email)
order_details = Order.objects.filter(emailAddress=email)
return render(request, 'order/order_list.html', {'order_details': order_details})
This code fetches Orders in Order History order_details = Order.objects.filter(emailAddress=email) when users sign up with 1 email and use another email at checkout the orders don't appear in their Order history. Plus it is mandatory to have a account to checkout that's why I needed the below
Below are the views.py of my shopping cart
def cart_detail(request, total=0, counter=0, cart_items=None):
try:
cart = Cart.objects.get(cart_id=_cart_id(request))
cart_items = CartItem.objects.filter(cart=cart, active=True)
for cart_item in cart_items:
total += (cart_item.tasting.price * cart_item.quantity)
counter += cart_item.quantity
except ObjectDoesNotExist:
pass
stripe.api_key = settings.STRIPE_SECRET_KEY
stripe_total = int(total * 100)
description = 'Khal: Share your recipes - New tasting request'
data_key = settings.STRIPE_PUBLISHABLE_KEY
if request.method == 'POST':
# print(request.POST)
try:
token = request.POST['stripeToken']
email = request.POST['stripeEmail']
billingName = request.POST['stripeBillingName']
billingAddress1 = request.POST['stripeBillingAddressLine1']
billingCity = request.POST['stripeBillingAddressCity']
billingZipcode = request.POST['stripeBillingAddressZip']
billingCountry = request.POST['stripeBillingAddressCountryCode']
customer = stripe.Customer.create(
email=email,
source=token
)
charge = stripe.Charge.create(
amount=stripe_total,
currency='usd',
description=description,
customer=customer.id,
)
'''Creating the Order'''
try:
order_details = Order.objects.create(
token=token,
total=total,
emailAddress=email,
billingName=billingName,
billingAddress1=billingAddress1,
billingCity=billingCity,
billingZipcode=billingZipcode,
billingCountry=billingCountry,
)
order_details.save()
for order_item in cart_items:
oi = OrderItem.objects.create(
tasting=order_item.tasting.post.title,
quantity=order_item.quantity,
price=order_item.tasting.price,
order=order_details
)
oi.save()
'''Reduce stock when Order is placed or saved'''
tastings = Tasting.objects.get(id=order_item.tasting.id)
tastings.stock = int(order_item.tasting.stock - order_item.quantity)
tastings.save()
order_item.delete()
'''The terminal will print this message when the order is saved'''
print('The order has been created')
try:
'''*********************Calling the sendEmail function************************************'''
sendEmail(order_details.id)
print('The order email has been sent to the customer.')
except IOError as e:
return e
return redirect('order:thanks', order_details.id)
except ObjectDoesNotExist:
pass
except stripe.error.CardError as e:
return False,e
return render(request, 'cart/cart.html', dict(cart_items=cart_items, total=total, counter=counter, data_key=data_key,
stripe_total=stripe_total, description=description))
I have also attached below my cart.html template
<form action="" method="POST">
{% csrf_token %}
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{{ data_key }}"
data-amount="{{ stripe_total }}"
data-name="Perfect Cushion Store"
data-description="{{ description }}"
data-image="{% static 'images/logo.png' %}"
data-locale="auto"
data-currency="usd"
data-shipping-address="true"
data-billing-address="true"
data-zip-code="true">
</script>
</form>
I believe you can hide email by including data-email into the stripe script :
cart.html:
<form action="" method="POST">
{% csrf_token %}
<script ... data-email="{{request.user.email}}"></script>
</form>
You could then retrieve stripeEmail or directly use request.user.email in your view.
I have a Django 1.8 form that contains a paragraph tag that renders either some feedback or a question submitted by a user. It also contains a textarea input 'response_text' and a pair of radio buttons 'close_issue'. This response input can be used to send an optional response to the user. If the user submitted some feedback, the admin should be able to click the 'close issue' radio button and submit the form with no response. However, if the textarea input contains a question, then the form should render an error telling the admin that he/she can't submit the form without typing an answer into the response input. The problem I'm having is that I can't get the form to cause the template to render an error message if the user submitted a question but the admin didn't type in a response. My view, model, form, and template are shown below. forms.py shows all the ways (all commented out) I have tried to make the response input field required if the user submitted a question so that the template will display an error. I also tried overriding the default 'clean' method with one that would raise a ValidationError if the user submitted a question and the response input is blank but that didn't work either. Can anyone tell me what I'm doing wrong?
Thanks.
# view.py
def review_feedback_or_question(request, template, *args, **kwargs):
fqid = kwargs['fqid']## Heading ##
submission = FeedbackQuestion.objects.get(pk=fqid)
if request.method == 'POST':
form = FeedbackQuestionResponseForm(request.POST, submission=submission)
if form.is_valid():
# process the form
return redirect('review-feedback-or-question-queue')
else:
pass
form = FeedbackQuestionResponseForm(submission=submission)
context = {'form': form, 'submission': submission,}
return render(request, template, context)
# models.py
class FeedbackQuestion(models.Model):
SELECT = ''
FEEDBACK = 'feedback'
QUESTION = 'question'
SUBMISSION_TYPE_CHOICES = (
(SELECT , '-- Select --'),
(FEEDBACK, 'Feedback'),
(QUESTION, 'Question'),
)
user = models.ForeignKey(User, related_name="user")
submission_type = models.CharField(max_length=8,
choices=SUBMISSION_TYPE_CHOICES,
default=SELECT)
submission_text = models.TextField()
date_submitted = models.DateTimeField(auto_now_add=True)
response_text = models.TextField()
respondent = models.ForeignKey(User, related_name='respondent')
date_responded = models.DateTimeField(auto_now=True)
issue_closed = models.BooleanField(default=False)
class Meta:
db_table = 'feedback_question'
# forms.py
class FeedbackQuestionResponseForm(forms.Form):
TRUE = 1
FALSE = 0
BLANK = ''
CHOICES = ( (TRUE, 'Yes'), (FALSE, 'No') )
response_text = forms.CharField(
required=False,
label='',
widget=forms.Textarea(attrs={'placeholder': 'Enter response...'}))
close_issue = forms.TypedChoiceField(
choices=CHOICES,
label='Close this issue?',
widget=forms.RadioSelect(renderer=HorizontalRadioRenderer),
coerce=int)
def __init__(self, *args, **kwargs):
if 'submission' in kwargs:
submission = kwargs.pop('submission')
if submission.submission_type == 'question':
# NONE OF THESE WORKED!
#self.fields.get('response_text').required = True
#self.declared_fields['response_text'].required = self.TRUE
#self.declared_fields['response_text'].required = self.TRUE
#self.declared_fields['response_text'].required = True
#self._errors['response_text'] = "You must enter a response"
pass
super(FeedbackQuestionResponseForm, self).__init__(*args, **kwargs)
# template.html
<p>{{ submission.submission_text }}</p>
<form action="" method="post">{% csrf_token %}
{{ form.non_field_errors }}
{% if form.errors %}
{% if form.errors.items|length == 1 %}
Please correct the error below.
{% else %}
Please correct the errors below.
{% endif %}
</p>
{% endif %}
{{ form.response_text.errors }}
{{ form.response_text.label_tag }} {{ form.response_text }}
{{ form.close_issue.errors }}
{{ form.close_issue }} {{ form.close_issue.label_tag }}
<input type="submit" value="Submit" class="" />
</form>
You're not passing submission into the form when you instantiate it on POST, so the required attribute is never being set.
Daniel Roseman was correct in that I need to pass 'submission' into the form when I instantiate the form on POST. But there were still two other problems. First, I need to instantiate the form inside the else block. If this isn't done and the form doesn't validate, then you're passing an unbound form back to the viewer and any errors won't be displayed. Also, it isn't necessary to pass 'submission' to the form when you instantiate it here:
...
else:
form = FeedbackQuestionResponseForm()
context = {...}
...
The next problem was that the order of my statements inside the init method was incorrect. It appears that I needed to execute 'super()' before trying to reference the 'response_text' field. I'll need to locate and study this method in the Django source code to understand exactly why. In any case, this works:
def __init__(self, *args, **kwargs):
if 'submission' in kwargs:
submission = kwargs.pop('submission')
else:
submission = False
super(FeedbackQuestionResponseForm, self).__init__(*args, **kwargs)
if submission:
if submission.submission_type == 'question':
self.fields['response_text'].required = True
else:
self.fields['response_text'].required = False
When the above changes are implemented, the form will make the response_text field required if the user submits a question and an error will be displayed if the admin doesn't enter a response before submitting the form. Many thanks again to Daniel for getting me back on track towards finding a solution.
I'm having trouble getting an image field to upload correctly with django crispy forms. Everything else on the form and page works fine, but the image field does not error or save, it just passes right over it. I am able to add the image through admin just fine, it only fails on my crispy form.
#views.py
#login_required
def dashboard(request, **kwargs):
'''
perform managerial and administrative tasks for a blog. Only
available to the blog owner
'''
alert_message = ""
status = ""
blog_slug = kwargs['blog']
blog = get_object_or_404(PersonalBlog, slug=blog_slug)
# handle the form submit to update blog data
form = BlogEditForm(instance=blog)
if request.method == "POST":
if blog.owner == request.user:
form = BlogEditForm(request.POST, instance=blog)
if form.is_valid():
form.save()
alert_message = "Your blog data has been updated successfully"
status = "saved"
else:
alert_message = "There was a problem saving the data you entered. Please correct the errors above."
status = "error"
else:
alert_message = "You do not have access to update this blog's information."
status = "error"
return render(request, "blogcontent/dashboard.html", {'alert_message':alert_message,
'status':status, 'form':form})
#forms.py
class BlogEditForm(ModelForm):
description = forms.CharField(widget = forms.Textarea())
twitter = forms.CharField(required=False, help_text="show twitter feed, and allow people to interact with you on twitter")
twitter_widget_id = forms.CharField(required=False, help_text="required to show a timeline widget for your twitter account. " + \
"<span class='glyphicon glyphicon-question-sign'></span>")
instagram = forms.CharField(required=False, help_text="show instagram feed on your blog page")
disqus = forms.CharField(required=False, help_text="allow comments at the bottom of your blog posts")
class Meta:
model = PersonalBlog
def __init__(self, *args, **kwargs):
super(BlogEditForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(
'<h2 class="text-center">Edit data about your blog</h2>',
Field('owner', type="hidden"),
Field('title', type="hidden"),
Div('description', css_class="col-md-12"),
Div('twitter', css_class="col-md-6"),
Div('twitter_widget_id', css_class="col-md-6"),
Div('instagram', css_class="col-md-6"),
Div('disqus', css_class="col-md-6"),
Div('logo', css_class="col-md-12"),
),
ButtonHolder(
Submit('submit', 'Update Info', css_class='btn-lg'),
css_class="text-center"
),
)
#dashboard.html
<form method="post" enctype="multipart/form-data">
{% crispy form %}
</form>
Ah, I knew it was going to be something dumb. I was not attaching the request.FILES to the form.save() object.
form = BlogEditForm(request.POST, request.FILES, instance=blog)
Have you tried changing:
<form method="post" enctype="multipart/form-data">
{% crispy form %}
</form>
To just:
{% load crispy_forms_tags %}
{% crispy form %}
Also in your code, your are calling:
if form.is_valid():
form.save()
You don't want to save() the form. You want to save the form data to a model instance. So create() a model using the form data. This may be why as well. Forms are just used to hold data until you clean it and save it to the database using a model.