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')
Related
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 ↓
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.
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})
I am implementing DRF's Pagination over my existing web service (RESTful API). Now I learned from the docs of DRF Pagination that pagination is authomatically applied to ListCreateAPIView , only need to add some of the lines in settings.py file.
So I did the changes according to the documentation and for my webservice I wanted my queryset to be dynamic.
Below are the changes done:
urls.py
url(r'^users/(?P<pk>[0-9]+)/workouts/get/$',
ListCreateAPIView.as_view(WorkoutList.get_queryset(), serializer_class=WorkoutSerializer), name='list'),
views.py
class WorkoutList(generics.ListCreateAPIView):
queryset = Workout.objects.all()
serializer_class = WorkoutSerializer
permission_classes = (UserPermissions,)
def get_queryset(self):
workout_instance = WorkoutList()
workout_instance.get_queryset()
query_params = self.request.QUERY_PARAMS.dict()
if 'date' in query_params and 'exclude_app_install_time' in query_params:
query_set = Workout.objects.filter(created__contains=date).exclude(
app_install_time=query_params['exclude_app_install_time'])
else:
query_set = {}
return query_set
def list(self, request, *args, **kwargs):
workouts = self.get_queryset()
serializer = WorkoutSerializer(workouts, many=True)
return Response(serializer.data)
PS : I have stackoverflowed (pun intented) the problem but couldn't find the right solution(s).
Also I want to implement OffsetLimitPagination in the DRF. A small example link will be helpful
You're doing a couple of very strange things here.
If you subclass a view, you should use that subclass in the urls, not a strange mash-up of the original class and a method from the subclass. So:
url(r'^users/(?P<pk>[0-9]+)/workouts/get/$',
WorkoutList.as_view(serializer_class=WorkoutSerializer), name='list'),
Once you've fixed that, you'll get into an infinite recursion inside your get_queryset method. Again, when you subclass, if you want to call the original implementation you use super; you don't initialize another instance of the current class and try to call that method, because it'll be the same method.
def get_queryset(self):
query_set = super(WorkoutList, self).get_queryset()
Edit I guess the pagination doesn't work because you are starting from a blank Workout query rather than using the returned value from the super call. So you should do:
def get_queryset(self):
query_set = super(WorkoutList, self).get_queryset()
query_params = self.request.QUERY_PARAMS.dict()
if 'date' in query_params and 'exclude_app_install_time' in query_params:
query_set = query_set.filter(created__contains=date).exclude(
app_install_time=query_params['exclude_app_install_time'])
return query_set
I managed to get data from the tables MemberDeclareRecept and Member with the following config files. Here I am looking for the MemberDeclareRecept.pk. But how can I get all the data if I search the Member.CoId instead?
The MemberSearchByCode view gives all the members in the table but I can't get the specific member.
Here are my models
class Member(models.Model):
Name = models.CharField(max_length=40,null=True)
FirstName = models.CharField(max_length=40,null=True)
DateBirth = models.DateField(,null=True)
CoId = models.CharField(max_length=6,null=True)
class MemberDeclareRecept(models.Model):
SyMember=models.ForeignKey(Member,verbose_name='Name member ',null=True,related_name='Member')
DateDeclareRecept=models.DateField(('Date received',null=True)
And the serializers that are being used
class MemberDeclareSerializer(serializers.ModelSerializer):
member = serializers.StringRelatedField(read_only=True)
SyRecept=serializers.StringRelatedField(read_only=True)
class Meta:
model = MemberDeclareRecept
fields=('id','member','SyRecept')
And the views that I am currently using
class MemberDeclareDetail(generics.ListCreateAPIView):
queryset=MemberDeclareRecep.objects.all()
serializer_class =MemberDeclareSerializer
def get_object(self,pk):
try:
return self.queryset.get(pk=pk)
except MemberDeclareRecep.DoesNotExist:
raise Http404
def get(self, request, pk,format=None):
entries = self.get_object(pk)
serializer = MemberDeclareSerializer(entries)
return Response(serializer.data)
class MemberSearchByCode(generics.ListAPIView):
serializer_class =MemberSerializer
def get_queryset(self):
member=self.request.QUERY_PARAMS.get(Co_id',None)
if membre is not None:
queryset = queryset.filter(member__Name=member
return queryset
It appears as though you've found an answer, based on the comment, and it's included below.
class MemberSearch(generics.ListAPIView):
serializer_class=MemberDeclareSerializer
def get_queryset(self):
member = self.kwargs['Co_id']
return member_declare_recept.objects.filter(member__Co_id=member)
It is important to note that this is not filtering the queryset based on query parameters, this is filtering it based on parameters present in the url. If you were filtering it based on query parameters, which is useful if you will need to get a list of all objects at once, the url that you would be using would be like
/api/members/?company=[co_id]
Which would make the company id optional. In your case though, the id is being embedded within the url itself. This is typically referred to as hierarchal urls, and it's generally not recommended, but your urls end up like
/api/company/[co_id]/members
Which is preferable for some, and even required in certain cases.
Now, if you wanted to use the query parameter instead of the url parameter for filtering, only a slight change would be required in your code.
class MemberSearch(generics.ListAPIView):
serializer_class=MemberDeclareSerializer
def get_queryset(self):
company_id = self.request.query_parameters.get('company', None)
if not company_id:
return member_declare_recept.objects.all()
return member_declare_recept.objects.filter(member__Co_id=company_id)
This has the additional advantage of also being support directly through django-filter and the DjangoFilterBackend.
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.