web-dev-qa-db-fra.com

Comment puis-je enregistrer une seule vue (pas un ensemble de vues) sur mon routeur?

J'utilise le framework Django REST et j'essaie de créer une vue qui renvoie un petit nombre d'informations, ainsi que de l'enregistrer sur mon routeur.

J'ai quatre modèles qui stockent des informations, et tous ont un champ created_time. J'essaie de créer une vue qui renvoie les objets les plus récents (basés sur le created_time) dans une seule vue, dans laquelle seules les quatre heures de création sont renvoyées.

Ainsi, une sortie JSON possible à partir de la vue ressemblerait à

{
    "publish_updatetime": "2015.05.20 11:53",
    "meeting_updatetime": "2015.05.20 11:32",
    "training_updatetime": "2015.05.20 15:25",
    "exhibiting_updatetime": "2015.05.19 16:23"
}

J'espère également enregistrer cette vue sur mon routeur. Elle apparaît donc avec le reste de mes points de terminaison lorsque la racine de l'API est chargée.

router.register(r'updatetime', views.UpdateTimeView)

Voici les quatre modèles avec lesquels j'essaie de travailler

class Publish(models.Model):
    user = models.ForeignKey(MyUser)
    name = models.CharField(max_length=50)
    created_time = models.DateTimeField( default=datetime.now)

class Meeting(models.Model):
    user = models.ForeignKey(MyUser)
    name = models.CharField(max_length=50)
    file_addr = models.FileField(upload_to=get_file_path)
    created_time = models.DateTimeField(default=datetime.now)

class Training(models.Model):
    user = models.ForeignKey(MyUser)
    name = models.CharField(max_length=50)
    image = models.ImageField(upload_to=get_file_path, max_length=255)
    created_time = models.DateTimeField(default=datetime.now)

class Exhibiting(models.Model):
    user = models.ForeignKey(MyUser)
    name = models.CharField(max_length=50)
    file_addr = models.FileField(upload_to=get_file_path)
    created_time = models.DateTimeField(default=datetime.now)

Est-il possible de faire cela? Et comment cela se ferait-il?

44
flytofuture

Les routeurs fonctionnent avec un ViewSet et ne sont pas conçus pour des vues normales, mais cela ne signifie pas que vous ne pouvez pas les utiliser avec une vue normale. Normalement, ils sont utilisés avec des modèles (et une ModelViewSet), mais ils peuvent être utilisés sans GenericViewSet (si vous utiliseriez normalement un GenericAPIView) et ViewSet (si vous utilisiez simplement un APIView).

Pour une vue liste, les méthodes de requête sont mappées sur des méthodes ViewSet comme celle-ci

  • GET -> list(self, request, format=None)
  • POST-> create(self, request, format=None)

Pour les vues détaillées (avec une clé primaire dans l'URL), les méthodes de requête utilisent la carte suivante

  • GET -> retrieve(self, request, pk, format=None)
  • PUT -> update(self, request, pk, format=None)
  • PATCH -> partial_update(self, request, pk, format=None)
  • DELETE -> destroy(self, request, pk, format=None)

Par conséquent, si vous souhaitez utiliser l'une de ces méthodes de requête avec votre vue sur votre routeur, vous devez remplacer la méthode de vue correcte (donc list() au lieu de get()).


Maintenant, spécifiquement dans votre cas, vous auriez normalement utilisé une APIView qui ressemblait à

class UpdateTimeView(APIView):

    def get(self, request, format=None):
        latest_publish = Publish.objects.latest('created_time')
        latest_meeting = Meeting.objects.latest('created_time')
        latest_training = Training.objects.latest('created_time')
        latest_exhibiting = Exhibiting.objects.latest('created_time')

        return Response({
            "publish_updatetime": latest_publish.created_time,
            "meeting_updatetime": latest_meeting.created_time,
            "training_updatetime": latest_training.created_time,
            "exhibiting_updatetime": latest_exhibiting.created_time,
        })

Le ViewSet comparable serait

class UpdateTimeViewSet(ViewSet):

    def list(self, request, format=None):
        latest_publish = Publish.objects.latest('created_time')
        latest_meeting = Meeting.objects.latest('created_time')
        latest_training = Training.objects.latest('created_time')
        latest_exhibiting = Exhibiting.objects.latest('created_time')

        return Response({
            "publish_updatetime": latest_publish.created_time,
            "meeting_updatetime": latest_meeting.created_time,
            "training_updatetime": latest_training.created_time,
            "exhibiting_updatetime": latest_exhibiting.created_time,
        })

Notez les deux modifications requises: APIView -> ViewSet et get -> list. J'ai également mis à jour le nom pour indiquer qu'il ne s'agissait pas simplement d'une vue normale (une variable ViewSet ne pouvant pas être initialisée de la même manière), mais ce n'est pas obligatoire.

Donc, avec cette nouvelle vue, vous pouvez simplement l’enregistrer dans le routeur de la même manière que les autres. Vous avez besoin d'un base_name ici pour pouvoir générer les noms d'URL (normalement, ils seraient extraits du jeu de requêtes).

router.register(r'updatetime', views.UpdateTimeViewSet, base_name='updatetime')

Alors maintenant, le noeud final updatetime sera disponible dans la racine de l'API et vous pourrez obtenir les dernières heures en appelant simplement le noeud final (une simple requête GET).

56
Kevin Brown

Il y a une autre façon de le faire:

urlpatterns = [
    # ... 
    url(r'^you_path/', include(router.urls)),
    url(r'^you_path/you_sub_path', views.UpdateTimeView.as_view()),
    # ... 
]

Mais des choses comme Swagger ne fonctionneront pas avec ça

0
Alexander