Pass slug or id on GET request - python

I'm trying to test an API view for my Django project:
BOOK_URL = reverse('api:book') // '/api/book/'
book_id = 1
res = APIClient().get(f'BOOK_URL${book_id}/')
This works, but as you can see I need to interpolate the book_id into the string. Is there a way I can send a request without interpolating?
I tried:
res = APIClient().get(BOOK_URL, data={'book_id': book_id})
This is my views.py
class BookView(APIView):
def get(self, request, book_id):
book = get_object_or_404(
Book.objects.all(),
id=book_id
)
return book

The best you can do (and you should do at least) is to use the reverse (django.url.reverse) to get the URL endpoint for the detail URL from view name and URL keyword arguments (like you're doing for the list URL).
For example:
url = reverse('api:book', kwargs={'book_id': book_id})
Assuming the URL keyword argument is book_id.
The default keyword argument is pk (takes the value of viewset's lookup_field if you don't set lookup_url_kwarg); so for pk this would be:
url = reverse('api:book', kwargs={'pk': book_id})

Related

want to filter model objects by email, however filtering is not working in Django REST api

I have my API in Django REST Framework:
Here is my models.py:
class myModel(models.Model):
user_email = models.CharField(max_length= 200, null= False)
Here is my views.py:
class GetItemsByEmail(generics.ListAPIView):
def get_queryset(self):
email_items = self.request.query_params.get("user_email")
if(email_items is not None):
itemsReturned = myModel.objects.all().filter(user_email = email_items)
return Response(data= itemsReturned)
Here is my urls.py:
url_patterns = [
path('users/account=<str:id>/items', GetItemsByEmail.as_view()),
]
My Question:
I am getting an empty list, getting nothing from making an API call to the above endpoint.
I want to get all the items in the database associated with a particular email, but the filter is not working ?
What is the reason behind that ?
You defined the parameter in the URL, so this is an URL parameter. request.query_params is however not determined by the path, but by the query string [wiki].
You obtain URL parameters through self.kwargs, so:
class GetItemsByEmail(generics.ListAPIView):
def get_queryset(self):
# use self.kwargs &downarrow;
email_items = self.kwargs.get('user_email')
if email_items is not None:
return myModel.objects.filter(user_email=email_items)
else:
# return some queryset
pass
Your urls.py should be updated to work with user_email, not id:
url_patterns = [
path('users/account=<str:user_email>/items', GetItemsByEmail.as_view()),
]
While it is not impossible, it is not very common to have an equal sign in the URL, nor to include an email address, these are typically done through the query string or in case of non-GET requests in the payload of the request or the headers.

django how to get request object (url param) in class based view

I have a class based view which has a query set like below:
def get_queryset(self):
queryset = Article.objects.all()
return queryset
If I pass an article id as a URL parameter like this:
<url>/stories/?articleid=1000
Then how can I get this value in the get_queryset function so that I can use it to filter? something like below:
def get_queryset(self):
articleId = #get the article_id from URL. How to do this?
queryset = Article.objects.filter(article_id=articleId)
return queryset
Any help is appreciated.
In this case, you can get it from self.request.GET["articleid'].
Note however this is not best practice in Django; you should write a URL pattern that includes the id directly, so that your URL would be /stories/100/.

Django function doesn't return HTML page

I'm adding pagination on my website. This is my function:
views.py
def ProductList(request, category_slug=None, page_number=1):
content = {}
category = None
categories = Category.objects.all()
products = Product.objects.filter(available=True)
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
products = products.filter(category=category)
current_page = Paginator(products, 2)
content['category'] = category
content['categories'] = categories
content['products'] = current_page.page(page_number)
return render(request, 'product/list.html', content)
urls.py
urlpatterns = [
url(r'^$', views.ProductList, name='ProductList'),
url(r'^page/(\d+)/$', views.ProductList, name='ProductList'),
url(r'^(?P<category_slug>[-\w]+)/$', views.ProductList, name='ProductListByCategory'),
url(r'^(?P<id>\d+)/(?P<slug>[-\w]+)/$', views.ProductDetail, name='ProductDetail'),
]
But every time I'm trying to get next page I see this error:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/page/2/
Raised by: shop.views.ProductList
I can't really understand what I'm doing wrong. Thank you.
You haven't given a name to the group that captures the page number in your regex. So Django passes it to the view as a positional argument, not a keyword argument; and since the first positional argument after request is category_slug, that is the variable the number will be assigned to.
To fix this, use a named argument, like you do for id later:
url(r'^page/(?P<page_number>\d+)/$', views.ProductList, name='ProductList'),
Note, though, page number is usually passed as a querystring parameter, rather than in the URL path itself.

Django: how to inject data when overriding get_queryset()?

Very begginer with the Django class based view.
I had a ListView that worked well but displayed all the objects. I wanted to filter this, and here what I did, following some examples found:
models.py:
class FolderElement(TimeStampedModel):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
class FolderMedia(TimeStampedModel):
folder_element = models.ForeignKey(FolderElement)
file = models.FileField(upload_to=generate_filepath_folder)
slug = models.SlugField(max_length=50, blank=True)
views.py:
class FolderMediaListView(ListView):
model = FolderMedia
template_name = "book.html"
def get_queryset(self):
self.folder_element = get_object_or_404(FolderElement,
pk=self.kwargs['pk'])
return FolderMedia.filter(folder_element=self.folder_element)
def render_to_response(self, context, **response_kwargs):
files = [ serialize(p) for p in self.get_queryset() ]
data = {'files': files}
response = JSONResponse(data, mimetype=response_mimetype(self.request))
response['Content-Disposition'] = 'inline; filename=files.json'
return response
But now that I overrided the get_queryset() method, I don't understand how I'm supposed to inject the pkparameter to the view sothat the filter works. Currently, using pdb, I can see that self.kwargs equals {} into the get_queryset() method.
Thanks.
The keyword arguments (kwargs) that the Django URL dispatcher passes to the view comes from the following:
Captured parameters in the URL expression
Additional arguments specified in the URL definition
All of them in urls.py.
So, for example, in order to get an ID form the URL in a form: /folder/id/:
url(r'folder/(?P<pk>\d+)/', FolderMediaListView.as_view)
Or if the id is constant (more rarely), you can pass it as an additional argument:
url(r'folder/', FolderMediaListView.as_view, {'pk': 1})
More information on the subject in the Django documentation.
You need to supply it in the URL. For example:
url(r'folder/(?P<id>\d+)/media', FolderMediaListView.as_view, name='folder_media_list')

how to set cookie in class based generic view

newbies to django1.6
i want to set cookie in class based generic view (Listview)
models.py
class Designation(Models.model):
title = models.CharField(max_length=50)
description = models.CharField(max_length=10000, blank=True)
views.py
class DesignationList(ListVew):
def get_queryset(self):
"""
will get 'sort_by' parameter from request,
based on that objects list is return to template
"""
col_nm = self.request.GET.get('sort_by', None)
if col_nm:
if cookie['sort_on'] == col_nm:
objects=Designation.objects.all().order_by(col_nm).reverse()
else:
cookie['sort_on'] = col_nm
objects=Designation.objects.all().order_by(col_nm)
else:
objects = Designation.objects.all().order_by('title')
//set cookie['sort_on']='title'
return objects
template
in template im iterating over objects
so initially objects display in sort_by 'title' desc.
"this values is i want to set in cookie".
in template, if user click over title,it will check in cookie
cookie['sort_on']='title'
then all objects are in asce order
if user click over description,then cookie value is replaced
cookie['sort_on']='description' and objects are in desc order..
soo,how to set cookie which i can use in whole ListView class.. ?
Thnx in advance..
In order to set/delete cookies you have to have access to the "response" object. To do so, in a class-based view, you can override "render_to_response".
Example:
class DesignationList(ListVew):
def render_to_response(self, context, **response_kwargs):
response = super(LoginView, self).render_to_response(context, **response_kwargs)
response.set_cookie('sort_on', 'title')
return response
Unless you have a very good reason, you shouldn't be using cookies, but the session framework. You can access that inside your methods with self.request.session, and it acts like a dictionary.
if col_nm:
if self.request.session.get('sort_on') == col_nm:
objects=Designation.objects.all().order_by(col_nm).reverse()
else:
self.request.session['sort_on'] = col_nm
objects=Designation.objects.all().order_by(col_nm)
etc.

Categories

Resources