What is the right™ way to design DRF serializers that receive the following POSTed data to a List model:
{
list_name: "friends",
contacts: ["alice", "bob"]
}
And handles the creation of the nested Contact objects? Additionally, assume an extra step is needed to convert the names to capitalized (['Alice', 'Bob']).
You could use django-rest-framework-bulk which is linked from Django Rest Framework's documentation: http://www.django-rest-framework.org/topics/third-party-resources#views
'Implements generic view mixins as well as some common concrete generic views to allow to apply bulk operations via API requests.'
I'm not sure if it's the 'right™' way of doing it but the library is being actively maintained and it's 9 months old and seems to have a few contributors. Worth looking into.
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.
I am starting a web application in pure Django. However, in the future, there might be a requirement for REST api. If it happens, the most obvious choice will be Django REST framework.
Both the "old-fashioned" and REST parts share the models, however, the views are slightly different (permissions definitions, for example) and forms are replaced with serializers. Doing it the most obvious way would mean to duplicate the application logic several times, and thus a failure to follow DRY principle, and so the code becomes unmaintainable.
I got an idea to write all the logic into models (since they are shared), but in such case, there will be no use of permission mixins, generic views and the code would not be among the nicest ones.
Now I ran out of ideas. What is the best practice here?
I'd try to keep things simple as you're not sure about the future requirements for the API, and guessing can introduce extra complexity that may not even be needed when requirements will be clear.
Both Django forms and Rest Framework serializers already offer you a declarative approach that abstracts away the boilerplate code needed for basic stuff, which normally accounts for most of your code anyway.
For example, one of your Django form could look like this:
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['title', 'content']
And in the future the DRS serializer would be:
class ArticleSerializer(ModelSerializer):
class Meta:
model = Article
fields = ['title', 'content']
As you can see, if you try and stick to ModelForm and ModelSerializer, there won't be much duplication anyway. You can also simply store the fields list in a variable and just reuse that.
For more custom things, you can start by sharing logic into simple functions, for example:
def save_article_with_author(article_data, author_data):
# custom data manipulation before saving, consider that article_data will be a dictionary either if it comes from deserialized JSON (api) or POST data
# send email, whatever
This function can be shared between your form and serializer.
For everything related to data fetching, I'd try to use Model Managers as much as possible, defining custom querysets that can be resued e.g. for options by forms and serializers.
I tend to avoid writing any logic that doesn't directly read or write data into the model classes. I think that couples too much the business logic with the data layer. As an example, I never want to write any auth/permission checks into a save() method of a model, because that couples different layers too tightly.
As a rule of thumb, imagine this scenario: you add say permissions checks or the logic to send an email when a user is created overriding the save() method of your Article model.
Then, later on you're asked to write a simple manage command that batch-import users from a spreadsheet. At this point, what you did in your save() method really gets in the way, as you can freely access your data through your model without having to bother with permissions, emails and all of that.
Regarding the view layer and assuming you need to implement some shared auth/permission checks and you don't want to have separate views, you can use this approach:
https://www.django-rest-framework.org/topics/html-and-forms/
Blockquote
REST framework is suitable for returning both API style responses, and regular HTML pages. Additionally, serializers can be used as HTML forms and rendered in templates.
Here's some guidelines on how you could dynamically switch from HTML to JSON based to the request content type:
https://www.django-rest-framework.org/api-guide/renderers/#advanced-renderer-usage
This seems like a good option in your situation, I'd just write down a quick proof-of-concept before you go all in to see if you are not too limited for what you need to do.
How to prefer which one of generics and viewset to use?
in other words when should I use generics and when should I use viewset for building api.
I know that they do the same thing, but viewset has routers, so in what situation generics are better than viewset?
They are different, let's see.
DRF has two main systems for handling views:
APIView: This provides methods handler for http verbs: get, post, put, patch, and delete.
ViewSet: This is an abstraction over APIView, which provides actions as methods:
list: read only, returns multiple resources (http verb: get). Returns a list of dicts.
retrieve: read only, single resource (http verb: get, but will expect an id in the url). Returns a single dict.
create: creates a new resource (http verb: post)
update/partial_update: edits a resource (http verbs: put/patch)
destroy: removes a resource (http verb: delete)
Both can be used with normal django urls.
Because of the conventions established with the actions, the ViewSet has also the ability to be mapped into a router, which is really helpful.
Now, both of this Views, have shortcuts, these shortcuts give you a simple implementation ready to be used.
GenericAPIView: for APIView, this gives you shortcuts that map closely to your database models. Adds commonly required behavior for standard list and detail views. Gives you some attributes like, the serializer_class, also gives pagination_class, filter_backend, etc
GenericViewSet: There are many GenericViewSet, the most common being ModelViewSet. They inherit from GenericAPIView and have a full implementation of all of the actions: list, retrieve, destroy, updated, etc. Of course, you can also pick some of them, read the docs.
So, to answer your question: DRY, if you are doing something really simple, with a ModelViewSet should be enough, even redefining and calling super also is enough. For more complex cases, you can go for lower level classes.
Hope to have helped you!
My golden rule for this is to use generics whenever I have to override the default methods to accomplish different specifications from list and details views.
For instance, when you have different serializer classes for listing your resources and for retrieving a resource details by id I consider that using generics is a better option since probably these two endpoints' logic is going to evolve separately. Keep in mind is a good practice to maintain different logics decoupled.
When your endpoint is very simple and you don't need to customize logic between list/create and retrieve/update/delete operations you can use viewset, but yet having in mind it may be good to separate it in two views in case these operations' logic start growing in different paths.
I have a general algorithm design question. I am creating a Django app that will connect to an API, but I won't be storing these results (at least not at first). After I retrieve the data from the API I manipulate it accordingly and have already created a class with numerous methods to do this.
Should the programming logic for this be performed in the model or the view for the Django framework? Is one more sustainable than the other (e.g. in a few months I decide to store the information). Also, is it best to encapsulate my class in its own file, and them import into the model/view?
Thanks!
Rob
If you don't need to store data, don't use Djnago's built in models.
Write views and import your own modules/classes.
Bonus: If your views share a lot of logic (probably related to request/response handling), use class based views and write a common MyBaseView.
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