Why is this Django view being executed twice on post? - django

I have a Django view that signs a user up to a free trial through Stripe. When the view makes a POST request, it does so twice.
I've tried idempotency keys, both after the if request.method == 'POST' line and in the initial rendering of the view. The customer in Stripe always ends up with two identical payment sources and two identical subscriptions to the plan.
def start_trial(request):
title = 'get started'
description = title
form = MembershipForm()
key = settings.STRIPE_PUBLISHABLE_KEY
trial_days = 30
coupon = None
custom_message = ''
subscription_idempotency = str(uuid.uuid4())
source_idempotency = str(uuid.uuid4())
try:
vendor = Vendor.objects.get(user=request.user)
custom_message = vendor.message
coupon = Coupon.objects.get(vendor.coupon)
coupon = coupon.stripe_coupon_id
trial_days = vendor.trial_days
except Vendor.DoesNotExist:
pass
try:
partner = Partner.objects.get(user=request.user)
custom_message = partner.message
coupon = Coupon.objects.get(partner.coupon)
coupon = coupon.stripe_coupon_id
trial_days = partner.trial_days
except Partner.DoesNotExist:
pass
if request.method == 'POST':
form = MembershipForm(request.POST)
if form.is_valid():
user = request.user
plan = Membership.objects.get(type_of=form.cleaned_data['plan'])
# stripe needs to attempt to create a customer
# TODO what if there's already a membership/subscription?
user_membership = UserMembership.objects.get(user=request.user)
stripe_subscription = stripe.Subscription.create(
customer=user_membership.stripe_customer_id,
items=[
{"plan": plan.stripe_plan_id}
],
trial_period_days=trial_days,
coupon=coupon,
idempotency_key=subscription_idempotency,
)
subscription = Subscription.objects.create(
user_membership=user_membership, stripe_subscription_id=stripe_subscription.id)
subscription.save()
stripe.Customer.create_source(user_membership.stripe_customer_id,
source=request.POST.get('stripeToken'),
idempotency_key=source_idempotency)
user_membership.membership = plan
user_membership.save()
user.is_subscriber = True
user.save()
# if subscription status is incomplete, display error.
# if passes, redirect to onboarding
message = 'yay'
messages.success(request, message=message)
return HttpResponseRedirect('/onboarding/')
return render(request, 'memberships/free_trial.html',
{'title': title, 'description': description, 'form': form,
'key': key, 'custom_message': custom_message})
Data always ends up in Stripe twice. Log shows:
[18/Jun/2019 11:05:21] "POST /memberships/free-trial/ HTTP/1.1" 302 0
[18/Jun/2019 11:05:22] "POST /memberships/free-trial/ HTTP/1.1" 302 0

Thanks to #duck for pointing me in the right direction. I had unseen (to me) JavaScript duplicating what was happening in the view. Removed the offending file and the problem is solved.

Related

i working on django application to charge a user before posting his products. i want to offer a free option, how to archive this and save add with sti

