Symfony ou Django ou [Flask] ? Angular/React/ [Vuejs 3] /Stimulus?

Pour un projet en 2020 je te déconseillerais d’utiliser jquery honnêtement, surtout si tu l’utilises que pour faire des requêtes Ajax alors qu’on a l’API Fetch en JS natif qui est supportée de partout. Et si tu devais supporter de vieux navigateurs Axios est probablement une meilleure solution.

2 « J'aime »

DRF fournit des views et serializer prêt à l’emploi sur lequel tu dérives tes propres classes pour avoir une interface REST.

Mais ça utilise les mêmes backend à la fin: le Phili_b_View que tu utilises qui hérite du APIView de DRF hérite lui aussi du View de Django.

Si j’ai bien compris Django Rest Framework n’a pas les templates back de Django «normal », ce qui paraît logique d’après son nom. Il faut, d’après ce que j’ai compris, créer alors les templates côté front js, mais surtout que ce framework front js ait des controllers.

Or comme conseillé, par @damaki notamment, je voudrais éviter pour ce projet d’installer des framework comme React/Angular/Vue.

édit : ha j’ai trouvé. voilà ce que je cherchais. Effectivement DRF peut gérer les template en back, mais je ne le trouvais dans aucun exemple ou résumé de DRF

Ils ont été piratés ou pas ? Ça met erreur de certificat, et si on passe outre on a un menu d’upload pas engageant du tout.

Intéressant. Pas mal fait, sa formule est originale.

Oui on dirait en effet.
Ou bien ils n’ont pas reouvelé le domaine, le site était mort depuis longtemps de toutes façons. Mais c’est dommage, les articles étaient sympas et pleins d’infos intéressantes.

Excellent l’article Django Views — The Right Way dont tu me parles. Je suis content de l’avoir lu avant d’avoir vraiment démarré.

C’est clair que les FBV rendent les views largement plus maintenables et évolutives. :slight_smile:

Et bien vu les parties « Discussion » d’un point de vue pédagogique pour contrer/discuter les « oui mais… » sans que ça noie l’explication initiale.

édit : Le seul truc que je n’ai pas compris: Pourquoi il n’a pas implémenté ses solutions en class ? Le modèle POO de Django ne s’y prête pas car les méthodes présentées par Django sont trop haut niveaux pour les CBV? C’est bien ça ? (ou alors, dans la même logique, il faudrait taper plus bas mais là il faut récrire une partie de la class initiale ).

Après j’ai bien lu que ça posait aussi un souci sur les communications inter-methodes d’une même classe.

Mais bon de toute façon comme c’est bien plus clair et maintenable je vais adopter ses FBV.

sametmax.com est revenu à la vie. Je vais pouvoir lire l’article « Des vues normales aux vues génériques Django »

mais


Pour des parties de mon projet développées de A à Z, je ferais des function based views , mais pour tout ce qui est mise en application de packages externes déjà en class based views, ça risque d’être compliqué.

En effet j’ai vu que la très grande majorité des POCs, github, articles, ainsi que les exemples de packages sont en class based views.

Par exemple je suis tombé sur le package ci-dessous pour implémenter le plugin js datatables.net, que j’utilise déjà beaucoup avec R Shiny (dont le wrapper s’appelle DT), ben tout est en class based view.

J’ai essayé de modifier les class based view en function based view grace à ces 2 pages sur DRF mais pour l’instant je rame car il ne retrouve pas ses petits dans le serializer, et je me demande si c’est utile dans ce cas de figure de transformer les CBV en FBV.

