How to get models current values from a view to another? - python

I have a website where I would like to display the product name the user purchased after he was redirected from the checkout to the thank you page.
The problem is that I don't get how I could send a data from a view to another without creating a form in the template.
here is two example of views from checkout_payment to checkout_confirmation pages:
def checkout_payment(request):
customer_id = request.user.profile.stripe_id
if request.method == 'POST':
try:
gig = Gig.objects.get(id=request.POST.get('gig_id'))
except Gig.DoesNotExist:
return redirect(reverse('purchase_error_detail'))
return redirect(reverse('purchase_confirmation_detail'))
def checkout_confirmation(request):
#how can I get the purchased gig datas ?
return render(request, 'purchase/confirmation.html', {})
models.py Gig contains : user, title, price fields.
urls.py : name='purchase_confirmation_detail'
Is there a way to get the last purchased datas avoiding using a form or the urls to get the product informations ?

Easy and fast way: Sessions
If all you need is a list of strings or a single string, you can just use sessions. You can read about them in detail in the docs. Just save the names in some key, display them and clear them.
Better, more future proof solution but slightly more complicated: Models
When you are selling something, it is desirable to keep around some record of what the user bought. This can be helpful when system fails (trust me, it will) or to keep a record of everything.
It can be something as simple as:
class Transaction(models.Model):
gig = models.ForeignKey(Gig)
user = models.ForeignKey(User)
Now you refactor your view in 2 ways:
Only the user in the transaction should be able to see the content on it.
Add the pk of the Gig to the url you redirected to.
Your source view should use a redirect like:
def checkout_payment(request):
customer_id = request.user.profile.stripe_id
if request.method == 'POST':
try:
gig = Gig.objects.get(id=request.POST.get('gig_id'))
except Gig.DoesNotExist:
return redirect(reverse('purchase_error_detail'))
new_transaction = Transaction.objects.create(user=request.user, gig=gig)
return redirect(reverse('purchase_confirmation_detail', kwargs={'pk': new_transaction.pk}))
And your destination view will be something like:
def checkout_confirmation(request, *args, **kwargs):
new_transaction = Transaction.objects.get(kwargs.get('pk'))
if request.user != new_transaction.user:
return HttpResponseForbidden() # You can raise Http404 here too to hide the resource, like github does
return render(request, 'purchase/confirmation.html', {'gig': transaction.gig})
Now you have access to everything you need to display.

Related

How can i fetch my data from database to django template?

Whenever I run this,
Exception Value:
name 'current_user' is not defined;
error is raised.
I am not getting where i am doing the mistake as I m new in django programming. Please help me fetch the data
# To add a new product in the database
def AddNewProduct(request):
if request.method == "POST":
current_user = request.user
product_title =request.POST['product_title']
uid = request.POST['uid']
specification =request.POST['specification']
sale_price = request.POST['sale_price']
discount = request.POST['discount']
img1 = request.FILES['img1']
img2 = request.FILES['img2']
promote_method = request.POST['promote_method']
terms_conditions = request.POST['terms_conditions']
newproduct = AffProduct(user_id=current_user.id, product_title=product_title, uid=uid, specification=specification, sale_price=sale_price,
discount=discount, img1=request.FILES.get('img1'), img2=request.FILES.get('img2'),
promote_method=promote_method, terms_conditions=terms_conditions)
newproduct.save()
# Status message
messages.success(request, 'Product added successfully')
return render(request, 'blink_network.html')
else:
return render(request, 'blink_network.html')
#Here i m trying to fetch my data.
def showproduct(request):
if request.user.is_authenticated:
result = AffProduct.objects.filter(user_id=current_user.id)
else:
result = AffProduct.objects.all()
return render(request, 'blink_viewproduct.html', {'result': result})
It looks like you will be getting that problem from showproduct(request) because you don't define current_user in that method before calling it.
to call this
result = AffProduct.objects.filter(user_id=current_user.id)
you need to define current_user = request.user beforehand
Could you share the relevant models.py file as well? You probably linked the user model with the ForeignKey with the Product model. If you did this, you need to give current_user, not current_user.id, django handles the matching itself.
Also, I guess you are using django form. If you are using it, I recommend you to use it because you can increase the readability of your code by writing less code.

