Hoe kan ik een enkele weergave (geen weergaveset) op mijn router registreren?

Ik gebruik het Django REST-framework en heb geprobeerd een weergave te maken die een klein beetje informatie retourneert, en deze ook op mijn router te registreren.

Ik heb vier modellen die informatie opslaan, en ze hebben allemaal een veld created_time. Ik probeer een weergave te maken die de meest recente objecten retourneert (gebaseerd op de created_time) in een enkele weergave, waarbij alleen de vier aanmaaktijden worden geretourneerd.

Dus, een mogelijke JSON-uitvoer van de weergave zou er als volgt uitzien

{
    "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"
}

Ik hoop deze weergave ook op mijn router te registreren, zodat deze bij de rest van mijn eindpunten verschijnt wanneer de API-root wordt geladen.

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

Hier zijn de vier modellen waarmee ik probeer te werken

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)

Is het mogelijk om dit te doen? En hoe zou het gedaan worden?


Antwoord 1, autoriteit 100%

Routers werken met een ViewSeten zijn niet ontworpen voor normale weergaven, maar dat betekent niet dat u ze niet kunt gebruiken met een normale weergave. Normaal gesproken worden ze gebruikt met modellen (en een ModelViewSet), maar ze kunnen ook zonder worden gebruikt met behulp van de GenericViewSet(als u normaal gesproken een GenericAPIView) en ViewSet(als je gewoon een APIViewzou gebruiken).

Voor een lijstweergave worden de aanvraagmethoden toegewezen aan ViewSetmethoden zoals deze

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

Voor detailweergaven (met een primaire sleutel in de url), gebruiken de aanvraagmethoden de volgende kaart

  • 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)

Dus als je een van deze verzoekmethoden wilt gebruiken met je weergave op je router, moet je de juiste weergavemethode overschrijven (dus list()in plaats van get()).


Nu, specifiek in jouw geval zou je normaal gesproken een APIViewhebben gebruikt die eruitzag als

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,
        })

De vergelijkbare ViewSetzou zijn

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,
        })

Let op de twee vereiste wijzigingen: APIView-> ViewSeten get-> list. Ik heb ook de naam bijgewerkt om aan te geven dat het meer was dan alleen een normale weergave (aangezien een ViewSetniet op dezelfde manier kan worden geïnitialiseerd), maar dat is niet vereist.

Dus met deze nieuwe weergave kunt u deze op dezelfde manier als elke andere in de router registreren. Je hebt hier een base_namenodig zodat de url-namen kunnen worden gegenereerd (normaal gesproken zou dit uit de queryset worden gehaald).

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

Dus nu wordt het updatetime-eindpunt beschikbaar gemaakt in de API-root en kunt u de laatste tijden krijgen door het eindpunt aan te roepen (een eenvoudig GET-verzoek).


Antwoord 2, autoriteit 4%

Er is nog een manier om het te doen:

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

Maar dingen als Swagger werken daar niet mee

Other episodes