i am working on django application where admin can set pricing,and give coupon, my proble is how to offer a free option or free listing whe you are using stripe.
this is a function on my views.py
`#login_required(login_url='/users/login')
def create_ad_func(request):
user = request.user
if request.method == "POST":
data = dict(request.POST)
data = clean(data)
ad = AdList.objects.create_ad(**data)
img_counter = 0
img_files = request.FILES
if len(request.FILES) > 0:
for ad_img in request.FILES:
print(img_files[ad_img])
upload_img(ad_img, img_files, ad)
else:
url = upload_image(request.FILES[ad_img], ad.id, img_counter)
img_counter = img_counter + 1
data[ad_img] = url
date_time = arrow.utcnow().format('YYYY-MM-DD HH:mm:ss')
data['post_date'] = date_time
pprint(data)
AdList.objects.filter(pk=ad.id).update(**data)
objectss = AdList.objects.filter(pk=ad.id)
subscription_list = ['urgent_ad', 'regular_ad', 'featured_ad']
for key in data.keys():
if key in subscription_list:
ad_subscription = AdSubscription.objects.values()[0]
price = ad_subscription[key]
charge = ad_subscription[key] * 100
print(price, charge)
key = settings.STRIPE_PUBLISHABLE_KEY
return render(request, 'checkout.html', {"user": request.user, 'ad': ad, 'price':price, 'key':key, 'charge':charge})
else:
ad_subscription = AdSubscription.objects.values()[0]
return render(request, 'ad-list-cat.html', {"user": request.user, "subscription": ad_subscription})
and this is my manage.py
class AdListManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
def create_ad(self, **data):
"""
Create and save a User with the given email and password.
"""
email = data["email"]
email = self.normalize_email(email)
ad = self.model(**data)
ad.save()
message="your ad was published successiful"
return ad,message
def update_ad(self, pk, data):
pprint(data)
self.model.objects.filter(pk=pk).update(**data)
def list_ads(self, email):
return self.model.objects.filter(email=email)
i tried to modify so that if the value is les than <5 charge 0 but problem is that stripe do not accepte zero charge.
this is what i tried.
#login_required(login_url='/users/login')
def create_ad_func(request):
user = request.user
if request.method == "POST":
data = dict(request.POST)
data = clean(data)
ad = AdList.objects.create_ad(**data)
img_counter = 0
img_files = request.FILES
if len(request.FILES) > 0:
for ad_img in request.FILES:
print(img_files[ad_img])
upload_img(ad_img, img_files, ad)
else:
url = upload_image(request.FILES[ad_img], ad.id, img_counter)
img_counter = img_counter + 1
data[ad_img] = url
date_time = arrow.utcnow().format('YYYY-MM-DD HH:mm:ss')
data['post_date'] = date_time
pprint(data)
AdList.objects.filter(pk=ad.id).update(**data)
objectss = AdList.objects.filter(pk=ad.id)
subscription_list = ['urgent_ad', 'regular_ad', 'featured_ad']
for key in data.keys():
if key in subscription_list:
ad_subscription = AdSubscription.objects.values()[0]
if ad_subscription[key] < 5:
# save the subscription without charging with stripe
ad.subscriptions.create(
items=[{
'price': 'price_id',
'quantity': 1,
}],
expand=['latest_invoice.payment_intent']
)
price = 0
charge = 0
else:
price = ad_subscription[key]
charge = ad_subscription[key] * 100
key = settings.STRIPE_PUBLISHABLE_KEY
return render(request, 'checkout.html', {"user": request.user, 'ad': ad, 'price':price, 'key':key, 'charge':charge})
else:
ad_subscription = AdSubscription.objects.values()[0]
return render(request, 'ad-list-cat.html', {"user": request.user, "subscription": ad_subscription})
any help to archive an option of adding a free listing option while using stripe?`
I guess you want to offer a free trial for you customer? If so, you can specify a trial_end or trial_period_days when creating a subscription. Alternatively, you can also use a coupon to apply discounts to invoices generated for this particular subscription.

why do i keep getting this error( Field 'id' expected a number but got ''. ) each time users like a post from their own timeline?