Posting product quantity in a Django form

I'm working with an e-commerce webapp and in the product detailed-view I want to give the option to set the quantity before the checkout. I thought I could do this with a simple form:
class QuantityForm(forms.Form):
quantity = forms.IntegerField(widget=forms.NumberInput(attrs={'class':'required'}))
And then implementing it to the view:
class BagDetailView(DetailView):
context_object_name = 'ctx'
model = Bag
template_name = 'product_page.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = QuantityForm(initial={'quantity':1})
context['Jackson'] = Bag.objects.get(title = 'Jackson')
context['Anthony'] = Bag.objects.get(title = 'Anthony')
return context
But the problem is the POST request. I cannot call the render() function because I have another view to handle the checkout, so I need to call redirect(). This is the code:
def post(self, *args, **kwargs):
form = QuantityForm()
b = Bag.objects.get(slug=kwargs['slug'])
if form.is_valid:
return redirect(b)# calls get_absolute_url which redirects to checkout/<slug>
And I cannot access the data that I'm posting in the other view. I think it's bad practise to post data like this to another view, but I couldn't come up with anything but that. Is there any other way to pass that data into the other view?
Note: I'm not using a cart system because I'm only dealing with two products.
I am not sure if I have understood correctly, maybe you can do something like this.
In the template for increasing quantity, you can put this:
<i class="">INCREASE QUANTITY</i>
When the user clicks this, a function will be called:
#login_required
def add_to_checkout(request, slug):
#get the checkout for this customer which is not fulfilled
#increase the quantity
#redirect to checkout page
Another idea can be using session. You can increase the amount in the detail page and save it to the sessions, then use in the checkout page.
I hope I have understood correctly your question.

Django: User Reporting Some URL on Website

So i'm trying to build something, so that users would be able to report something on site. Here's the model,
class Report(models.Model):
reporting_url = models.URLField()
message = models.TextField()
I created Form for this Model including 'message' field only because 'reporting_url' is something it needs to populate by itself depending upon the specific page from where user has clicked "Report" button.
def report(request):
url_report = ???
if request.method == 'POST':
form = ReportForm(request.POST or None)
if form.is_valid():
new_form = form.save(commit=False)
new_form.reporting_url = url_report
new_form.save()
I was wondering How can I pass the specific url to 'reporting_url' field in form depending on the Page from where user has clicked "Report" button? (Much like s we see on social Networks).
Am I doing this correctly, Or is there a better way for doing this?
Please help me with this code. Thanks in Advance!
If there is a report button on that specific page then I believe you could write custom context processor.
More info: Django: get URL of current page, including parameters, in a template
https://docs.djangoproject.com/en/1.11/ref/templates/api/
Or maybe just write it directly in the views.py in your function and set
url_report = request.get_full_path()
I think you can use the form on the same page of the URL and use:
url_report = request.get_full_path()
in the view, to get the current URL.
Else if you want to create a separate view for the reporting form. You can use
url_report = request.META.get('HTTP_REFERER')
to get the previous or refering URL which led the user to that page.
request.META.get('HTTP_REFERER') will return None if it come from a different website.

Django and one-time links with data