Le fichier views.my dont j’essaye de transformer AlbumViewSet en function base view (ainsi que le fichier serializers.py correspon

J’ai essayé avec les lignes en dessous. ça fonctionne presque. En tout cas ça m’a permis de comprendre la class viewsets.ModelViewSet de la refaire en FBV.

...
from rest_framework.response import Response
from rest_framework_datatables import pagination as dt_pagination
...
from rest_framework.decorators import api_view, renderer_classes
from rest_framework.renderers import JSONRenderer , BrowsableAPIRenderer
from rest_framework_datatables.renderers import DatatablesRenderer
....
@api_view(['GET', 'HEAD' ])
@renderer_classes([BrowsableAPIRenderer,DatatablesRenderer])
def AlbumViewFBV(request):
        paginator=dt_pagination.DatatablesPageNumberPagination()
        paginator.page_size = 10
        paginator.template ='albums/albums.html'
        queryset = Album.objects.all().order_by('rank')

        page = paginator.paginate_queryset(queryset,request)
        if page is not None:
            serializer = AlbumSerializer(page, many=True)
            return paginator.get_paginated_response(serializer.data)

        serializer = AlbumSerializer(queryset, many=True)
        return Response(serializer.data)

Mais quand je vais dans http://192.168.x.xxx :yyyy/AlbumViewFBV/ il me manque ce qui existe dans la vue initiale en CBV, en fait j’ai les bonnes données en json mais pas l’étage du dessus c’est à dire pas qu’il manque la pagination nécessaire pour le plug-in js datatables.net.

 "count": 500,
    "next": "http://192.168.x.xxx:yyyy/AlbumViewFBV/?page=2",
    "previous": null,
    "results":

Bon je ne vais pas mettre pas à pas ce que je fais je vais simplement poser des questions plus importantes.

Simplement pour finir, ma solution à mon précédent message était simplement d’inverser les decorators.

@renderer_classes([BrowsableAPIRenderer,DatatablesRenderer,JSONRenderer])
@api_view(['GET'])
def AlbumViewFBV(request):
    
    request.accepted_renderer.format == 'datatables'
    
    queryset = Album.objects.all().order_by('rank')
    if len(queryset)> 0:
        paginator=dt_pagination.DatatablesPageNumberPagination()
        #paginator = PageNumberPagination()
        paginator.page_size = 10
        paginator.template ='albums/albums.html'
        result_page = paginator.paginate_queryset(queryset, request)
        serializer = AlbumSerializer(result_page, many=True)
        return paginator.get_paginated_response(serializer.data)
    else:
        return Response({},status=status.HTTP_200_OK)

Vraiment tout les tutoriaux récents ne sont pas en FBV sans parler comme je disais des add-ons comme django_rest_framework_datatables qui n’ont été pensé qu’en ModelViewSet (ou ViewSet) de Django Rest Framework, et qu’il faudrait analyser pas à pas comme j’ai commencé à le faire dans les messages précédents, mais c’est sans fin pour que ça marche avec django_rest_framework_datatables, mais je vais avoir le même souci pour d’autres packages récents.

Je crois que je vais finalement utiliser les ModelViewSet (ou ViewSet), comme je vais utiliser DRF, mais en détaillant les options possibles, même si je ne me sers pas de toutes, pour faciliter la lecture et la maintenance.

En plus avec les ModelViewSet (ou ViewSet) les routeurs sont bien plus faciles à écrire.

Après pour les petites fonctionnalités purement spécifiques à ce projet et non dépendantes de framework alors là j’utiliserai peut-être des FBV.

Je pensais à cela pour savoir comment architecturer mon projet en lisant les articles ci-dessous.

@PetitPrince, @Thomasorus @Histrion, tout le monde susceptible de répondre :slight_smile: :

Je trouve plein de solutions d’affichage de table mais très peu en édition. Il y a bien celle-ci, GitHub - Dmitri-Sintsov/django-jinja-knockout: Django datatables and widgets, both AJAX and traditional. Display-only ModelForms. ModelForms / inline formsets with AJAX submit and validation. Works with Django templates., mais ce sont des formulaires modaux au dessus de la table. Sinon y’a ça python - Django - edit HTML table rows and update database - Stack Overflow et ça Python Django Tutorial Part 12 | Live Editable Table Using Jquery Ajax (Youtube)

Qu’en pensez vous ?

Qu’est-ce que vous utilisez pour éditer des tables de plusieurs milliers de lignes sous Django ?

Donc j’arrive bien à brancher tout ce que je veux Django Rest Framework, avec Django Rest Framework Datatables, avec SQL Server. Et je vais continuer a priori puisque j’ai bien investi dedans, et que j’arrive à faire fonctionner le bouzin.

Par contre je m’aperçois d’un truc:

  • Django est très pratique pour créer et gérer un modèle par Django. En fait que Django soit la source de la structure des données.
  • En revanche pour pour utiliser des requêtes de données variées dynamiques, de nombre de colonnes variables, en SQL et Python, comme je le faisais avec R Shiny, c’est la croix et la bannière avec cet ORM qui veut tout régenter. J’ai réussi à contourner en faisant une vue. Mais pour les vues paramétrées (en fait les fonctions utilisées comme vues paramétrées en SQL server), c’est pas simple (POC d’adaptation en pause).

Et donc autant l’ORM est pratique pour les formulaires de mises à jour et les SELECT simple, mais en fait j’aimerais débrancher l’ORM pour les SELECT complexes…mais ce n’est pas du tout dans la philosophie de Django qui est de nous prendre par la main dans ce domaine.

Et quand on sort de l’ORM, quelqu’il soit (merci pour la suggestion pour SqlAlchemy), tout la couche haute ne fonctionne plus, il faut réécrire cette couche. Les CMS ont vraiment du mal avec une structure de sélection changeante: je me demande quelles solutions utilisent les gens pour avoir du Web Python sans structure rigide de données.

En fait dans mon besoin c’est la donnée qui devrait s’imposer à la solution de restitution et non le contraire. (En fait comme R Shiny mais qui n’est pas adapté, sauf bricolage, à la mise à jour données).

Je ne sais pas si tu as vu le module text d’SqlAlchimie il permet d’utiliser l’ORM ou le sql classique (mais jamais utilisé avec django):

from sqlalchemy.sql import text
with engine.connect() as con:

data = ( { "id": 1, "nom": "Ewi", "mail": "ewi@gz.fr" },
         { "id": 2, "nom": "phili_b", "mail": "phili_b@gz.fr" },
)

stat= text("INSERT INTO user(id, nom, mail) VALUES(:id, :nom, :mail)")

for line in data:
    con.execute(stat, line)
with engine.connect() as con:

    rs = con.execute('SELECT * FROM user')

    for row in rs:
        print row

Mais de ce que j’en ai vu, en tout cas pour l’ORM natif, quand on écrit en SQL, tout l’arborescence de ModelViewSet saute, et il faut donc récrire une partie.

Je ne serais pas surpris que ça soit la même chose quelque soit l’ORM, car les objets appelant ne retrouvent plus leurs fonctionnalités.

Par exemple j’ai bien réussi à faire cela ci-dessous dans les modèles, mais Django Rest Framework et Django Rest Framework Datatables ne fonctionnaient plus au niveau des vues car ils ne retrouvaient pas leurs petits. Je doute que cela fonctionne mieux avec SqlAlchemy, après je peux me tromper.

MonProjetDjango/MonAppli/models.py

    from django.db import models
    from itertools import *
    from django.db import connections

    class MaTableMaitreManager(models.Manager):
        def __init__(self, *args, **kwargs):
            self.db_params = kwargs.pop('db_params')
            super(MaTableMaitreManager, self).__init__(*args, **kwargs)

        def tout(self):
            return list(
                query_to_dicts(
                    self.db_params, '''SELECT * from VF_mafonction(1234,1)'''
                )
            )


    class MaTableMaitre(models.Model):
        class params:
            db = 'ma_base_mssql_metier'

        db_params = params().db
        objects = MaTableMaitreManager(db_params=db_params)

        class Meta:
            managed = False
            app_label = 'MonAppli'


   # je l'ai mis à la fin pour faciliter la lecture
    def query_to_dicts(db_params, query_string, *query_args):
        cursor = connections[db_params].cursor()
        cursor.execute(query_string, query_args)
        col_names = [desc[0] for desc in cursor.description]
        while True:
            row = cursor.fetchone()
            if row is None:
                break
            row_dict = dict(zip(col_names, row))
            yield row_dict
        return

ag-grid. C’est pur Javascript, donc ce n’est pas lié du tout à Django ou à quoique ce soit côté serveur.

La version gratuite est parfaite si tu veux juste présenter tes données dans un table en pouvant les y éditer. C’est plus prévu pour lui fournir les données en JSon que pour prendre une table HTML existente, mais au final tu pourras filtrer/ranger toutes tes colonnes, et surtout ça scale très très bien même avec des dizaines de milliers de lignes et des centaines de colonnes, sans avoir forcément besoin de mettre en place de la pagination de données avec le serveur si toutes tes données sont dispo rapidement côté serveur.

Après il y a des features en plus qui sont payantes (export en XLSX, mode Pivot pour l’analyse des données, etc.), mais si tu cherches juste à montrer plein de données dans une table avec de l’édition inline qui-va-bien, ça vaut vraiment le coup de jeter un oeil à la version gratuite.

Ah ok, merci. Je regarderais comme alternative dans certains cas à datatables.net (que j’utilise déjà beaucoup dans R Shiny d’où ma réutilisation avec Django et comme maintenant les utilisateurs y sont habitués).

Mais comme c’est payant en édition… comme l’est d’ailleurs editor.datatables.net

Non, c’est pas forcément payant. La version gratuite (« Community ») possède déjà plein de features.

Comme c’est du MIT License, c’est très business-friendly, donc pas de souci pour l’utiliser dans un produit payant, il n’y a rien à payer. Bon après si tu veux les features avancées il faut payer pour la version Enterprise, mais de ce que j’ai cru comprendre ce n’est pas ton cas.

Bon vous allez rire. Je viens d’essayer cet petit article tutoriel en Flask, concis mais efficace, et tout fonctionne comme un charme et je peux écrire ce que je veux en SQL, surtout select * sans être obliger de me repalucher la structure à chaque fois.

Contrairement à Django qui est conçu pour gérer sa structure dont il est le maitre.

Ce que j’ai fais en Django m’a permis d’avoir une structure et de comprendre les tenants et aboutissants, dont je vais recopier plus ou moins l’arborescence mais finalement je vais peut-être opter pour Flask :smiley: Pour un CMS, Django est très bien, mais pour des données versatiles et évolutives comme j’ai, il est trop rigide.

Avec mes petites modifs pour tester pour Sql Server et datatables, inspiré de l’article ci-dessous (que j’avais essayé d’appliquer sur Django Rest Framework datables à moitié) pour reproduire mes tableaux comme sur R Shiny.

app.py

@@ -1,10 +1,21 @@
 from flask import Flask, render_template, request
-import sqlite3
+#import sqlite3
+import pyodbc
 import pandas as pd
 
 # Database file
-DB = "data.sqlite"
+# DB = "data.sqlite"
+
+server = 'xxxx'
+database = 'xxxx'
+username = 'xxxx'
+password = 'xxxx'
+port = xxxx
+driver = '{ODBC Driver 17 for SQL Server}'
+connexion_bdd_odbc_txt= f'DRIVER={driver};SERVER={server},{port};DATABASE={database};UID={username};PWD={password}'
+
 # Create app
 app = Flask(__name__)
 app.config.from_object(__name__)
@@ -14,8 +25,11 @@
 @app.route("/index/")
 def index():
     # Load table from database
-    conn = sqlite3.connect(DB)
-    conn.row_factory = sqlite3.Row
+    # conn = sqlite3.connect(DB)
+    # conn.row_factory = sqlite3.Row
+    conn = pyodbc.connect(connexion_bdd_odbc_txt)
+   # fonctionne aussi avec une fonction MsSql comme vue paramétrée
     df = pd.read_sql("SELECT * FROM my_items", conn)
     conn.close()
     # Add empty column for checkboxes
@@ -44,8 +58,12 @@
     # Thus this parsing will be table-dependent.
     id = int(row_data[2:-3].split(",")[1].replace('"', ''))
     # Now update database with the selection/deselection information
-    conn = sqlite3.connect(DB)
-    conn.row_factory = sqlite3.Row
+
+
+    # conn = sqlite3.connect(DB)
+    # conn.row_factory = sqlite3.Row
+
+    conn = pyodbc.connect(connexion_bdd_odbc_txt)
     c = conn.cursor() 

index.html

@@ -41,7 +41,21 @@
         },
         order: [[ 1, 'asc' ]]
       } );
