How can I get the lenth of a session in django views - django

I am using a code for my wish list . I need the no of products in the wishlist to show there on my site .I tried various methods but I Think session will only do this .Can some help please .
How can I do so .
#never_cache
def wishlist(request, template="shop/wishlist.html"):
"""
Display the wishlist and handle removing items from the wishlist and
adding them to the cart.
"""
skus = request.wishlist
error = None
if request.method == "POST":
to_cart = request.POST.get("add_cart")
add_product_form = AddProductForm(request.POST or None,
to_cart=to_cart,request=request)
if to_cart:
if add_product_form.is_valid():
request.cart.add_item(add_product_form.variation, 1,request)
recalculate_discount(request)
message = _("Item added to cart")
url = "shop_cart"
else:
error = add_product_form.errors.values()[0]
else:
message = _("Item removed from wishlist")
url = "shop_wishlist"
sku = request.POST.get("sku")
if sku in skus:
skus.remove(sku)
if not error:
info(request, message)
response = redirect(url)
set_cookie(response, "wishlist", ",".join(skus))
return response
# Remove skus from the cookie that no longer exist.
published_products = Product.objects.published(for_user=request.user)
f = {"product__in": published_products, "sku__in": skus}
wishlist = ProductVariation.objects.filter(**f).select_related(depth=1)
wishlist = sorted(wishlist, key=lambda v: skus.index(v.sku))
context = {"wishlist_items": wishlist, "error": error}
response = render(request, template, context)
if len(wishlist) < len(skus):
skus = [variation.sku for variation in wishlist]
set_cookie(response, "wishlist", ",".join(skus))
return response

Session != Cookies. The session is managed by the server on the backend, cookies are sent to the users browser. Django uses a single cookie to help track sessions but you are simply using cookies in this instance.
The session framework lets you store and retrieve arbitrary data on a per-site-visitor basis. It stores data on the server side and abstracts the sending and receiving of cookies. Cookies contain a session ID – not the data itself (unless you’re using the cookie based backend).
It's difficult to tell what you want, but if you simply want to get a count of the number of items you are saving in the cookie, you simply have to count your skus and put it in the context being sent to the template:
if len(wishlist) < len(skus):
skus = [variation.sku for variation in wishlist]
set_cookie(response, "wishlist", ",".join(skus))
context = {"wishlist_items": wishlist, "error": error, "wishlist_length":len(wishlist)}
return render(request, template, context)
and use:
{{ wishlist_length }}
in your template

Related

How to perform the delete method in drf django

How to perform the delete request in Django drf? How will I pass the params for the request?
Kindly help with the solution. I am very new in this drf-django-python programming.
class DeleteView(APIView):
def delete(self, request,format=None):
id = request.POST['book_id']
email = request.POST['email']
book = models.Book.objects.filter(book_id=id)
book_uploader = serializers.BookSerializer(book[0]).data['uploader']['email']
logged_in = request.user
print(log)
if book_uploader == logged_in :
books = models.BookUserRelationship.objects.filter(book= id, user__email=email)
books.delete()
return Response("Successfully removed", status=status.HTTP_204_NO_CONTENT)
else :
return Response("Not able to remove")
In comments you noticed that parameters will be embedded in url but you are trying to get values from POST dict.
If your url is something like
/books/id/email/
You should use request.kwargs dict like request.kwargs.get('email')
But if your url is like
/books/id/?email=someemail#google.com
id would be in request.kwargs but email in request.query_params
Notice that every url variable is in the request.query_params dict.
IMPORTANT
If you have ID url param without named group, viewset would not be able to get this from request.kwargs by name

Django pagination while objects are being added

