Question

Django view pointe vers une fonction, ce qui peut poser problème si vous souhaitez modifier seulement un peu de fonctionnalité.Oui, je pourrais avoir des millions d'arguments de mots-clés et encore plus d'instructions if dans la fonction, mais je pensais davantage à une approche orientée objet.

Par exemple, j'ai une page qui affiche un utilisateur.Cette page est très similaire à la page qui affiche un groupe, mais elle n'est toujours pas si similaire à la simple utilisation d'un autre modèle de données.Le groupe compte aussi des membres etc...

Une solution consisterait à pointer les vues vers des méthodes de classe, puis à étendre cette classe.Quelqu'un a-t-il essayé cette approche ou a-t-il une autre idée ?

Était-ce utile?

La solution

J'ai créé et utilisé mes propres classes de vues génériques, définissant __call__ donc une instance de la classe est appelable.J'aime vraiment ça;alors que les vues génériques de Django permettent une certaine personnalisation via des arguments de mots-clés, les vues génériques OO (si leur comportement est divisé en un certain nombre de méthodes distinctes) peuvent avoir une personnalisation beaucoup plus fine via des sous-classes, ce qui me permet de me répéter beaucoup moins.(J'en ai marre de réécrire la même logique de création/mise à jour de vue chaque fois que j'ai besoin de modifier quelque chose que les vues génériques de Django ne permettent pas tout à fait).

J'ai posté du code sur djangosnippets.org.

Le seul véritable inconvénient que je vois est la prolifération des appels de méthodes internes, qui peuvent avoir un impact quelque peu sur les performances.Je ne pense pas que ce soit vraiment un problème ;il est rare que l'exécution de code Python constitue un goulot d'étranglement en termes de performances dans une application Web.

MISE À JOUR:Celui de Django vues génériques sont désormais basés sur les classes.

MISE À JOUR:FWIW, j'ai changé d'avis sur les vues basées sur les classes depuis la rédaction de cette réponse.Après les avoir largement utilisés sur quelques projets, je pense qu'ils ont tendance à conduire à un code satisfaisant et SEC à écrire, mais très difficile à lire et à maintenir plus tard, car les fonctionnalités sont réparties sur de nombreux endroits différents et les sous-classes sont tellement dépendantes. sur chaque détail d'implémentation des superclasses et des mixins.Je sens maintenant que ModèleRéponse et les décorateurs de vue sont une meilleure réponse pour décomposer le code de vue.

Autres conseils

J'avais besoin d'utiliser des vues basées sur les classes, mais je voulais pouvoir utiliser le nom complet de la classe dans ma configuration URL sans toujours avoir à instancier la classe de vues avant de l'utiliser.Ce qui m'a aidé, c'est une métaclasse étonnamment simple :

class CallableViewClass(type):
    def __call__(cls, *args, **kwargs):
        if args and isinstance(args[0], HttpRequest):
            instance = super(CallableViewClass, cls).__call__()
            return instance.__call__(*args, **kwargs)
        else:
            instance = super(CallableViewClass, cls).__call__(*args, **kwargs)
            return instance


class View(object):
    __metaclass__ = CallableViewClass

    def __call__(self, request, *args, **kwargs):
        if hasattr(self, request.method):
            handler = getattr(self, request.method)
            if hasattr(handler, '__call__'):
                return handler(request, *args, **kwargs)
        return HttpResponseBadRequest('Method Not Allowed', status=405)

Je peux maintenant à la fois instancier des classes de vue et utiliser les instances comme fonctions de vue, OU je peux simplement pointer mon URLconf vers ma classe et demander à la métaclasse d'instancier (et d'appeler) la classe de vue pour moi.Cela fonctionne en vérifiant le premier argument de __call__ – si c'est un HttpRequest, il doit s'agir d'une véritable requête HTTP car il serait absurde d'essayer d'instancier une classe de vue avec un HttpRequest exemple.

class MyView(View):
    def __init__(self, arg=None):
        self.arg = arg
    def GET(request):
        return HttpResponse(self.arg or 'no args provided')

@login_required
class MyOtherView(View):
    def POST(request):
        pass

# And all the following work as expected.
urlpatterns = patterns(''
    url(r'^myview1$', 'myapp.views.MyView', name='myview1'),
    url(r'^myview2$', myapp.views.MyView, name='myview2'),
    url(r'^myview3$', myapp.views.MyView('foobar'), name='myview3'),
    url(r'^myotherview$', 'myapp.views.MyOtherView', name='otherview'),
)

(J'ai posté un extrait à ce sujet sur http://djangosnippets.org/snippets/2041/)

Si vous affichez simplement les données des modèles, pourquoi ne pas utiliser le Vues génériques de Django?Ils sont conçus pour vous permettre d'afficher facilement les données d'un modèle sans avoir à écrire votre propre vue et des informations sur le mappage des paramètres d'URL aux vues, la récupération des données, la gestion des cas extrêmes, le rendu de la sortie, etc.

Vous pouvez toujours créer une classe, remplacer le __call__ fonction, puis pointez le fichier URL vers une instance de la classe.Vous pouvez jeter un oeil à Assistant de formulaire classe pour voir comment cela se fait.

Il me semble que vous essayez de combiner des choses qui ne devraient pas l'être.Si vous devez effectuer un traitement différent dans votre vue selon qu'il s'agit d'un objet Utilisateur ou Groupe que vous essayez d'examiner, vous devez utiliser deux fonctions d'affichage différentes.

D'un autre côté, il peut y avoir des expressions idiomatiques courantes que vous voudriez extraire de vos vues de type object_detail...peut-être pourriez-vous utiliser un décorateur ou simplement des fonctions d'assistance ?

-Dan

À moins que vous souhaitiez faire quelque chose d'un peu complexe, l'utilisation des vues génériques est la solution.Ils sont bien plus puissants que leur nom ne l'indique, et si vous affichez simplement des données de modèle, des vues génériques feront l'affaire.

Les vues génériques seront généralement la solution, mais en fin de compte, vous êtes libre de gérer les URL comme vous le souhaitez.FormWizard fait les choses de manière basée sur les classes, tout comme certaines applications pour les API RESTful.

Fondamentalement, avec une URL, vous disposez d'un tas de variables et d'un emplacement pour fournir un appelable, ce que vous fournissez dépend entièrement de vous - la méthode standard est de fournir une fonction - mais en fin de compte, Django n'impose aucune restriction sur ce que vous faites.

Je suis d'accord que quelques exemples supplémentaires sur la façon de procéder seraient bien, mais FormWizard est probablement le point de départ.

Si vous souhaitez partager des fonctionnalités communes entre les pages, je vous suggère de consulter les balises personnalisées.Ils sont plutôt facile à créer, et sont très puissants.

Aussi, les modèles peuvent s'étendre à partir d'autres modèles.Cela vous permet d'avoir un modèle de base pour configurer la mise en page de la page et de le partager entre d'autres modèles qui remplissent les blancs.Vous pouvez imbriquer des modèles à n'importe quelle profondeur ;vous permettant de spécifier la mise en page sur des groupes distincts de pages associées en un seul endroit.

Vous pouvez utiliser les vues génériques de Django.Vous pouvez facilement obtenir les fonctionnalités souhaitées grâce aux vues génériques de Django

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top