web-dev-qa-db-fra.com

Vue basée sur la classe Django pour créer et mettre à jour

Dites que je veux créer une vue basée sur les classes dont mises à jour et crée un objet. D'une question précédente J'ai travaillé sur je pourrais faire l'une des choses suivantes:

1) Utilisez 2 vues génériques CreateView et UpdateView, ce qui signifierait, selon moi, que deux URL pointent vers deux classes différentes.

2) Utilisez une vue basée sur les classes qui hérite de la base View, ce qui signifierait, selon moi, que deux URL pointent vers une seule classe (que j'ai créée et qui hérite de View).

J'ai deux questions:

a) Quel est le meilleur?

b) ccbv.co.uk montre une View de base, mais je ne vois aucune méthode get, post etc. décrite, est-ce correct?

25
GrantU

Pourquoi devez-vous gérer la création et la mise à jour à l'aide d'une seule vue? Il est beaucoup plus simple de disposer de deux vues distinctes, chacune héritant de sa classe de vues générique respective. Ils peuvent partager le même formulaire et le même modèle si vous le souhaitez. Ils sont probablement servis à partir d'URL différentes. Je ne vois donc pas ce que vous obtiendriez en le faisant en une seule vue.

Donc: utilisez deux vues, l’une héritant de CreateView et l’autre de UpdateView. Celles-ci gèrent quasiment tout ce dont vous pourriez avoir besoin, tandis que la seconde approche nécessiterait de réinventer la roue vous-même. Si vous avez un code "Entretien" commun utilisé à la fois lors de la création ou de la mise à jour d'objets, utilisez un mixin ou créez votre propre vue couvrant les deux cas d'utilisation, en héritant de CreateView et UpdateView.

6
Berislav Lopac

Je me suis retrouvé dans une situation où je voulais quelque chose comme ça. Voici ce que j'ai proposé (notez que si vous essayez de l'utiliser comme une vue de mise à jour et que l'objet demandé ne peut pas être trouvé, il se comportera comme une vue de création plutôt que de lancer un 404):

from Django.views.generic.detail import SingleObjectTemplateResponseMixin
from Django.views.generic.edit import ModelFormMixin, ProcessFormView

class CreateUpdateView(SingleObjectTemplateResponseMixin, ModelFormMixin,
        ProcessFormView):

    def get_object(self, queryset=None):
        try:
            return super(CreateUpdateView,self).get_object(queryset)
        except AttributeError:
            return None

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(CreateUpdateView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(CreateUpdateView, self).post(request, *args, **kwargs)

Il s'avère que UpdateView et CreateView héritent de exactement les mêmes classes et mixins. La seule différence réside dans les méthodes get/post. Voici comment ils sont définis dans le source Django (1.8.2):

class BaseCreateView(ModelFormMixin, ProcessFormView):
    """
    Base view for creating an new object instance.

    Using this base class requires subclassing to provide a response mixin.
    """
    def get(self, request, *args, **kwargs):
        self.object = None
        return super(BaseCreateView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = None
        return super(BaseCreateView, self).post(request, *args, **kwargs)


class CreateView(SingleObjectTemplateResponseMixin, BaseCreateView):
    """
    View for creating a new object instance,
    with a response rendered by template.
    """
    template_name_suffix = '_form'


class BaseUpdateView(ModelFormMixin, ProcessFormView):
    """
    Base view for updating an existing object.

    Using this base class requires subclassing to provide a response mixin.
    """
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(BaseUpdateView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(BaseUpdateView, self).post(request, *args, **kwargs)


class UpdateView(SingleObjectTemplateResponseMixin, BaseUpdateView):
    """
    View for updating an object,
    with a response rendered by template.
    """
    template_name_suffix = '_form'

Comme vous pouvez le constater, les méthodes getView et post de CreateView définissent self.object = None alors que UpdateView le définit sur self.get_object(). Tout ce que j'ai fait est de combiner ces deux méthodes dans ma méthode CreateUpdateView.get_object qui tente d'appeler la get_object de la classe parente et renvoie None au lieu de déclencher une exception s'il n'y a pas d'objet.

Pour servir une page 404 lorsqu'elle est utilisée comme vue de mise à jour, vous pouvez probablement remplacer as_view et lui transmettre un argument booléen update_only. Si update_only est True et que la vue ne trouve pas l'objet, déclenchez le 404. 

38
scubabuddha

Comme suggéré par @scubabuddha J'ai rencontré une situation similaire et j'ai utilisé sa réponse modifiée en @ mario-orlandi suggéré dans son commentaire:

from Django.views.generic import UpdateView


class CreateUpdateView(UpdateView):

    def get_object(self, queryset=None):
        try:
            return super().get_object(queryset)
        except AttributeError:
            return None

J'ai utilisé cette solution avec Django 1.11 mais je pense que cela peut fonctionner avec Django 2.0.

Mettre à jour

Je confirme que cette solution fonctionne avec Django 2.0 et 2.1.

6
Paolo Melchiorre

Pour partager du code entre vos UpdateView et CreateView, au lieu de créer une classe combinée, vous pouvez utiliser une super-classe commune en tant que mixin. De cette façon, il serait peut-être plus facile de séparer les différentes préoccupations. Et vous pouvez réutiliser beaucoup de code Django existant.

class BookFormView(PJAXContextMixin):
    template_name = 'library/book_form.html'
    form_class = BookForm

    def form_valid(self, form):
        form.instance.owner = self.request.user
        return super().form_valid(form)

    class Meta:
        abstract = True


class BookCreateView(BookFormView, CreateView):
    pass


class FormatUpdateView(BookFormView, UpdateView):
    queryset = Book.objects
1
Risadinha

Vous pouvez également utiliser Django Smartmin qui s’inspire du CBV de Django. Voici un exemple tiré de la documentation: https://smartmin.readthedocs.org/en/latest/quickstart.html

0
iMitwe

La solution la plus simple et la meilleure de toutes link

class WorkerUpdate(UpdateView):
form_class = WorkerForm

def get_object(self, queryset=None):

    # get the existing object or created a new one
    obj, created = Worker.objects.get_or_create(mac=self.kwargs['mac'])

    return obj

et voilà merci @chriskief

0
vladtyum