I've got a website that shows photos that are always being added and people are seeing duplicates between pages on the home page (last added photos)
I'm not entirely sure how to approach this problem but this is basically whats happening:
Home page displays latest 20 photos [0:20]
User scrolls (meanwhile photos are being added to the db
User loads next page (through ajax)
Page displays photos [20:40]
User sees duplicate photos because the photos added to the top of the list pushed them down into the next page
What is the best way to solve this problem? I think I need to somehow cache the queryset on the users session maybe? I don't know much about caches really so a step-by-step explanation would be invaluable
here is the function that gets a new page of images:
def get_images_paginated(query, origins, page_num):
args = None
queryset = Image.objects.all().exclude(hidden=True).exclude(tags__isnull=True)
per_page = 20
page_num = int(page_num)
if origins:
origins = [Q(origin=origin) for origin in origins]
args = reduce(operator.or_, origins)
queryset = queryset.filter(args)
if query:
images = watson.filter(queryset, query)
else:
images = watson.filter(queryset, query).order_by('-id')
amount = images.count()
images = images.prefetch_related('tags')[(per_page*page_num)-per_page:per_page*page_num]
return images, amount
the view that uses the function:
def get_images_ajax(request):
if not request.is_ajax():
return render(request, 'home.html')
query = request.POST.get('query')
origins = request.POST.getlist('origin')
page_num = request.POST.get('page')
images, amount = get_images_paginated(query, origins, page_num)
pages = int(math.ceil(amount / 20))
if int(page_num) >= pages:
last_page = True;
else:
last_page = False;
context = {
'images':images,
'last_page':last_page,
}
return render(request, '_images.html', context)
One approach you could take is to send the oldest ID that the client currently has (i.e., the ID of the last item in the list currently) in the AJAX request, and then make sure you only query older IDs.
So get_images_paginated is modified as follows:
def get_images_paginated(query, origins, page_num, last_id=None):
args = None
queryset = Image.objects.all().exclude(hidden=True).exclude(tags__isnull=True)
if last_id is not None:
queryset = queryset.filter(id__lt=last_id)
...
You would need to send the last ID in your AJAX request, and pass this from your view function to get_images_paginated:
def get_images_ajax(request):
if not request.is_ajax():
return render(request, 'home.html')
query = request.POST.get('query')
origins = request.POST.getlist('origin')
page_num = request.POST.get('page')
# Get last ID. Note you probably need to do some type casting here.
last_id = request.POST.get('last_id', None)
images, amount = get_images_paginated(query, origins, page_num, last_id)
...
As #doniyor says you should use Django's built in pagination in conjunction with this logic.

Django backend receives one less param than sent by frontend

I have a small web app with AngularJS front-end and Django ReST in the back. There's a strange hitch going on when I make POST request to the web service: the browser console clearly shows 3 parameters being sent, but the backend logging reports only 2 params received. The result is that the server throws a code 500 error due to a bad database lookup.
Here's the code:
Client
var b = newQuesForm.username.value;
$http.post('/myapp/questions/new', {username:b,title:q.title,description:q.description}).
success(function(data, status, headers, config) {
$http.get('/myapp/questions').success(function(data){
$scope.questions = data;
q = null;
$scope.newQuesForm.$setPristine();
}).error(function(data, status, headers, config) {
console.log(headers+data);
});
}).
error(function(data, status, headers, config) {
console.log(headers+data);
});
Both my manual logging and the dev console show a string like:
{"username":"admin","description":"What's your name?","title":"question 1"}
Server
class CreateQuestionSerializer(serializers.Serializer):
author = UserSerializer(required=False)
title = serializers.CharField(max_length=150)
description = serializers.CharField(max_length=350)
def create(self, data):
q= Question()
d = data
q.title = d.get('title')
q.description = d.get("description")
q.author = User.objects.get(username=d.get('username'))
q.save()
return q
Server-side logging shows the username parameter never succeeds in making the trip, and thus I end up with code 500 and error message:
User matching query does not exist. (No user with id=none)
What's causing some of the data to get lost?
So it turns out the problem was really with the serialization of fields, as #nikhiln began to point out. I followed his lead to refactor the code, moving the create() method to api.py, rather than serializers.py, and stopped relying altogether on the client-side data for the user's identity, something that was a bit silly in the first place (passing User to a hidden input in the view, and then harvesting the username from there and passing it back to the server in the AJAX params). Here's the new code, that works perfectly:
class QuestionCreate(generics.CreateAPIView):
model = Question
serializer_class = CreateQuestionSerializer
def create(self, request,*args,**kwargs):
q= Question()
d = request.data
q.title = d.get('title')
q.description = d.get("description")
q.author = request.user
q.save()
if q.pk:
return Response({'id':q.pk,'author':q.author.username}, status=status.HTTP_201_CREATED)
return Response({'error':'record not created'}, status=status.HTTP_400_BAD_REQUEST)
So here, I do it the right way: pull the User from the request param directly in the backend.

Not getting notified on return/return_cancel using Django paypal

Am using django paypal for my e-commerce site and payments are all working correctly,but once payment is done it is not redirected back to my site.Am using paypal IPN in my localhost.is it because am running in my local machine,Following is the code for sending data to paypal.
def checkout(request,name):
product=Products.objects.get(name=name)
print "producttttttttttttttttttttt",product
# What you want the button to do.
paypal_dict = {
"business": settings.PAYPAL_RECEIVER_EMAIL,
"amount": product.price,
"item_name": product.name,
"invoice": "unique-invoice-id",
"notify_url": "192.168.5.108:8000" + reverse('paypalipn'),
"return_url": "192.168.5.108:8000/payment-complete/",
"cancel_return": "192.168.5.108:8000",
}
form = PayPalPaymentsForm(initial=paypal_dict)
context = {"form": form}
return render_to_response("payment.html", context)
Following view is for getting data from paypal ipn:
def paypalipn(request,item_check_callable=None):
'''
django paypal view to store the IPN . the notify url excecutes this view.
'''
print "haaaaaaaaaaaaaaaaaaaaaaaaaaiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"
"""
PayPal IPN endpoint (notify_url).
Used by both PayPal Payments Pro and Payments Standard to confirm transactions.
https://www.paypal.com/it/home
PayPal IPN Simulator:
https://developer.paypal.com/cgi-bin/devscr?cmd=_ipn-link-session
"""
#TODO: Clean up code so that we don't need to set None here and have a lot
# of if checks just to determine if flag is set.
flag = None
ipn_obj = None
# Clean up the data as PayPal sends some weird values such as "N/A"
# Also, need to cope with custom encoding, which is stored in the body (!).
# Assuming the tolerate parsing of QueryDict and an ASCII-like encoding,
# such as windows-1252, latin1 or UTF8, the following will work:
encoding = request.POST.get('charset', None)
if encoding is None:
flag = "Invalid form - no charset passed, can't decode"
data = None
else:
try:
data = QueryDict(request.body, encoding=encoding)
except LookupError:
data = None
flag = "Invalid form - invalid charset"
if data is not None:
date_fields = ('time_created', 'payment_date', 'next_payment_date',
'subscr_date', 'subscr_effective')
for date_field in date_fields:
if data.get(date_field) == 'N/A':
del data[date_field]
form = PayPalIPNForm(data)
if form.is_valid():
try:
#When commit = False, object is returned without saving to DB.
ipn_obj = form.save(commit=False)
except Exception, e:
flag = "Exception while processing. (%s)" % e
else:
flag = "Invalid form. (%s)" % form.errors
if ipn_obj is None:
ipn_obj = PayPalIPN()
#Set query params and sender's IP address
ipn_obj.initialize(request)
if flag is not None:
#We save errors in the flag field
ipn_obj.set_flag(flag)
else:
# Secrets should only be used over SSL.
if request.is_secure() and 'secret' in request.GET:
ipn_obj.verify_secret(form, request.GET['secret'])
else:
ipn_obj.verify(item_check_callable)
ipn_obj.save()
return HttpResponse("OKAY")
Plese Help???
The issue happened because i was working on localhost,when i moved to development server it worked for me.The page was redirected back to my site.
I will quote this directly from django-paypal documentation:
If you are attempting to test this in development, using the PayPal sandbox, and your machine is behind a firewall/router and therefore is not publicly accessible on the internet (this will be the case for most developer machines), PayPal will not be able to post back to your view. You will need to use a tool like https://ngrok.com/ to make your machine publicly accessible, and ensure that you are sending PayPal your public URL, not localhost, in the notify_url, return and cancel_return fields.

The view companies.views.view didn't return an HttpResponse object

I am still learning and none of the other questions answer my question, why do I have to have an HTTP Response?
def view(request):
namesTickers = Company.objects.all().values('name', 'ticker')
names, tickers = [], []
for nameTicker in namesTickers:
names.append(nameTicker['name'])
tickers.append(nameTicker['ticker'])
nameTickerDict = dict(zip(names, tickers))
print nameTickerDict
if 'ticker' in request.POST and request.POST['ticker']:
q = request.POST['ticker']
context = {}
context['companies'] = json.dumps(nameTickerDict)
context['companyInfo'] = Company.objects.filter(ticker__icontains=q)
context['financial'] = Financials.objects.filter(ticker__icontains=q).order_by('-year')
return render( request, "companies/view.html",[context])
Because HTTP is a request/response mechanism. You get a request and you must respond to it. It doesn’t have to be a successful response, though. If you cannot respond meaningfully without a ticker, you may return an error page instead. Or, if you have a form where the user enters a ticker and submits that to your view, then you probably want to return the user back to the same form but with an error message. If that is the case, Django’s forms framework will help you.