Django: same method different url - django

My url looks like:
/api/v1/files/
/api/v1/files/100
Is it a good practice to use the same function to match them? just like the following:
class FileView(APIView):
parser_classes = (MultiPartParser,)
permission_classes = (IsAuthenticated,)
#method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(FileView, self).dispatch(request, *args, **kwargs)
def post(self, request, pk = None):
if pk is not None:
Do something
else:
do something
How to use different functions in Class-based views?
Thanks

I think having separate methods is cleaner than a single method that branches based on the pk. It's easier to understand which logic goes where by just looking at the view's methods rather than having to follow the (albeit simple) control flow.
My first recommendation would be to check out the viewsets that Django Rest Framework provides and look at performing your logic within the given methods it provides. This seems like it would best fit your use case.
Another option would be to look DRF's generic views which are based off these mixins. These allow more control and customization than the viewsets and are sometimes a better option if you don't need all of the functionality provided by the viewsets.

Related

How to re use the code from a class based view - Django Rest Framework

I'm new to Django/Django rest framework class-based view. If it is a repeated question kindly excuse.
Consider I have a class-based views like this.
class UserBucket(APIView):
def get(self, request):
...
...
return Response(some_data)
def put(self, request):
...
...
return Response(some_data)
class FilterView(APIView):
def get(self, request):
data_to_filter = request.query_params.get('filterData')
# filter logic goes here
...
...
return Response(filtred_data)
If I want to use this FilterView code in the UserBucket's put method so that I can maintain DRY principle how can I achieve it?
What I really want to do here is that from UserBucket put method I want to call the FilterView's get method with few arguments and get back the result.
Try using Generic views with Mixins or you can dive in their code to learn how to implement like that
https://www.django-rest-framework.org/api-guide/generic-views/#mixins
https://github.com/encode/django-rest-framework/blob/master/rest_framework/viewsets.py

get_object() that depends on `request` in UpdateView

I am writing a class-based view to allow users to edit their profile. Since I want the users to access this view with a URL of the type my_profile/edit/ rather than something like profile/<int:pk>/edit/, using a view based on UpdateView is quite cumbersome since getting the user profile object requires to access the request object, and get_object does not directly have access to it.
My two questions:
Shall I use UpdateView in this case?
If so, what would be the best way to override get_object(self, queryset=None)? My best attempt so far is the following:
class EditProfileView(UpdateView):
model = UserProfile
_request = None
def get_object(self, queryset=None):
return get_user_profile(self._request)
def dispatch(self, request, *args, **kwargs): # can also override setup() in newer Django versions
self._request = request
return super().dispatch(request, *args, **kwargs)
This looks clean enough to me except that if one day the Django framework decides that get_object should be called early in the workflow of the view generation, this piece of code could break.
You don't need to do this. All class-based views make the request available as self.request.
Your entire code should just be:
class EditProfileView(UpdateView):
model = UserProfile
def get_object(self, queryset=None):
return get_user_profile(self.request)
Note, even if it didn't, you still wouldn't need to define _request at class level. That's just not necessary in Python.
Also, I don't know what your get_user_profile function does but it can probably be replaced with just self.request.user.profile.

django 405 method not allowed

The error occurs when I request via post method.
views.py
class ConceptForkView(ConceptBaseView, mixins.CreateModelMixin):
print 'oclapi ConceptForkView111'
def dispatch(self, request, *args, **kwargs):
print 'oclapi ConceptForkView dispatch'
return super(ConceptForkView, self).dispatch(request, *args, **kwargs)
def post(self, request):
print 'oclapi ConceptForkView post'
urls.py
url(r'^forking/$', ConceptForkView.as_view(), name='concept-forking'),
ConceptBaseView
class ConceptBaseView(ChildResourceMixin):
lookup_field = 'concept'
pk_field = 'mnemonic'
model = Concept
permission_classes = (CanViewParentDictionary,)
child_list_attribute = 'concepts'
The command print 'oclapi ConceptForkView111' can run, but the method dispatch and post don't run. What is the reason?
I have searched many solutions, but they don't work to me. How can I solve this problem? Thank you.
Note that mixin is not a view. You probably have to inherit from View also. Mixins are usually classes that extend functionality and are not standalone. Class inheriting only from mixins probably won't work properly unless one of these mixins is not mixin in fact.
See: rest framework documentation. There is CreateAPIView which inherits not only from CreateModelMixin but also from GenericAPIView (and you probably should inherit it too). As we can read about GenericAPIView:
This class extends REST framework's APIView class, adding commonly required behavior for standard list and detail views.
So this "commonly required behavior" is important for your class to behave like view.
try using
def create(request, *args, **kwargs)
...
method instead of
def post(self, request):
...
CreateModelMixin uses create method rather than post method

Django/Python: How to write Create, List, Update and Delete in a single View or a generic view?

I am trying to write a view in which a post can be created and in the same page, the object_list will be displayed. And even an object can be updated and deleted.
Country Capital
India Delhi UPDATE DELETE
USA Washington UPDATE DELETE
----- ------
I would appreciate helping me in achieve this or suggesting a similar type of question.
What you're looking for are Mixins.
Try creating a detail view class with the following parameters:
mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView
For example:
class ObjectDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):
queryset = Object.objects.all()
As has proposed by Daniel, if you like DRF, ViewSets are also a decent alternative. However, they're not exactly succinct so I generally avoid them when possible.
Something like a ModelViewSet, however, is extremely clear-cut and the approach I generally choose.
Here's an example:
class ObjectViewSet(viewsets.ModelViewSet):
queryset = Object.objects.all()
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
Beautiful, isn't it?
For more details, see the DRF tutorial: http://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/
You are mixing view and template. View handle requests and template show content and links.
You will have ListView, which will contain list of posts. In template you add forms for update, form for create and forms for delete. Each form will have attribute action with link to proper view. So update forms will have link to url with UpdateView, create forms to CreateView, and delete to DeleteView. In each form you set redirect back to ListView. This way if you want to use only Django.
OR
If you really want to everything handle on one page without refreshing and redirecting. You can use ajax and django-rest-framework and its viewset. In viewset you can handle lists, create, update, push, detail, in one class.
Viewset:
class UserViewSet(viewsets.ViewSet):
"""
Example empty viewset demonstrating the standard
actions that will be handled by a router class.
If you're using format suffixes, make sure to also include
the `format=None` keyword argument for each action.
"""
def list(self, request):
pass
def create(self, request):
pass
def retrieve(self, request, pk=None):
pass
def update(self, request, pk=None):
pass
def partial_update(self, request, pk=None):
pass
def destroy(self, request, pk=None):
pass

how to use commit_manually decorator in a Django class based view

is it possible to use the decorator commit_manually in a Django class based view?
The same way you use any other decorator in a class based view.
I personally like decorating the dispatch method on the class view:
class ManualCommitView(SomeView):
#method_decorator(commit_manually)
def dispatch(self, *args, **kwargs):
return super(ManualCommitView, self).dispatch(*args, **kwargs)
but that's only worth if you plan on reusing the view, otherwise it's easier to just decorate the view in the URLconf.