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.
Related
I am attempting to take in a form for update or delete, run the process and either return the updated url, or the updated list of objects. I've got the dynamic url building working, but when I hit submit I get a 404. I am struggling with the how to process the POST, as it doesn't even seem to be hitting that far in the code. Code below:
urls.py
path("customers/", views.customers, name="customers"),
path("customers/customer/<int:id>/", views.customer),
forms.py
class CustomerMaintForm(ModelForm):
class Meta:
model = AppCustomerCst
fields = ('id_cst', 'is_active_cst', 'name_cst', 'address_1_cst', 'address_2_cst', 'address_3_cst',
'city_cst', 'state_cst', 'zip_cst', 'country_cst', 'salesrep_cst', 'type_cst',
'is_allowed_flat_cst', 'iddef_cst', 'date_created_cst', 'date_suspended_cst',
'date_first_tran_cst', 'date_last_tran_cst', 'is_credit_hold_cst',
'old_balance_cst', 'balance_notify_cst', 'balance_statement_cst',
'balance_conversion_cst', 'balance_cst', 'receive_emails_cst',
'contact_domain_cst'
)
labels = {'id_cst': 'Customer ID', 'is_active_cst': 'Active?', 'name_cst': mark_safe('<p>Name'),
'address_1_cst': 'Address 1',
'address_2_cst': 'Address 2', 'address_3_cst': 'Address 3', 'city_cst': 'City', 'state_cst': 'State',
'zip_cst': 'Zip', 'country_cst': 'Country', 'salesrep_cst': 'Sales Rep', 'type_cst': 'Type',
'is_allowed_flat_cst': 'Allowed Flat?', 'iddef_cst': mark_safe('<p>Id'),
'date_created_cst': 'Created Date', 'date_suspended_cst': 'Suspended Date',
'date_first_tran_cst': 'First Tran Date', 'date_last_tran_cst': 'Last Tran Date',
'is_credit_hold_cst': 'Credit Hold?', 'old_balance_cst': 'Old Balance',
'balance_notify_cst': 'Balance Notify', 'balance_statement_cst': 'Balance Statement',
'balance_conversion_cst': 'Balance Conversion', 'balance_cst': 'Current Balance',
'receive_emails_cst': 'Receive Emails?', 'contact_domain_cst': mark_safe('<p>Contact Domain')}
views.py
def customer(request, id):
if request.method == "GET":
obj = AppCustomerCst.objects.get(id_cst=id)
instance = get_object_or_404(AppCustomerCst, id_cst=id)
form = CustomerMaintForm(request.POST or None, instance=instance)
ContactFormSet = modelformset_factory(AppContactCnt, can_delete=True, fields=(
'name_cnt', 'phone_cnt', 'email_cnt', 'note_cnt', 'receives_emails_cnt'))
formset = ContactFormSet(queryset=AppContactCnt.objects.filter(idcst_cnt=id), prefix='contact')
tpList = AppCustomerTpRel.objects.filter(idcst_rel=id).select_related('idcst_rel', 'idtrp_rel').values(
'idtrp_rel__id_trp', 'idtrp_rel__tpid_trp', 'idtrp_rel__name_trp', 'sender_id_rel', 'category_rel',
'cust_vendor_rel')
TPFormSet = formset_factory(TPListForm, can_delete=True)
tp_formset = TPFormSet(initial=tpList, prefix='tp')
doc_list = DocData.objects.document_list(id)
DocFormSet = formset_factory(DocumentListForm)
DocFormSet = formset_factory(DocumentListForm)
doc_formset = DocFormSet(initial=doc_list, prefix='doc')
context = {'form': form, 'formset': formset, 'tp_formset': tp_formset, 'doc_formset': doc_formset, 'id': id}
print(form.errors)
return render(request, 'customer.html', context=context)
elif '_edit' in request.POST:
print(id, request.POST)
cust_name = request.POST['name_cst']
instance = get_object_or_404(AppCustomerCst, name_cst=cust_name)
form = CustomerMaintForm(request.POST, instance=instance)
if form.is_valid():
form.save()
return HttpResponseRedirect("/customers/customer/{id}")
else:
context = {'form': form, 'contact_form': contact_form}
return redirect(request, 'customer.html', context=context)
elif '_delete' in request.POST:
cust_name = request.POST['name_cst']
instance = get_object_or_404(AppCustomerCst, name_cst=cust_name)
form = CustomerMaintForm(request.POST, instance=instance)
if form.is_valid():
AppCustomerCst.objects.filter(id_cst=id).delete()
return render(request, 'customers.html')
else:
pass
customer.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% url customer string %}
{% block content %}
<form method="post" action="/customer">
{% csrf_token %}
<div style="height:300px;overflow:auto;">
{{ form }}
</div>
<input type="submit" value="Edit" name="_edit">
<input type="submit" value="Delete" name="_delete">
</form>
{% endblock %}
The 404 is because the form sends a POST to /customer and your URLs are
/customers/
/customers/customer/<int:id>/
So I'd first add a name to your path so it becomes something like path("customers/customer/<int:id>/", views.customer, name='customer')
Then change your form action to use django URL reversal;
<form method="post" action="{% url 'customer' id=id %}">
By doing this it'll generate the URL for you based on the ID of the customer form you're on, assuming id is in the context which it appears to be from your view code.
That should solve the 404 and improve things a little.
I want to use Ajax in Django to handle the view of my checkout form after it has been submitted. After the form is submitted, I want it to go to :
return HttpResponseRedirect(reverse(str(next_page))+"?address_added=True") , i.e http://127.0.0.1:8000/checkout/?address_added=True
But for some reason, it is not going there. Rather it's being going to http://127.0.0.1:8000/checkout/?csrfmiddlewaretoken=W4iXFaxwpdtbZLyVI0ov8Uw7KWOM8Ix5GcOQ4k3Ve65KPkJwPUKyBVcE1IjL3GHa&address=123+Main+Street&address2=&state=MA&country=USA&zipcode=55525&phone=%28877%29+314-0742&billing=on
As a result, the form data is also not getting saved. I was thinking if it were because of the new version of Django.
What I want to do is that after they submit the place order button, the form is going to be None, i.e disappear and then I would add a credit card form there for payment. But it is not happening. What is wrong here? How can I do this or is there a better way to do this?
My forms.py:
class UserAddressForm(forms.ModelForm):
class Meta:
model = UserAddress
fields = ["address", "address", "address2", "state", "country", "zipcode", "phone", "billing"]
My accounts.views.py:
def add_user_address(request):
try:
next_page = request.GET.get("next")
except:
next_page = None
if request.method == "POST":
form = UserAddressForm(request.POST)
if form.is_valid():
new_address = form.save(commit=False)
new_address.user = request.user
new_address.save()
if next_page is not None:
return HttpResponseRedirect(reverse(str(next_page))+"?address_added=True")
else:
raise Http404
My orders.views.py:
#login_required()
def checkout(request):
try:
the_id = request.session['cart_id']
cart = Cart.objects.get(id=the_id)
except:
the_id = None
return redirect(reverse("myshop-home"))
try:
new_order = Order.objects.get(cart=cart)
except Order.DoesNotExist:
new_order = Order(cart=cart)
new_order.cart = cart
new_order.user = request.user
new_order.order_id = id_generator()
new_order.save()
except:
return redirect(reverse("cart"))
try:
address_added = request.GET.get("address_added")
except:
address_added = None
if address_added is None:
address_form = UserAddressForm()
else:
address_form = None
if new_order.status == "Finished":
#cart.delete()
del request.session['cart_id']
del request.session['items_total']
return redirect(reverse("cart"))
context = {"address_form": address_form, "cart": cart}
template = "orders/checkout.html"
return render(request, template, context)
My urls.py:
path('ajax/add_user_address', accounts_views.add_user_address, name='ajax_add_user_address'),
My checkout.html:
<form method="POST" action="{% url 'ajax_add_user_address' %}?redirect=checkout">
{% csrf_token %}
<fieldset class="form-group">
{{ address_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-dark" type="submit">Place Order</button>
</div>
</form>
I would personally split these up in two views, because they do different stuff.
But, if you want to keep it that way, you can do the following:
First of all, because you are making an AJAX Request, you should return a JsonResponse object.
In your view you can render the checkout.html and pass it as a context variable to your json response:
def add_user_address(request):
...
data = dict()
context = {
'address_form': form,
...
}
data['html_form'] = render_to_string("checkout.html",
context,
request=request)
return JsonResponse(data)
And in your $.ajax success function you can do the following
success: function(data) {
// console.log(data);
$("div-to-replace-html").html(data.html_form);
}
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.
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.
So I am working on an e-commerce app(to do with ordering food online) and currently I am able to add an item to an order but cannot add more than one item. I really do not understand how that happens.
In my views,
def show_item(request,id):
# need to evaluate the HTTP method
if request.method == 'POST'
a = Item.objects.get(pk=id)
form = PartialOrderItemForm(request.POST,instance=a)
# check validation of posted data
if form.is_valid():
order.add_to_order(request,a)
# if test cookie worked, get rid of it
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
url =urlresolvers.reverse('order_index')
# redirect to order page
return HttpResponseRedirect(url)
else:
form = PartialOrderItemForm()
request.session.set_test_cookie()
context={
'form':form,
}
return render_to_response('item.html',context,context_instance=RequestContext(request))
after validating the form,the view calls this method which is responsible for adding items
def add_to_order(request,obj):
postdata = request.POST.copy()
#get quantity added, return 0 if empty
quantity = postdata.get('quantity',0)
# fetch the item or return missing page error_message
i = get_object_or_404(Item,pk=obj.id)
i.orderitem_set.all()
# get items in order
order_items = get_order_items(request)
item_in_orders = False
# check to see if item is already in order
for order_item in order_items:
if order_item.item.id == i.id:
#update the quantity if found
order_item.augment_quantity(quantity)
item_in_orders = True
if not item_in_orders:
# creat and save a new order item
oi = OrderItem()
oi.order_id = _order_id(request)
oi.quantity = quantity
oi.item = i
oi.save()
and here is my form in the template..
<form method="post" action=".">
{% csrf_token %}
{{ form.as_p }}
<br />
<input type="submit" id="submit_order" value="Add To Order" name="submit">
</form>
Any suggestions on how I should go about this.
Well the problem was with my indentation and could only find it with pdb.
pdb is the real deal