I'm learning about the Django Rest Framework. And there are two concepts that from my point of view are almost the same, and they are used in different scenarios.
rest_framework mixins I think that they are used when we use viewsets.
And rest_framework generics are used with APIViews.
What is the difference between these two components?
The generics and mixin modules are indeed different, yet they are inter-related.
Django Rest Framework (DRF) separates ReSTful API / HTTP verb behaviour from Django model operations and organises a set of abstract/base classes for each. The ReSTful functionality is in APIView, GenericAPIView and ViewSetMixin. The Model related operations are implemented in the mixin module.
DRF then makes use of Python's multiple inheritance, and the "mixin" pattern, to combine these together into higher-level classes that are both useable and extensible.
The generic views and the concrete ModelViewSet both inherit from APIView in addition to composing functionality via the mixin classes.
Though not related to the question, the following observation about ViewSets may be helpful...
The following is the intro to ViewSets on the DRF site that might make things seem more complicated than they really are...
A ViewSet class is simply a type of class-based View, that does not provide any method handlers such as .get() or .post(), and instead provides actions such as .list() and .create().
The method handlers for a ViewSet are only bound to the corresponding actions at the point of finalizing the view, using the .as_view() method.
Rather than inheriting the ViewSet directly, in many cases, it will make the most sense to inherit a ModelViewSet and combine it with a DefaultRouter. The ModelViewSet obtains the method handlers via the various mixin classes, and the DefaultRouter provides the 'action' function mapping.
In combination, all the basic REST actions can be performed on a given Model, with very little code.
Related
I´m building an API with Django Rest Framework, and I’m wondering if it's enough to use only the ModelViewSet class to implement the CRUD. My worries is that it’s not enough for the frontend to consume and use the create, read, update and delete functionalities.
For a short answer, "yes".
But, I would suggest you to read the official docs from DRF.
ModelViewSet's docs
The ModelViewSet class inherits from GenericAPIView and includes implementations for various actions, by mixing in the behavior of the various mixin classes.
The actions provided by the ModelViewSet class are .list(), .retrieve(), .create(), .update(), .partial_update(), and .destroy().
GenericAPIView's docs
This class extends REST framework's APIView class, adding commonly required behavior for standard list and detail views.
Each of the concrete generic views provided is built by combining GenericAPIView, with one or more mixin classes.
--
There are also plenty of blogs explaining why and when to use these class.
Django Rest Framework ViewSets
--
Lastly, I'm new to the community just like you did. I'm not sure this kind of question would be allowed here or not. But, what I'm trying to say is..
Stop worrying, just go and try out yourself. I believe that people in the community would willing to help you out if you've stuck.
What are the differences between the APIView and ViewSets classes? I am following Django REST-framework official documentation. I find it lacking in examples.
Can you explain the above difference with a suitable example?
APIView is the most basic class that you usually override when defining your REST view. You usually define your methods like get, put, delete and others see: http://www.cdrf.co/3.5/rest_framework.views/APIView.html. With APIView you define your view and add it to your urls like so:
# in views.py
class MyAPIView(APIView):
... #here you put your logic check methods you can use
# in urls.py
url(r'^posts$', MyAPIView.as_view()), #List of all the posts
Because certain things like getting /post/4, deleting /post/4, getting all posts, updating posts, and creating new posts are so common DRF provides ViewSets.
Before you use ViewSets, let me tell you about Generic Classes. They things very well, but you need to provide the full API end point like I did with my MyAPIView view (again for more info check http://www.cdrf.co/ or http://www.django-rest-framework.org/). So you would have to define your own urls path.
But with ViewSets you create ViewSet that actually merges all the above described operations and also you don't need to define the url path you, instead you use a router that makes paths for you like this:
# views.py
class PostViewSet(ViewSet): # here you subclass ViewSet check methods you can override, you have also ModelViewSet,...
# urls.py
router = routers.DefaultRouter()
router.register(r'post', PostViewSet, base_name='Post')
APIView allow us to define functions that match standard HTTP methods like GET, POST, PUT, PATCH, etc.
Viewsets allow us to define functions that match to common API object actions like : LIST, CREATE, RETRIEVE, UPDATE, etc.
Viewsets are also used to write logic to perform standard database operations and to interface with a database back-end. And are usually used for existing database model to manage predefined objects.
The functions you add to the APIView are different than the functions you add to the ViewSet class.
APIView: you add functions for the particular HTTP method you want to support on your endpoint. Ex: GET, POST, PUT, PATCH, DELETE
ViewSet: you would add functions that represent actions that you'd perform on a typical API. Ex: LIST, CREATE, RETRIEVE, UPDATE
Viewsets and APIView both allow us to write logic for end point but Viewsets dont define functions which map to HTTP methods instead map to common API object actions
I'm learning Django REST Framework (http://tomchristie.github.io/rest-framework-2-docs/, we're still on version 2.4). Is it correct to define a class like this, for instance:
class UserView(generics.RetrieveUpdateDestroyAPIView,
generics.ListCreateAPIView,
viewsets.GenericViewSet):
# ... rest of class
In other words, is it correct or possible to use *ViewSet and *APIView mixins/classes together, or are they intended as two wholly separate concepts, not to be combined?
I don't think it is advisable to use both together. They were built for different purposes.
As per the docs,
ListCreateAPIView:
Used for read-write endpoints to represent a collection of model
instances.
Provides get and post method handlers.
Extends: GenericAPIView, ListModelMixin, CreateModelMixin
RetrieveUpdateDestroyAPIView:
Provides get, put, patch and delete method handlers.
Extends: GenericAPIView, RetrieveModelMixin, UpdateModelMixin,
DestroyModelMixin
GenericViewSet:
The GenericViewSet class inherits from GenericAPIView, and provides
the default set of get_object, get_queryset methods and other generic
view base behavior, but does not include any actions by default.
ModelViewSet:
The ModelViewSet class inherits from GenericAPIView and includes
implementations for various actions, by mixing in the behavior of the
various mixin classes.
The actions provided by the ModelViewSet class are .list(),
.retrieve(), .create(), .update(), and .destroy().
With ModelViewSet you can achieve all the CRUD operations that you intend to use with your above code snippet.
If you want a custom functionality i.e not all the method handlers, you can use generic views. But, if you want all the method handlers, then viewsets comes to your rescue. You can even browse through the rest framework code and see that mixins inherited in generic API views are a subset of mixins inherited in Viewsets.
Viewsets basically bundles those views together.
You can just do the following and achieve what you were intending to do in the first place:
class UserView(viewsets.ModelViewSet):
.....
In all versions of Django REST framework, the generic API views and ViewSet classes are distinctly separate, but the mixins can be shared across them. This is because the viewsets actually inherit from the generic classes in the first place.
As stated before, you can use the generic mixins though if you want to build a viewset with only a few supported methods, or if you want to override one of them on your own.
class UserView(mixins.CreateModelMixin, mixins.ListModelMixin,
mixins.RetrieveModelMixin, mixins.DestroyModelMixin,
mixins.UpdateModelMixin,
viewsets.GenericViewSet):
Don't forget that Django REST framework does provide a ModelViewSet and ReadOnlyModelViewSet base class that you can use as well.
I have discovered Django's generic class views now when I'm in the middle of my first Django project.
I didn't know that there are class based views or generic views.
I have made my own class views but now I'm thinking of refactoring. The only problem is I don't like these Django built-in views. I don't like putting stuff in the urls.py, my own views call sometimes each-other (they don't return a result, just add to the context)...
Anyway, I'm curios what others are doing? Are Django's built-in generic views actually used in real life?
mixins are a good way of using generic class based views.
here is a good comparison of the advantages and disadvantages of class based views
I'm working on an e-commerce framework for Django. The chief design goal is to provide the bare minimum functionality in terms of models and view, instead allowing the users of the library to extend or replace the components with their own.
The reasoning for this is that trying to develop a one-size-fits-all solution to e-commerce leads to overcomplicated code which is often far from optimal.
One approach to tackling this seems to be using inversion-of-control, either through Django's settings file or import hacks, but I've come up against a bit of a problem due to how Django registers its models.
The e-commerce framework provides a bunch of abstract models, as well as concrete versions in {app_label}/models.py. Views make use of Django's get_model(app_label,model) function to return the model class without having to hard-code the reference.
This approach has some problems:
Users have to mimic the structure of the framework's apps, ie the app_label and effectively replace our version of the app with their own
Because of the way the admin site works by looking for admin.py in each installed app, they have to mimic or explicitly import the framework's admin classes in order to use them. But by importing them, the register method gets called so they have to be unregistered if a user wants to customise them.
The user has to be extremely careful about how they import concrete models from the core framework. This is because Django's base model metaclass automatically registers a model with the app cache as soon as the class definition is read (ie upon __new__), and the first model registered with a specific label is the one you're stuck with. So you have to define all your override models BEFORE you import any of the core models. This means you end up with messy situations of having a bunch of imports at the bottom of your modules rather than the top.
My thinking is to go further down the inversion-of-control rabbit hole:
All references to core components (models, views, admin, etc) replaced with calls to an IoC container
For all the core (e-commerce framework) models, replace the use of Django's base model metaclass with one that doesn't automatically register the models, then have the container explicitly register them on startup.
My question:
Is there a better way to solve this problem? The goal is to make it easy to customise the framework and override functionality without having to learn lots of annoying tricks. The key seems to be with models and the admin site.
I appreciate that using an IoC container isn't a common pattern in the Django world, so I want to avoid it if possible, but it is seeming like the right solution.
Did you look at the code from other projects with a similar approach?
Not sure if this way covers your needs, but imo the code of django-shop is worth to look at.
This framework provides the basic logic, allowing you to provide custom logic where needed.
customize via models
eg see the productmodel.py
#==============================================================================
# Extensibility
#==============================================================================
PRODUCT_MODEL = getattr(settings, 'SHOP_PRODUCT_MODEL',
'shop.models.defaults.product.Product')
Product = load_class(PRODUCT_MODEL, 'SHOP_PRODUCT_MODEL')
customize via logic/urls
eg see the shop's simplevariation-plugin
It extends the cart-logic, so it hooks in via urlpattern:
(r'^shop/cart/', include(simplevariations_urls)),
(r'^shop/', include(shop_urls)),
and extends the views:
...
from shop.views.cart import CartDetails
class SimplevariationCartDetails(CartDetails):
"""Cart view that answers GET and POSTS request."""
...
The framework provides several points to hook-in, the simplevariation-plugin mentionned above additionally provides a cart-modifier:
SHOP_CART_MODIFIERS = [
...
'shop_simplevariations.cart_modifier.ProductOptionsModifier',
...
]
I worry that this explanation is not very understandable, it is difficult to briefly summarize this concept. But take a look at the django-shop project and some of its extensions: ecosystem