Here is the users account view that i want users to be able to like their post from, it has really been a challenge to get my head around this. would appreciate some help.
def account_view(request, *args, **kwargs):
"""
- Logic here is kind of tricky
is_self
is_friend
-1: NO_REQUEST_SENT
0: THEM_SENT_TO_YOU
1: YOU_SENT_TO_THEM
"""
context = {}
user_id = kwargs.get("user_id")
try:
account = User.objects.get(pk=user_id)
except:
return HttpResponse("Something went wrong.")
if account:
context['id'] = account.id
context['username'] = account.username
context['bio'] = account.bio
context['get_full_name'] = account.get_full_name
context['email'] = account.email
context['profile_pic'] = account.profile_pic.url
context['cover_image'] = account.cover_image.url
context['city'] = account.city
context['country'] = account.country
context['gender'] = account.gender
context['hide_email'] = account.hide_email
post_id = request.GET.get("likeId", "")
try:
post_id = Post.objects.get(pk=post_id)
except Post.DoesNotExist:
liked= False
like = Like.objects.filter(user=user, post=post)
try:
post_list = Post.objects.filter(user_name=account)
except Post.DoesNotExist:
post_list = Post(user_name=account)
save.post_list()
posts = post_list.all()
context['posts'] = posts
Here is my like view, how best do can i accomplish users and friends being able to like their post from their own profile or timeline ?
def like(request):
post_id = request.GET.get("likeId", "")
user = request.user
post = Post.objects.get(pk=post_id)
liked= False
like = Like.objects.filter(user=user, post=post)
if like:
like.delete()
else:
liked = True
Like.objects.create(user=user, post=post)
resp = {
'liked':liked
}
response = json.dumps(resp)
return HttpResponse(response, content_type = "application/json")
The error occurs either because likeId is sent as an empty string http://url_path?likeId=, or (most probably) because it is not present in the request.GET at all.
You've used request.GET.get("likeId", "") so the default value is "".
Next, the code runs post_id = Post.objects.get(pk=post_id). It's forbidden to pass a string to a pk filter, hence the error. So, verify the likeId is indeed send in the request and it's an actual Post.id (check for possible typos). Maybe you've meant to use request.POST instead?
Generally, it's a bad idea to use dict.get() where you clearly DO need an value. Also, there should be some validation in place to ensure the likeId is a valid integer. I would recommend validating input parameters with a form, but a manual approach is also possible.
try:
post_id = int(request.GET["likeId")
except (KeyError, ValueError):
return HttpResponse('Provide a valid likeId integer', status_code=404)

request.user is not letting me make changes to the current user?

In my view function, I'm trying to make 2 modifications to the current user; consider him a premium subscriber by marking model field is_premium_subscriber as True and adding him to a group named Premium Agents.
However the changes don't seem to be registering in my views.py! Here is my code:
def payment_response(request):
new_charge = PremiumSubscriptionCharge()
if request.method == "POST":
... Some code here
try:
... lots of code here
new_charge.agent = request.user # This line is working fine, meaning request.user is properly assigned to the current user
request.user.is_premium_subscriber = True # This is not working, is_premium_subscriber is still false after the request
premium_agent_group = Group.objects.get(name='Premium Agents')
premium_agent_group.user_set.add(request.user) # This is not working either, the current user does not get added to the group.
request.user.save() # I don't know if this is necessary, but I put it here just in case.
except stripe.error.CardError as ce:
... some code
else:
... some code
My user model for reference. I created a custom User model by inheriting AbstractUser... could this have caused the issue?
class Agent(AbstractUser):
is_premium_subscriber = models.BooleanField(default=False)
Full views function:
def payment_response(request):
new_charge = PremiumSubscriptionCharge()
if request.method == "POST":
token = request.POST.get("stripeToken")
try:
customer = stripe.Customer.create(
email = request.user.email,
source = token,
)
charge = stripe.Charge.create(
amount = 1500,
currency = 'cad',
customer = customer.id,
description = "Agent Premium Subscription"
)
subscription = stripe.Subscription.create(
customer=customer.id,
items=[
{
"plan": "premiumagent",
},
],
)
new_charge.stripe_charge_id = charge.id
new_charge.agent = request.user
new_charge.customer = charge.customer
new_charge.stripe_subscription_id = subscription.id
request.user.is_premium_subscriber = True
premium_agent_group = Group.objects.get(name='Premium Agents')
premium_agent_group.user_set.add(request.user)
request.user.save()
except stripe.error.CardError as ce:
return False, ce
else:
new_charge.save()
return redirect("payment_success")
Okay I was working on something else, came back to it, and now it is working. What the. Thank you to those who commented.

how to overide in forms queryset none() attribute and somehow allow to save the field?

I have models.py
class Visit(Model):
reference_visit = models.ForeignKey('self',
help_text="Visit needs a refrence to Prior Visits",
null=True, blank=True)
show_prior_responses = models.BooleanField(default=False,
help_text="Show PriorResponses")
# has many field but i am making it short.
def __unicode__(self):
result = """Visit id:%s pt:%s""" % (self.id, self.patient.id)
return result
forms.py
class VisitSetupForm(Form):
list_visit_ids = ModelChoiceField(
queryset=Visit.objects.none(),
empty_label='Select Revisit ID',required=False)
show_prior_visit = ModelChoiceField(
queryset=User.objects.all(),
empty_label="Select User for Revisit",required = False)
has many but question is on list_visit_ids.
views.py
def setup(request):
"""
Allow an Admin user the ability to setup a patient & visit all at once.
"""
if request.user.is_superuser:
form_class = AdminVisitSetupForm
all_topics = True
else:
form_class = VisitSetupForm
all_topics = False
f = form_class()
# Get a list of topics for each report.
report_topics = {}
for r in Interview.objects.all():
report_topics[r.id] = [t['ad'] for t in r.topics.values('ad')]
data = {
'superuser':request.user.is_superuser,
'report_topics':simplejson.dumps(report_topics)
}
try:
request.user.reviewer
data['reviewer'] = True
except:
pass
if request.method == "POST":
f = form_class(request.POST)
if f.is_valid():
# Create the patient, generate a password, and send them on their way.
cd = f.cleaned_data
patient = None
if cd['revisit']:
# Check for an existing user first.
try:
patient = Patient.objects.get(username=cd['username'])
except Patient.DoesNotExist, e:
data['form'] = f
data['msg'] = 'There is no user with this username.'
return render_to_response('visit/setup.html', data, context_instance=RequestContext(request))
admin_user = get_user(request)
organization = None
if admin_user:
organization = admin_user.organization
if patient and not request.user.is_superuser:
# Make sure the patient they've selected is one of their own.
if patient.organization != organization:
return HttpResponseForbidden('You are not allowed to see this page.')
if not patient:
password = generate_password()
user = User.objects.create_user(cd['username'], cd['contact_email'], password)
user.first_name = cd['first_name']
user.last_name = cd['last_name']
user.save()
patient = Patient(
user=user,
username=user.username,
contact_phone=cd['contact_phone'],
date_of_birth=cd['date_of_birth'],
email=user.email,
first_name=user.first_name,
gender=cd['gender'],
last_name=user.last_name,
maiden_name=cd['maiden_name'],
organization=organization,
patient_type=cd['patient_type'],
security_answer=cd['security_answer'],
security_question=cd['security_question'],
)
patient.save()
# Send them an email.
t = loader.get_template('www/new_account.txt')
c = Context({
'password':'%s-%s-%s' % (password[:3], password[3:5], password[5:]),
'patient':patient
})
msg = t.render(c)
try:
send_mail(
'A request by your physician to do an online medical history before your appointment.',
msg,
'support#careprep.com',
[user.email]
)
except Exception, e:
log.error('Could not send email for new account %s because: [%s]' % (user.username, e))
request.session['password'] = password
# Create the Visit, too.
interview = cd['interview']
list_visit_ids = cd['list_visit_ids']
print list_visit_ids
visit = Visit(
reference_visit = cd['list_visit_ids'],
show_prior_responses = cd['show_prior_responses'],
patient=patient
)
if request.user.is_superuser:
topics = cd['topics']
else:
topics = set(list(interview.topics.all()) + list(cd['topics']))
reviewer_mode = cd.get('reviewer_mode') or patient.patient_type == 'Reviewer'
url, visit = initialize_visit(
request,
patient=patient,
starting_section=interview.starting_section,
visit_title='%s %s' % (patient, interview.title),
topics=topics,
reviewer_mode=reviewer_mode,
chief_complaint=cd['chief_complaint'],
location=cd['interview_site'],
reference_visit = cd['list_visit_ids'],
show_prior_responses = cd['show_prior_responses'],
)
next_url = "/visit/confirmation/%s/%s/?next=%s" % (patient.user.id, interview.id, url)
else:
v = Visit.objects.get(pk=request.POST['list_visit_ids'])
print v
return HttpResponseRedirect(next_url)
# all the fields that are not given pls ignore.
The template is fine.
Now watch forms.py when i do list_visit_ids = ModelChoiceField(queryset=Visit.objects.all(), empty_label='Select Revisit ID',required=False) It works perfectly fine on my local machine.But on my server it has around 6000 visit objects so this page hangs or i should say keep on loading.
So initially i changed it to list_visit_ids = ModelChoiceField(queryset=Visit.objects.none(), empty_label='Select Revisit ID',required=False)
Now i know that by this the form becomes invalid and should go to the else part Now my question how do i make reference_visit=cd['list_visit_ids'] in else (form is invalid)
case save().How do i override the none() attribute.
Thanks in advance i will really appreciate.
If your goal is to save your html page load by removing the 6000 choices (which I've done too: 10000+ <option> fields wrapped by misc html will absolutely choke a page), you shouldn't be using a ChoiceField at all. By setting queryset=Visit.objects.none() you're allowing zero choices and nothing passed in will validate.
You either show 6000 select item drop downs, radio boxes, etc., or find a way to /not/ have a giant select drop down (such as a hidden input or charfield), not fake around a ModelChoiceField who's main purpose is to populate that select drop down and validate.
In short: don't use a ModelChoiceField if you're not going to be using the html choices generated by it. Use something else and do the validation / model pulling yourself via the clean_FOO methods.
class MyForm(forms.Form):
my_input = forms.CharField()
def clean_my_input(self):
input = self.cleaned_data.get('my_input')
try:
return MyModel.objects.get(pk=input) # add a filter here if you want
# (whatever filters you were using in the queryset argument)
except MyModel.DoesNotExist:
raise forms.ValidationError("Doesn't exist / is invalid")
return input

Problem with pymongo and django unique value

I am writing django app that as a beckend is using mongodb. I am curently writing register part. Here is how I connecto to database in settings.py
if socket.gethostname() == "Production server":
CON = Connection()
DB = CON.fish
else:
CON = Connection()
DB = CON.test
DB.user.ensure_index([("username", ASCENDING),("email",ASCENDING)],unique = True)#,drop_dups=True
Here is mye register view:
def register(request):
"""
handle user registration
code variable is for testing purposes
"""
if request.method== 'GET':
form = RegisterForm(auto_id=False)
code = 1
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
elif request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
password = form.cleaned_data['password']
password_confirmation = form.cleaned_data['password_confirmation']
if password == password_confirmation:
login = form.cleaned_data['login']
email = form.cleaned_data['email']
newsletter = form.cleaned_data['newsletter']
key = register_user(login,email,password,newsletter)
if key:
#send email
send_mail("Dziękujemy za rejestrację"," Klucz aktywacyjny to " + key,settings.EMAIL_HOST_USER,[email])
request.session['email'] = email
return redirect(register_success)
else:
code = 4
error = "Login/email taken"
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
else:
code = 3
error = "invalid password"
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
else:
code = 2
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
Here is my function I use to register user:
def register_user(login,email,password,newsletter):
"""
This function will return activation key for this user if user was added successfully or none otherwise
"""
key = generate_activation_key()
user = {
"username":login,
"email":email,
"password":crypt_password(password),
"date_join": datetime.now(),
"key": key
}
if newsletter:
user['newsletter'] = True
try:
settings.DB.user.insert(user,safe = True)
except DuplicateKeyError, error:
logging.debug("error raise during saving user")
return None
except OperationFailure, error:
logging.critical("Cannot save to database")
logging.critical(error)
else:
#we have no errors users is registred
return key
And when I test it in the browser it seems to be working. But I write test for it and it isn't working anymore. Here is code for test:
def test_valid_credentials(self):
#now try to register valid user
data = {'login':'test','password':'zaq12wsx','password_confirmation':'zaq12wsx','terms':True,'newsletter':True,'email':'test#test.com'}
response = self.c.post(reverse('register'),data)
#our user should be registred
self.assertEquals(302, response.status_code,'We dont have benn redirected')
self.assertEqual(len(mail.outbox), 1,'No activation email was sent')
#clen email box
mail.outbox = []
#now try to add another user with the same data
response = self.c.post(reverse('register'),data)
#template should be rendered with error message about used login and email
self.assertEquals(200, response.status_code)#this fails
And here is error that i get.
self.assertEquals(200, response.status_code)
AssertionError: 200 != 302
So user was registred with the same username and email which shoudn't happen. Any sugestions? Thanks in advance
Why don't you use https://github.com/django-mongodb-engine/mongodb-engine it works almost perfect with Django ORM. Works like a charm for me.