Объект CategoryDetail не имеет атрибута _state - PullRequest
0 голосов
/ 11 января 2019

Я хочу получить свойства по категориям.

Когда я пытаюсь достичь, например: http://127.0.0.1:8000/category/Berlin появляется следующая ошибка:

Объект CategoryDetail не имеет атрибута _state

Что я делаю не так?

Любая помощь будет высоко оценена.

models.py

from django.db import models
from django.urls import reverse

# Create your models here.

class Property(models.Model):
    title = models.CharField(max_length=140)
    description = models.TextField()
    rooms = models.PositiveIntegerField()
    bed_rooms = models.PositiveIntegerField()
    land_size = models.PositiveIntegerField()
    slug = models.SlugField()
    living_size = models.PositiveIntegerField()
    build_year = models.PositiveIntegerField()
    price = models.PositiveIntegerField()
    category = models.ForeignKey(to='Category', null=True, related_name='categories', on_delete=models.SET_NULL,)

    def get_absolute_url(self):
        return reverse('properties:PropertyDetail', kwargs={'slug': self.slug})

    def __str__(self):
        return '{} - {}'.format(
            self.title, self.build_year
        )

class Category(models.Model):
    name = models.CharField(max_length=150)
    slug = models.SlugField()


    def get_absolute_url(self):
        return reverse('properties:CategoryDetail', kwargs={'slug': self.slug})



    def __str__(self):
        return '{}'.format(self.name)

views.py

from django.shortcuts import render
from .filters import PropertyFilter

# Create your views here.

from django.views.generic import (
    TemplateView, DetailView, ListView
)

from .models import Property, Category

class HomePage(TemplateView):
    template_name = 'home.html'


class PropertyList(ListView):
    model = Property


class PropertyDetail(DetailView):
    model = Property


class CategoryList(ListView):
    model = Category


class CategoryDetail(ListView):
    queryset = Category.categories
    template_name = 'categorydetail.html'


def search(request):
    property_list = Property.objects.all()
    property_filter = PropertyFilter(request.GET, queryset=property_list)
    return render(request, 'prop_list.html', {'filter': property_filter})

urls.py

from django.urls import path

from .views import  (PropertyList, PropertyDetail, HomePage, CategoryList, CategoryDetail)

app_name = 'properties'

urlpatterns = [
    path('', HomePage.as_view(), name='home'),
    path('categories', CategoryList.as_view(), name='categories'),
    path('category/<slug:slug>', CategoryDetail.as_view(), name='CategoryDetail'),
    path('properties', PropertyList.as_view(), name='PropertyList'),
    path('property/<slug:slug>', PropertyDetail.as_view(), name='PropertyDetail'),
]

URL проекта

"""config URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from realestate import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('search', views.search, name='search'),
    path('', include('realestate.urls', namespace='properties')),
]

Ответы [ 2 ]

0 голосов
/ 11 января 2019

Сначала измените related_name на properties, как предложено @cezar, поскольку оно используется для получения связанных свойств для категории.

category = models.ForeignKey(to='Category', null=True, related_name='categories', on_delete=models.SET_NULL,)

Я предлагаю вам использовать DetailView для категории,

class CategoryDetail(DetailView):
    model = Category
    template_name = 'categorydetail.html'

Затем вы можете использовать обратную связь для доступа к свойствам в шаблоне:

{% for property in category.properties.all %}

Если вы действительно хотите использовать представление списка для CategoryDetail, то вам нужно переопределить get_queryset и использовать slug. Например, вы можете сделать:

from django.shortcuts import get_object_or_404

class PropertiesForCategory(ListView):
    template_name = 'categorydetail.html'

    def get_queryset(self):
        category = get_object_or_404(Category, slug=self.kwargs['slug']
        return category.properties.all()

Затем в шаблоне вы будете перебирать набор запросов с помощью:

{% for property in object_list %}
0 голосов
/ 11 января 2019

Пожалуйста, измените следующую строку в классе Property:

category = models.ForeignKey(to='Category', null=True, related_name='categories', on_delete=models.SET_NULL,)

к этому:

category = models.ForeignKey(
    to='Category',
    null=True,
    related_name=<b>'properties'</b>,
    on_delete=models.SET_NULL,
)

Изменение выделено жирным шрифтом. Причина изменения заключается в том, что вы хотите получить свойств для данной категории . Выполнение запроса типа Category.categories сбивает с толку читателя.

Доступ к related_name, который теперь properties, возможен с объекта Category. То, как вы делаете это в классе CategoryDetail:

queryset = Category.categories

, даже если адаптировано к:

queryset = <b>Category.properties</b>

не может работать. Это потому, что он вызвал бы связанный дескриптор ReverseManyToOneDescriptor, который здесь бесполезен.

Вы можете вызывать свойства для объекта Category. Примером может быть:

Category.objects.get(pk=1).properties.all()

Первая часть Category.objects.get(pk=1) вернет один объект Category, а во второй части properties.all() вы вызовете менеджера properties для объекта Category. С помощью метода all() вы получаете QuerySet, содержащий все properties для данного Category объекта.

Помните, что использование что-то вроде Category.objects.all().properties.all() не будет работать. Category.objects.all() вернет QuerySet без атрибута properties.

С учетом этого наилучшим подходом было бы то, что @Alasdair предлагает использовать DetailView. Вы хотите список все Свойства для Категория , и это вас немного смущает. Однако вы по-прежнему отображаете подробности s для категории. Использование DetailView для Category - намного более чистый и приятный подход.

Имея просто:

class CategoryDetail(DetailView):
    model = Category

сделает работу. Имя шаблона по умолчанию будет category_detail.html, и вам не нужно указывать его явно. Просто будьте последовательны с другими классами.

Внутренняя логика подробного представления извлечет отдельный объект Category, и в шаблоне вы можете получить доступ к properties для этого объекта:

{% for property in object.properties.all %}
    {{ property }}
{% endfor %}

Вместо object.properties.all вы можете использовать category.properties.all, что является более многословным и улучшает читабельность.

Если вы хотите изменить это, сделайте это, например:

class CategoryDetail(DetailView):
    model = Category
    context_object_name = 'ctgr'

{% for property in ctgr.properties.all %}

Надеюсь, это поможет вам двигаться вперед.

...