Je pense que ce n'est un secret pour personne que dans les conversations de dĂ©veloppeurs Python expĂ©rimentĂ©s, et pas seulement, des phrases glissent souvent que Django est malĂ©fique, que Django a une mauvaise architecture et qu'il est impossible d'Ă©crire un grand projet dessus sans douleur. MĂȘme un projet Django de taille moyenne est souvent difficile Ă maintenir et Ă Ă©tendre. Je propose de comprendre pourquoi cela se produit et ce qui ne va pas avec les projets Django.
Un peu de théorie
Lorsque nous commençons à apprendre Django sans expérience d'autres langages et frameworks, en plus de la documentation, nous lisons des tutoriels, des articles, des livres, et dans presque tout, nous voyons quelque chose comme ceci:
Django est un framework qui utilise le modĂšle de conception Model-View-Controller (MVC).
Et puis un tas de diagrammes et d'explications inexacts sur ce qu'est MVC. Pourquoi ils sont inexacts et ce qui ne va pas avec eux, vous pouvez voir ici ou ici .
En rÚgle générale, ces schémas décrivent MVC de cette maniÚre:
ModÚle - accÚs au magasin de données
View est l'interface avec laquelle l'utilisateur interagit
Le contrĂŽleur est une sorte d'objet de connexion entre le modĂšle et la vue.
Ces schĂ©mas courants ne font que semer la confusion et vous gĂȘner lorsque vous souhaitez Ă©crire une application contenant une logique mĂ©tier.
Il y a deux choses Ă noter.
, M MVC â , , , . , MVC MV*. MVC M domain model â , . , M MVC , domain model , . , , -.
, Django controller, , Django views â , . , FAQ, , View MVC, , DRF, Controller Django . FAQ, , Django MTV (Model, Template, and View). Web MVC Django , view .
, Django MVC , MVC â - . , .
Django , :
front-end/templates
serializers/forms
views
models
, . Django c DRF. , .
â . :
,
â . , :
serializers/forms
serializers ( serializers forms):
Python
Python Python (, Django dict)
, create update, save() view.
:
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
def create(self, validated_data):
return Comment.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
instance.save()
return instance
- view:
# .save() will create a new instance.
serializer = CommentSerializer(data=data)
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)
comment = serializer.save()
, .
ModelSerializer ModelViewSet, CRUD - .
# serializers.py
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = â__all__â
# views.py
class OrderViewsSet(viewsets.ModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderSerializer
ModelViewSet ModelSerializer, , .
, , create , - .
# serializers.py
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = []
def create(self, validated_data):
# ,
...
#
instance = super(OrderSerializer, self).create(validated_data)
#
...
#
...
#
...
return instance
# views.py
class OrderViewsSet(viewsets.ModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderSerializer
- , view.
:
:
CRUD
Django DRF CRUD.
:
MVC
- (/) . - .
View MVC Django. , MVC â -.
, - .
- .
â , views. - , , .
- , .
DRF Serializers Django Forms. serializers, . Django Forms DRF Serializers .
/
, .
. , , , -, - ( ).
-. - , CRUD, save , .
ModelSerializer create update ( ModelSerializer read only â ). - , CRUD , DRF .
Views
View Django , , . , , , views -, -. , views Django , - , («, , »; Fat Stupid Ugly Controllers).
- :
# views.py
class OrderViewsSet(viewsets.ModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderSerializer
def perform_create(self, serializer):
# ,
...
#
super(OrderViewsSet, self).perform_create(serializer)
#
...
#
...
#
...
, ModelViewSet , . , perform_create ( super, ModelViewSet). ModelViewSet APIView:
# views.py
class OrderCreateApi(views.APIView):
class InputSerializer(serializers.ModelSerializer):
number = serializers.IntegerField()
...
def post(self, request):
serializer = self.InputSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
# ,
...
#
order = Order.objects.create(**serializer.validated_data)
#
...
#
...
#
...
return Response(status=status.HTTP_201_CREATED)
serializers, views.
# views.py
class OrderViewsSet(viewsets.ModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderSerializer
def get_queryset(self):
queryset = super(OrderViewsSet, self).get_queryset()
queryset = queryset.filter(user=self.request.user)
return queryset
, , CRUD, , , . , .
:
, save serializers. serializers ââ ââ .
CRUD
Django DRF , CRUD views .
MVC
- .
view view, - . , - , , Celery .
DRF View Django View. views, . Django View DRF View .
views serializers Django + http client .
views , Celery , , views , â , .
view , -.
.
-
-.
- .
serializers â views -.
ModelViewSet , , APIView GenericAPIView.
CRUD, ModelViewSet .
models
Model MVC, , models -.
:
# models.py
class Order(models.Model):
number = serializers.IntegerField()
created = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=16)
def update_status(self, status: str) -> None:
self.status = status
self.save(update_fields=('status',))
...
@classmethod
def create(cls, data...):
instance = cls(...)
# ,
...
#
instance = instance.save()
#
...
# ( )
...
#
...
# views.py
class OrderCreateApi(views.APIView):
class InputSerializer(serializers.ModelSerializer):
number = serializers.IntegerField()
...
def post(self, request):
serializer = self.InputSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
Order.create(**serializer.validated_data)
return Response(status=status.HTTP_201_CREATED)
view serializer . classmethod, . , , - .
, - save(), .
Managers.
# views.py
class OrderListApi(views.APIView):
class OutputSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = â__all__â
def get(self, request):
orders = Order.objects.filter(user=request.user)
#
# , Order.objects.filter(user=request.user, is_deleted=False, is_archived=False...)
# Manager
data = self.OutputSerializer(orders, many=True).data
return Response(data)
:
serializers views ââ - .
MVC
. View , . MVC.
- , , , views serializers. python . save managers , .
, DRF Views, Django Views, Celery ..
, . Django models ORM â .
- , , . , . , , , , .
CRUD
CRUD, .
MVC . , - .
Services
Django , , Model MVC , .
services Model, - . models property, -, , . :
# models.py
class Order(models.Model):
number = serializers.IntegerField()
created = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=16)
def update_status(self, status: str) -> None:
self.status = status
self.save(update_fields=('status',))
...
# services.py
# DTO
def order_create(name: str, number: int ...) -> bool:
# ,
...
#
order = Order.objects.create(...)
#
...
# ( )
...
#
...
# views.py
class OrderCreateApi(views.APIView):
class InputSerializer(serializers.ModelSerializer):
number = serializers.IntegerField()
...
def post(self, request):
serializer = self.InputSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
services.order_create(**serializer.validated_data)
return Response(status=status.HTTP_201_CREATED)
:
views â , ,
serializers â ,
services â (Service Objects)
managers â ( )
models â
:
# services.py
def order_get_by_user(user: User) -> Iterable[Order]:
return Order.objects.filter(user=user)
# views.py
class OrderListApi(views.APIView):
class OutputSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = ('id', 'number', ...)
def get(self, request):
orders = services.order_get_by_user(user=request.user)
data = self.OutputSerializer(orders, many=True).data
return Response(data)
:
MVC
, - .
Python , .
+ - .
- , .
.
. Django . , Django ORM, .
CRUD
CRUD, .
. , . , .
, , , .
Django, HackSoftware , (services selectors) managers. serializers views . dry-python.
, ââ Django . Django DRF , . , , - , . â .