-       
+      // duplicate thead tr for search columns 
+      $("#output thead tr").clone().appendTo("#output thead ");
+      // Setup - add a text input to each footer cell
+      $('#output thead tr:eq(1) th').each(function() {
+         var title = $(this).text(); $(this).html('<input type="text"  placeholder="Search ' + title + '" class="column_search" />');
+      });
+
+      // Apply the search
+      $('#output thead').on('keyup', ".column_search", function() {
+           table
+            .column($(this).parent().index())
+            .search(this.value)
+            .draw();
+      });
+
       // Select rows that were specified by flask app.

J’ai adopté cette structure grâce à Blueprint et cet article de Real Python (à la fin du message).
Je commence à bien avancer (*) .

Et je relis tout les messages précédents me conseillant Flask :sweat_smile: (Mais de me plonger dans Django n’a pas été une perte du temps: pour avoir une structure et pour d’autres projets.)

flaskMonAppli/
    .gitignore
    app.py
    config.py
    db.py
    README.md
    api/
        api.py
        __init__.py
    auth/
        auth.py
        __init__.py
        templates/
            auth/
                forgot_password.html
                login.html
                signup.html
    HomePage/
        HomePage.py
        __init__.py
        templates/
            HomePage/
                Home_tag_head.html
    Ecran1/
        Ecran1.py
        static/
            js/
                Ecran1.js
        templates/
            Ecran1/
                Ecran1.html (extends de Home_tag_head.html)
                
    static/
        flasksharedwww/
        css/
            MonAppliRShiny.css
            MonAppliRShiny.ModifFlask.css


C’est vrai que RealPython est une mine d’or en plus chaque article est concis et efficace.

edit: * = Et surtout sans SqlAlchemy. En tout cas dans un premier temps car toutes mes tables servant de point de départ à mes écrans sont des requêtes SQL avec des données et structures versatiles.

Après pour les tables de référence et leurs mises à jour dans des formulaires j’utiliserais peut-être SqlAlchemy.