I think I have a simple case here but I'm not finding good examples of the implementation ( or probably failing to understand).
After the user (not logged in) types his username to a form, Django would generate a unique URL based of this data (encoded in URL?) for the user that can be accessed once and within 5 minutes. Based on that URL (after clicking it) the data (username) would be decoded and ready for use in this one-time view.
Simple scenario if needed: user nimda fills the form and then is redirected (for example) to a view that shows the generated URL. Then nimda clicks the generated URL and a view is shown with the data he or she typed into the form
If you don't need that url you could save data to the session and send the user to a specific url.
The view connected to the url generates content depending on the (anonymous) users session. The user can see the content as long as you sessions last or you implement a time stamp an check this before delivering content.
If you need the url:
Build a model connected with the sessions with url and a time stamp.
Configure the urls.py for the url-model like
url(r'^dataUrl/(?P[0-9]+)/$', PostDelete.as_view()),
Assign the user session and the entered data (saved to the session) with
the url-model.
When delivering the content check for the random-url-part, and the timestamp and deliver the date (or not ;) )
You can access the session in a cvb's like this:
class YourClassName(TemplateView):
template_name = ""
def get_context_data(self, **kwargs):
context = super(YourClassName , self).get_context_data(**kwargs)
DataYouNeed = self.request.session["SessionVariableOfTheUser"]
userDAta = self.request.user #if this is usefull `
or in a createView:
class URLCreate(CreateView):
model = randomUrl
template_name = "entryCreate.html"
success_url = "../xyz/"
form_class = UrlCreateForm
# if you like to change the success-url
def get_success_url(self):
#print dir(self.object.instance)
#print self.object.instance.id
url = "../bringMeTo/%s" % self.object.instance.id
return url
def form_valid(self,form):
form.instance.user = self.request.user
self.request.session["formData"]= form.instance
return super(URLCreate, self).form_valid(form)
pass
This is not a ready solution! Just an inspiration for a start.

Django: How do I access post data and match with a criteria

I need some guidance on best practice implementation of the following.
I have a scenario where I am building an app, but if it matches a certain "category" or "locale" and want to redirect it to a page in between else just go the normal route.
Here is my simple views.py
if form.is_valid():
...
kwargs = {'project_id':project_id, 'categories':request.POST['categories'], 'locale':request.POST['locale']}
process_se(request, **kwargs)
return HttpResponseRedirect(obj.next_url)
Here is what I have in my models.py file but it seems to be very inconsistent.
Is there a better way to handle this request?
def process_se(self, request, **kwargs):
if "All" or "Sweden" in kwargs['locale']:
if "Technology" or "Internet" in kwargs['categories']:
next_url = request.build_absolute_uri(reverse('project_new_se', kwargs={'project_id': self.id}))
else:
next_url = request.build_absolute_uri(reverse('project_new_step2', kwargs={'project_id': self.id}))
self.next_url = next_url
UPDATES:
I am using forms.ModelForm, categories and locales are ManyToManyField's
I have simulated a for in the shell and still seem to get no result
Here is the cleaned_data output
f.cleaned_data
{'locale': [<Locale: Sweden>, <Locale: All>], 'categories': [<Category: Technology>, <Category: Internet>]}
Although running this for fields in the form seem to render perfectly fine based on your solution
I originally proposed putting this code in the form class, but ApPeL revised the question to point out that locale and categories are many-to-many fields on the model. So now I suggest putting a method like this in your model:
def requires_swedish_setup(self):
"""
Return True if this project requires extra Swedish setup.
"""
return (self.locale.filter(name__in = ('All', 'Sweden')).exists())
and self.categories.filter(name__in = ('Technology', 'Internet')).exists())
and then implementing your view like this:
if form.is_valid():
project = form.save()
next = 'project_new_step2'
if project.requires_swedish_setup():
next = 'project_new_se'
next_url = reverse(next, kwargs={'project_id': project.id})
return HttpResponseRedirect(next_url)
Some notes:
I'm assuming that Locale and Category objects have name fields (if not, use whatever field contains the name you are testing).
It's not a good idea to read form data out of request.POST (widgets haven't had a chance to run, and it hasn't been validated): it's better to use form.cleaned_data.
You don't need to call request.build_absolute_uri in this case: it's fine to feed the result of reverse directly to HttpResponseRedirect.
"All" or "Sweden" in kwargs['locale'] is probably not what you mean: it parses like "All" or ("Sweden" in kwargs['locale']) and so is always true.

Categories