Ошибка Django: объект 'DetailView' не имеет атрибута '_meta'

Это меня поразило. Я строю модель с Django & REST API, и у меня проблемы с отображением DetailView для отдельных автомобилей в браузере. ListView работает нормально, но я включу и этот код, поскольку они взаимосвязаны.

В частности, я не могу заставить функцию get_object() работать должным образом.

Первый подход, который я попробовал, использовал следующее:

views.py

class CarDetailView(generics.RetrieveUpdateDestroyAPIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'car-detail.html'
    queryset = Car.objects.all()
    lookup_field = Car.id
    
    @action(detail=True, renderer_classes=[TemplateHTMLRenderer])
    def get(self, request, *args, **kwargs):
        car = self.get_object()
        return Response({
            'car': car,
        })

Хотя страница отображалась правильно и без ошибок, ни один из тегов шаблона не работал. Только {{ car.model }}, который вернул None.

Поэтому я изменил код, чтобы использовать self.get_object()

 class CarDetailView(generics.GenericAPIView):
        renderer_classes = [TemplateHTMLRenderer]
        template_name = 'car-detail.html'
    
        queryset = Car.objects.all()
        lookup_field = Car.id
    
        def get(self, request, id):
            serializer_class = CarSerializer
            car = self.get_object()
            id = Car.id
    
            return Response({
                'car': car,
            })

но это вызывает ошибку:

"AttributeError at /rentals/car/43c9b98d-9f2d-473f-9c34-7b2e25630278 Объект 'CarDetailView' не имеет атрибута '_meta'"

Можете ли вы помочь с этим? Я просмотрел большинство предыдущих вопросов здесь (именно здесь я научился передавать self в функции get и т.д...), но я все еще застрял.

Вот код:

views.py

class CarListView(generics.ListCreateAPIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'car-list.html'

    def get(self, request):
        car_list = Car.objects.all()
        serializer_class = CarSerializer

        return Response({
            'car_list': car_list,
        })

class CarDetailView(generics.GenericAPIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'car-detail.html'

    queryset = Car.objects.all()
    lookup_field = Car.id

    def get(self, request, id):
        serializer_class = CarSerializer
        car = self.get_object()
        id = Car.id

        return Response({
            'car': car,
        })

serializers.py class CarSerializer(serializers.ModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='rental:car-detail', format='html')

class Meta:
    model = Car
    fields = ['url', 'id', 'manufacturer', 'model', 'owner', 'color', 'year']

models.py

class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.SET_NULL, null=True)
    model = models.ForeignKey(CarModel, on_delete=models.SET_NULL, null=True)
    # Model year. Validator ensures that no model year  can be set in the future. 
    year = models.IntegerField(validators=[MaxValueValidator(int(datetime.date.today().year) + 1)], null=True, default=2022)

    ...
    Other fields for drivetrain, engine etc
    ...

    # Fields for individual car in database
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text="Automatically generated unique ID. Do not change.")
    mileage = models.IntegerField(null=True)
    
    insurance = models.ForeignKey(Insurance, on_delete=models.RESTRICT, null=True)

    daily_rate = models.IntegerField(default=3500, help_text="Daily rate in Kenyan Shillings")


    def __str__(self):
        return f'{ self.manufacturer } { self.model }'

    @property
    def insurance_expired(self):
        """Determines if insurance is expired based on due date and current date."""
        return bool(self.insurance.expiry_date and datetime.date.today() > self.insurance.expiry_date)

    class Meta:
        ordering = []
        permissions = (("can_change_availability", "Set car as rented"),)

    def get_absolute_url(self):
        return reverse('rental:car-detail', args=[str(self.id)])

urls.py

from django.urls import path, include 
from . import views

app_name = 'rental'

# API endpoints
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('cars/', views.CarListView.as_view(), name='car-list'),
    path('car/<uuid:id>', views.CarDetailView.as_view(), name='car-detail'),
] 

Код ошибки

AttributeError at /rentals/car/43c9b98d-9f2d-473f-9c34-7b2e25630278
'CarDetailView' object has no attribute '_meta'
Request Method: GET
Request URL:    http://localhost:8000/rentals/car/43c9b98d-9f2d-473f-9c34-7b2e25630278
Django Version: 4.1.3
Exception Type: AttributeError
Exception Value:    
'CarDetailView' object has no attribute '_meta'

Обычно вы должны не реализовывать метод get() самостоятельно, обычно это задача представлений Django (API), которые затем передадут его нужному рендереру и шаблону. Вы

class CarDetailView(generics.RetrieveAPIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'car-detail.html'
    serializer_class = CarSerializer
    queryset = Car.objects.all()

В шаблоне вы можете затем использовать поля автомобиля, таким образом: {{ url }}, {{ model }}, {{ owner }} и т.д.

Если вы планируете выводить шаблон, возможно, имеет смысл работать с DetailView [Django-doc] вместо этого:

from django.views.generic.detail import DetailView


class CarDetailView(DetailView):
    model = Car
    template_name = 'car-detail.html'

в шаблоне, вы можете затем использовать {{ object.url }}, {{ object.model }} и т.д., а также "следовать" отношениям.

Вернуться на верх