django: Why do we use a nested meta class inside modelSerializer? - django

I am new to python as well as to django and learning about serializers. I observed that While defining a serializer class it needs a nested meta class inside it. I am not good with this meta class concept, so i googled about it and found that metaclass is a class whose instances are classes. Even after reading that i am confused. Is the outer serializer class an instance of the inner meta class here? What is the need of using this meta class here?

Python's metaclasses and Django's Meta classes are different concepts.
What you found on google is talking about Python's metaclasses, a construct that the Django framework uses a lot, but not in its user-facing code. This blog post goes into explaining how Django uses metaclasses in the framework's code.
Django's Meta classes on the other hand, it's an internal class structure used in some of the framework frontmost elements: Models, Forms, Serializers, ModelAdmins, etc. Those classes describe the configuration of a certain element that are read on runtime, or migration-time, but are not strictly saved on the database, because they're not of the database concern. For example, the framework reads the Meta configuration of a model when it needs to know what is the preferred order of a QuerySet of such model if order is not specified. Forms will read what fields it must validate when it calls is_valid. Et cetera.

Related

Good Django design practice to add a REST api later following DRY

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.

Django Rest Framework -A concrete example of when you would use a serializer class vs a model serializer class

I am learning django rest framework, while I understand what a serializer does and when you would use it, I cannot fully seat the need for a serializer and a model serialzer class. Can one of you please give me a concrete real world example use case of both please?
Yes I have gone through the tutorial on DRF website several times and I still am experiencing fuzziness
There is an excellent example on the DRF tutorial and it would take too much to cover in an answer, but I would like to make some points.
First, the DRF documentation explains:
Our SnippetSerializer class is replicating a lot of information that's also contained in the Snippet model. It would be nice if we could keep our code a bit more concise.
In the same way that Django provides both Form classes and ModelForm classes, REST framework includes both Serializer classes, and ModelSerializer classes.
The Snippet model is the name of the model used in that example. So as the documentation says, rather than typing again the same fields from the model over to a Serializer, we can use a ModelSerializer as a shortcut, in a similar way that we would use a ModelForm over a simple Form.
But this leaves the question essentially as "ok, then why is there a simple Serializer class at all?", as you pointed out in your comment.
In the vast majority of cases where you have models and you need to serialize/deserialize relevant data (usually JSON but not limited to), then ModelSerializer is the way to go. Even if additional fields, related serializers or arbitrary logic is required, a ModelSerializer can be easily tweaked. Personally it has never occured to me with any of my projects that ModelSerializer is not suitable for data related to a model.
But there may be cases where you need to handle data that do not abide to a model. Such data would be POSTed to a DRF view and a Serializer would handle them. Such cases could be for example to send a mail message, to setup a Celery task, to add data to session, and many others that do not involve a model at all.

Is There a Good Way to Forbid Templates Accessing Related Managers Through Model Instances

I need an elegant way of disabling or authorizing related field traversal in Django templates.
Imagine following setup for models.py:
class Person(models.Model):
pass
class Secret(models.Model):
owner = models.ForeignKey(Person, related_name="secrets")
Now imagine this simple view that gives the template QuerySet of all Person instances in the system just so the template could put them in a list.
def show_people(request):
render_to_response("people.html", {people=Person.objects.all()})
Now my problem is that I would not provide the templates myself in this imaginary system and I don't fully trust those who make the templates. The show_people view gives the people.html template the secrets of the Person instances through the related_name="secrets". This example is quite silly but in reality I have model structures where template providers could access all kind of vulnerable data through related managers.
The obvious solution would be not to give models to templates but to convert them in to some more secure data objects. But that would be pain in my case because the system is already quite big and it's up and running.
I think a cool solution to this would be somehow preventing related field traversal in templates. Another solution would be to have such custom related managers that could have access to the request object and filter the initial query set according to the request.user.
A possible solution could be to use a custom model.Manager with your related models.
Set use_for_related_fields = True to force Django to use it instead of the plain manager. modify the manager to filter the data as needed.
also have a look at this:
Django: using managers for related object access (use_for_related_fields docs)
stackoverflow: use_for_related_fields howto, very good explanation here.

Django - Single model instance

I want to add a layout model to my website (a general settings file), and I want it to be available in the admin interface for configuration.
class Layout(...Model):
primary_header
logo_image
...
This structure shouldn't saved be in a table.
I am wondering if there is a built-in feature that can help me do this.
Thanks
My use case is a configurable layout of the website. Wordpress style. I would like to store that data in a concrete class, without having to implement the file /xml serialization myself.
What about an abstract model? It does not save in the database and is meant to be subclassed, but you are allowed to create instances of it and use its attributes. I assume you want some kind of temporary data structure to pass around that meets the requirements of a model instance.
class Layout(models.Model):
class Meta:
abstract = True
If you for some reason need actual concrete models, and are fine with it creating tables for them, you could technically also re-implement the save() method and make it no-op.
I don't really understand where and how you will be using this, but this is indeed a model that doesn't save.
Personally, I have actually used models that aren't intended to be saved, in a project that uses mongodb and the nonrel django fork. I create models that are purely meant to be embedded into other models as nested sub-documents and I never want them to be committed to a separate collection.
Update
Here is another suggestion that might make things a whole lot easier for your goal. Why not just use a normal django model, save it to the database like normal, and create a simple import/export function to save it out to XML or read into an instance from XML. That way you get 100% normal admin functionality, you can still query the database for the values, and the XML part is just a simple add-on. You can also use this to version up preferences and mark a certain one as active.

Django design patterns for overriding models

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