Перейти к содержимому

Get object or 404 django как работает

  • автор:

Использование метода get_object_or_404()

На данный момент, если пользователь вручную запрашивает несуществующую тему или запись, он получает ошибку сервера 500. Django пытается отобразить страницу, но не располагает достаточной информацией для этого, что приводит к ошибке 500. Такая ситуация более точно обрабатывается как ошибка 404, и это поведение можно реализовать при помощи вспомогательной функции Django get_object_or_404(). Эта функция пытается получить запрошенный объект из базы данных, а если этот объект не существует — инициирует исключение 404. Мы импортируем эту функцию в views.py и используем ее вместо get():

from django.shortcuts import render, get_object_or_404

from django.http import HttpResponseRedirect, Http404

def topic(request, topic_id):

«»»Выводит одну тему и все ее записи.»»»

# Проверка того, что тема принадлежит текущему пользователю.

Django shortcut functions¶

The package django.shortcuts collects helper functions and classes that “span” multiple levels of MVC. In other words, these functions/classes introduce controlled coupling for convenience’s sake.

render() ¶

render ( request , template_name , context = None , content_type = None , status = None , using = None

Combines a given template with a given context dictionary and returns an HttpResponse object with that rendered text.

Django does not provide a shortcut function which returns a TemplateResponse because the constructor of TemplateResponse offers the same level of convenience as render() .

Required arguments¶

request The request object used to generate this response. template_name The full name of a template to use or sequence of template names. If a sequence is given, the first template that exists will be used. See the template loading documentation for more information on how templates are found.

Optional arguments¶

context A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the view will call it just before rendering the template. content_type The MIME type to use for the resulting document. Defaults to ‘text/html’ . status The status code for the response. Defaults to 200 . using The NAME of a template engine to use for loading the template.

Example¶

The following example renders the template myapp/index.html with the MIME type application/xhtml+xml:

from django.shortcuts import render def my_view(request): # View code here. return render( request, "myapp/index.html",  "foo": "bar", >, content_type="application/xhtml+xml", ) 

This example is equivalent to:

from django.http import HttpResponse from django.template import loader def my_view(request): # View code here. t = loader.get_template("myapp/index.html") c = "foo": "bar"> return HttpResponse(t.render(c, request), content_type="application/xhtml+xml") 

redirect() ¶

redirect ( to , * args , permanent = False , ** kwargs

Returns an HttpResponseRedirect to the appropriate URL for the arguments passed.

The arguments could be:

  • A model: the model’s get_absolute_url() function will be called.
  • A view name, possibly with arguments: reverse() will be used to reverse-resolve the name.
  • An absolute or relative URL, which will be used as-is for the redirect location.

By default issues a temporary redirect; pass permanent=True to issue a permanent redirect.

Examples¶

You can use the redirect() function in a number of ways.

    By passing some object; that object’s get_absolute_url() method will be called to figure out the redirect URL:

from django.shortcuts import redirect def my_view(request): . obj = MyModel.objects.get(. ) return redirect(obj) 
def my_view(request): . return redirect("some-view-name", foo="bar") 
def my_view(request): . return redirect("/some/url/") 

This also works with full URLs:

def my_view(request): . return redirect("https://example.com/") 

By default, redirect() returns a temporary redirect. All of the above forms accept a permanent argument; if set to True a permanent redirect will be returned:

def my_view(request): . obj = MyModel.objects.get(. ) return redirect(obj, permanent=True) 

get_object_or_404() ¶

get_object_or_404 ( klass , * args , ** kwargs )¶ aget_object_or_404 ( klass , * args , ** kwargs

Asynchronous version: aget_object_or_404()

Calls get() on a given model manager, but it raises Http404 instead of the model’s DoesNotExist exception.

Arguments¶

klass A Model class, a Manager , or a QuerySet instance from which to get the object. *args Q objects . **kwargs Lookup parameters, which should be in the format accepted by get() and filter() .

Example¶

The following example gets the object with the primary key of 1 from MyModel :

from django.shortcuts import get_object_or_404 def my_view(request): obj = get_object_or_404(MyModel, pk=1) 

This example is equivalent to:

from django.http import Http404 def my_view(request): try: obj = MyModel.objects.get(pk=1) except MyModel.DoesNotExist: raise Http404("No MyModel matches the given query.") 

The most common use case is to pass a Model , as shown above. However, you can also pass a QuerySet instance:

queryset = Book.objects.filter(title__startswith="M") get_object_or_404(queryset, pk=1) 

The above example is a bit contrived since it’s equivalent to doing:

get_object_or_404(Book, title__startswith="M", pk=1) 

but it can be useful if you are passed the queryset variable from somewhere else.

Finally, you can also use a Manager . This is useful for example if you have a custom manager :

get_object_or_404(Book.dahl_objects, title="Matilda") 
author = Author.objects.get(name="Roald Dahl") get_object_or_404(author.book_set, title="Matilda") 

Note: As with get() , a MultipleObjectsReturned exception will be raised if more than one object is found.

Changed in Django 5.0:

aget_object_or_404() function was added.

get_list_or_404() ¶

get_list_or_404 ( klass , * args , ** kwargs )¶ aget_list_or_404 ( klass , * args , ** kwargs

Asynchronous version: aget_list_or_404()

Returns the result of filter() on a given model manager cast to a list, raising Http404 if the resulting list is empty.

Arguments¶

klass A Model , Manager or QuerySet instance from which to get the list. *args Q objects . **kwargs Lookup parameters, which should be in the format accepted by get() and filter() .

Example¶

The following example gets all published objects from MyModel :

from django.shortcuts import get_list_or_404 def my_view(request): my_objects = get_list_or_404(MyModel, published=True) 

This example is equivalent to:

from django.http import Http404 def my_view(request): my_objects = list(MyModel.objects.filter(published=True)) if not my_objects: raise Http404("No MyModel matches the given query.") 

Changed in Django 5.0:

aget_list_or_404() function was added.

Функции ярлыков Django ¶

Пакет django.shortcuts собирает вспомогательные функции и классы, которые «охватывают» несколько уровней MVC. Другими словами, эти функции / классы для удобства вводят управляемую связь.

render() ¶

render ( запрос , имя_шаблона , context = None , content_type = None , status = None , using = None ) ¶

Объединяет заданный шаблон с заданным контекстным словарем и возвращает HttpResponse объект с этим визуализированным текстом.

Django не предоставляет функцию быстрого доступа, которая возвращает a, TemplateResponse потому что конструктор TemplateResponse предлагает тот же уровень удобства, что и render() .

Обязательные аргументы ¶

request Объект запроса, использованный для генерации этого ответа. template_name Полное имя используемого шаблона или последовательность имен шаблонов. Если указана последовательность, будет использован первый существующий шаблон. См. Документацию по загрузке шаблонов для получения дополнительной информации о том, как найти шаблоны.

Необязательные аргументы ¶

context Словарь значений для добавления в контекст шаблона. По умолчанию это пустой словарь. Если значение в словаре вызывается, представление вызовет его непосредственно перед рендерингом шаблона. content_type Тип MIME для использования в итоговом документе. По умолчанию ‘text/html’ . status Код состояния для ответа. По умолчанию 200 . using Механизм NAME шаблонов, используемый для загрузки шаблона.

Пример ¶

В следующем примере отображается шаблон myapp/index.html с MIME-типом application / xhtml + xml :

from django.shortcuts import render def my_view(request): # View code here. return render(request, 'myapp/index.html',  'foo': 'bar', >, content_type='application/xhtml+xml') 

Этот пример эквивалентен:

from django.http import HttpResponse from django.template import loader def my_view(request): # View code here. t = loader.get_template('myapp/index.html') c = 'foo': 'bar'> return HttpResponse(t.render(c, request), content_type='application/xhtml+xml') 

redirect() ¶

redirect ( to , * args , постоянный = False , ** kwargs ) ¶

Возвращает HttpResponseRedirect соответствующий URL-адрес для переданных аргументов.

Аргументами могут быть:

  • Модель: get_absolute_url() будет вызвана функция модели .
  • Имя представления, возможно с аргументами: reverse() будет использоваться для обратного разрешения имени.
  • Абсолютный или относительный URL-адрес, который будет использоваться как есть для местоположения перенаправления.

По умолчанию выдает временное перенаправление; пройти, permanent=True чтобы оформить постоянное перенаправление.

Примеры ¶

Вы можете использовать эту redirect() функцию разными способами.

    Путем передачи некоторого объекта; get_absolute_url() метод этого объекта будет вызван для определения URL-адреса перенаправления:

from django.shortcuts import redirect def my_view(request): . obj = MyModel.objects.get(. ) return redirect(obj) 
def my_view(request): . return redirect('some-view-name', foo='bar') 
def my_view(request): . return redirect('/some/url/') 

Это также работает с полными URL-адресами:

def my_view(request): . return redirect('https://example.com/') 

По умолчанию redirect() возвращает временное перенаправление. Все вышеперечисленные формы принимают permanent аргумент; если установлено True постоянное перенаправление, будет возвращено:

def my_view(request): . obj = MyModel.objects.get(. ) return redirect(obj, permanent=True) 

get_object_or_404() ¶

get_object_or_404 ( klass , * args , ** kwargs ) ¶

Вызывает get() данный менеджер модели, но вызывает исключение Http404 модели DoesNotExist .

Обязательные аргументы ¶

klass Model Класс, Manager или QuerySet экземпляр , из которого получить объект. **kwargs Параметры поиска, которые должны быть в формате, принятом get() и filter() .

Пример ¶

В следующем примере объект с первичным ключом 1 получается из MyModel :

from django.shortcuts import get_object_or_404 def my_view(request): obj = get_object_or_404(MyModel, pk=1) 

Этот пример эквивалентен:

from django.http import Http404 def my_view(request): try: obj = MyModel.objects.get(pk=1) except MyModel.DoesNotExist: raise Http404("No MyModel matches the given query.") 

Наиболее распространенный вариант использования — передача Model , как показано выше. Однако вы также можете передать QuerySet экземпляр:

queryset = Book.objects.filter(title__startswith='M') get_object_or_404(queryset, pk=1) 

Приведенный выше пример немного надуман, поскольку он эквивалентен выполнению:

get_object_or_404(Book, title__startswith='M', pk=1) 

но это может быть полезно, если вам передали queryset переменную откуда-то еще.

Наконец, вы также можете использовать Manager . Это полезно, например, если у вас есть собственный менеджер :

get_object_or_404(Book.dahl_objects, title='Matilda') 

Вы также можете использовать : related managers

author = Author.objects.get(name='Roald Dahl') get_object_or_404(author.book_set, title='Matilda') 

Примечание. Как get() и в MultipleObjectsReturned случае, если будет найдено более одного объекта, будет сгенерировано исключение.

get_list_or_404() ¶

get_list_or_404 ( klass , * args , ** kwargs ) ¶

Возвращает результат filter() преобразования данного менеджера модели в список, повышая, Http404 если результирующий список пуст.

Обязательные аргументы ¶

klass Model , Manager Или QuerySet экземпляр , из которого , чтобы получить список. **kwargs Параметры поиска, которые должны быть в формате, принятом get() и filter() .

Пример ¶

Следующий пример получает все опубликованные объекты из MyModel :

from django.shortcuts import get_list_or_404 def my_view(request): my_objects = get_list_or_404(MyModel, published=True) 

Этот пример эквивалентен:

from django.http import Http404 def my_view(request): my_objects = list(MyModel.objects.filter(published=True)) if not my_objects: raise Http404("No MyModel matches the given query.") 

Создаём своё первое приложение с Django, часть 3¶

Продолжаем начатое во второй части учебника. Мы продолжим разрабатывать приложение для голосования и сосредоточимся на создании страниц сайта – “представлений”.

Обзор¶

Представление – это “тип” страниц вашего приложения, которое является функцией для обработки запроса и использует шаблон для генерации страницы. Например, блог может состоять из следующих представлений:

  • Главная страница – показывает несколько последних записей блога.
  • Страница записи – страница отображения одной записи блога.
  • Страница-архив записей по годам – показывает все месяца года и записи блога, сгруппированные по этим месяцам.
  • Страница-архив записей по месяцам – показывает все дни месяца и записи блога, сгруппированные по этим дням.
  • Страница-архив записей по дням – показывает все записи за указанный день.
  • Форма комментариев – предоставляет возможность добавить комментарий к записи блога.

В нашем приложении для голосования мы реализуем следующие представления:

  • Главная страница вопросов – показывает несколько последних вопросов.
  • Страница вопроса – показывает вопрос без результатов но с формой для ответа.
  • Страница результата опроса – показывает результаты опроса.
  • Обрабатывает процесс опроса – обрабатывает ответ на вопрос.

В Django страницы и остальной контент отдается представлениями. Представление — это просто функция Python(или метод представления-класса). Django выбирает представление, анализируя запрошенный URL(точнее часть URL-а после домена).

В наше время в интернете можно наткнуться на такие прелести как “ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B”. Рады вам сообщить, что Django позволяет использовать более элегантные URL шаблоны чем этот.

URL-шаблон — это общая форма URL-а. Например: /newsarchive/// .

Чтобы из URL-а получить представление, Django используется так называемый ‘URLconf’. URLconf определяет соответствие URL-шаблонов(являются регулярными выражениями) и представлений.

В этом разделе мы опишем основы использования настроек URL-ов, больше информации вы можете найти в разделе django.core.urlresolvers .

Добавь парочку представлений¶

Теперь создадим еще парочку представлений в polls/views.py . Эти представления немного отличаются, так как принимают аргументы:

polls/views.py

def detail(request, question_id): return HttpResponse("You're looking at question %s." % question_id) def results(request, question_id): response = "You're looking at the results of question %s." return HttpResponse(response % question_id) def vote(request, question_id): return HttpResponse("You're voting on question %s." % question_id) 

Привяжем наше представление новостей в модуле polls.urls добавив вызов url() :

polls/urls.py

from django.conf.urls import url from . import views urlpatterns = [ # ex: /polls/ url(r'^$', views.index, name='index'), # ex: /polls/5/ url(r'^(?P[0-9]+)/$', views.detail, name='detail'), # ex: /polls/5/results/ url(r'^(?P[0-9]+)/results/$', views.results, name='results'), # ex: /polls/5/vote/ url(r'^(?P[0-9]+)/vote/$', views.vote, name='vote'), ] 

Откройте страницу “/polls/34/”. Будет выполнена функция detail() и показан ID, который вы указали в URL. Откройте “/polls/34/results/” и “/polls/34/vote/” – вы увидите наши будущие страницы результатов и голосования.

При запросе страницы – например, “/polls/34/”, Django загружает модуль mysite.urls т.к. он указан в ROOT_URLCONF . Находит переменную urlpatterns и перебирает все регулярные выражения по порядку. include() просто ссылается на другой URLconf. Заметим, что регулярное выражение для include() не содержит $ (признак конца строки) но содержит завершающий слэш. Когда Django встречает include() , он отрезает распознанную часть URL, все что осталось передает в указанный URLconf для дальнейшей обработки.

Идея использования include() и разделения URLconf состоит в том, чтобы легко подключать и изменять конфигурацию URL-ов. Теперь, когда приложение голосования содержит собственный URLconf( polls/urls.py ), вы можете подключить его в “/polls/”, или “/fun_polls/”, или в “/content/polls/”, или другой путь и приложение будет работать.

Вот что произойдет при запросе к “/polls/34/”:

  • Django найдет '^polls/'
  • Затем Django обрежет распознанную часть ( "polls/" ) и передаст остаток – "34/" – в ‘polls.urls’ для дальнейшей обработки, который будет распознан r'^(?P[0-9]+)/$' и будет вызвана функция detail() :

detail(request=, question_id='34')

Аргумент question_id='34' получен из (?P[0-9]+) . Использование скобок вокруг “captures” позволяет передать значения распознанные регулярным выражением в представление, ?P определяет название переменной при передаче и регулярное выражение [0-9]+ , которое распознает цифры.

Так как URL-шаблоны – это регулярные выражения, вы можете распознать какой угодно URL. И нет необходимости добавлять в URL всякий хлам, вроде .html , пока это вам не понадобится. В таком случае добавьте что-то вроде:

url(r'^polls/latest\.html$', views.index), 

Но не делайте так. Это глупо.

Добавим функционал в наши представления¶

Каждое представление должно выполнить одно из двух действий: вернуть экземпляр HttpResponse с содержимым страницы, или вызвать исключения такое как Http404 . Все остальное на ваше усмотрение.

Ваше представление может обращаться к базе данных или нет. Может использовать систему шаблонов Django – или любую другую – или не использовать. Может генерировать PDF файл, возвращать XML, создавать ZIP архив “на лету”, все что угодно, используя любые библиотеки Python.

Все что нужно Django – это HttpResponse . Или исключение.

Мы будем использовать API Django для работы с базой данных, которое мы рассматривали в Части 1. Изменим index() так, чтобы оно отображало последние 5 вопросов разделенные запятой от самого нового к самому старому:

polls/views.py

from django.http import HttpResponse from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] output = ', '.join([q.question_text for q in latest_question_list]) return HttpResponse(output) # Leave the rest of the views (detail, results, vote) unchanged 

Есть небольшая проблема: внешний вид страницы определяется в представлении. Если вы захотите изменить дизайн страницы, вам придется менять код. Давайте воспользуемся системой шаблонов Django, чтобы отделить представление от кода.

Для начала создайте каталог templates в каталоге приложения polls . Django будет искать шаблоны в этом каталоге.

Настройка TEMPLATES указывает Django как загружать и выполнять шаблоны. По умолчанию используется бэкенд DjangoTemplates , с опцией APP_DIRS равной True . В этом случае DjangoTemplates проверяет подкаталог “templates” в приложениях, указанных в INSTALLED_APPS .

В только что созданном каталоге templates , создайте каталог polls , и в нем создайте файл index.html . То есть создайте файл polls/templates/polls/index.html . Учитывая как работает загрузчик шаблонов app_directories , вы сможете обращаться к шаблону как polls/index.html .

Пространства имен для шаблонов

Мы бы могли создать наш шаблон непосредственно в polls/templates (а не подкаталоге polls ), но это плохая идея. Django будет использовать первый найденный шаблон, и если существует шаблон с аналогичным названием в другом приложении, Django не сможет различить их. Чтобы этого избежать, мы будем использовать пространство имен. Точнее, просто добавим их в еще один подкаталог с названием, аналогичным названию приложения.

Добавьте следующий код в шаблон:

polls/templates/polls/index.html

Теперь изменим наше представление index в polls/views.py , чтобы использовать шаблон:

polls/views.py

from django.http import HttpResponse from django.template import RequestContext, loader from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] template = loader.get_template('polls/index.html') context = RequestContext(request,  'latest_question_list': latest_question_list, >) return HttpResponse(template.render(context)) 

Этот код загружает шаблон polls/index.html и передает ему контекст. Контекст - это словарь, содержащий название переменных шаблона и соответствующие им значения.

Загрузите страницу в браузере по адресу “/polls/”, вы должны увидеть список с опросом “What’s up” из Части 2. Ссылка ведет на страницу опроса.

Функция render()

Процесс загрузки шаблона, добавления контекста и возврат объекта HttpResponse , вполне тривиальный. Django предоставляет функцию для всех этих операций. Вот как будет выглядеть наш index() :

polls/views.py

from django.shortcuts import render from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] context = 'latest_question_list': latest_question_list> return render(request, 'polls/index.html', context) 

Так как мы используем такой подход во всех наших представлениях, нет необходимости импортировать loader , RequestContext и HttpResponse ( HttpResponse еще нужен, если остались старые detail , results и vote ).

Функция render() первым аргументом принимает объект запроса, также название шаблона и необязательный словарь значений контекста. Возвращает объект HttpResponse содержащий выполненный шаблон с указанным контекстом.

Вызов 404 исключения¶

Теперь создадим страницу опроса, которая отображает вопрос и варианты ответа. Вот так будет выглядеть наше представление:

polls/views.py

from django.http import Http404 from django.shortcuts import render from .models import Question # . def detail(request, question_id): try: question = Question.objects.get(pk=question_id) except Question.DoesNotExist: raise Http404("Question does not exist") return render(request, 'polls/detail.html', 'question': question>) 

Представление вызывает исключение Http404 , если вопрос с указанным ID не существует.

Содержимое шаблона polls/detail.html обсудим позже, но если хотите прям вот сразу, чтобы все заработало, вот его содержимое:

polls/templates/polls/detail.html

 question >> 

чтобы можно было загрузить страницу.

Функция get_object_or_404()

Вызов get() и Http404 при отсутствии объекта – обыденные операции. Django предоставляет функцию, которая выполняет эти действия. Вот как будет выглядеть наше представление detail() :

polls/views.py

from django.shortcuts import get_object_or_404, render from .models import Question # . def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', 'question': question>) 

Функция get_object_or_404() первым аргументом принимает Django модель и произвольное количество именованных аргументов, которые передаются в метод get() менеджера модели. Если объект не найден, вызывается исключение Http404 .

Зачем мы используем функцию get_object_or_404() вместо того, чтобы автоматически перехватывать исключения ObjectDoesNotExist уровнем выше, или вызывать на уровне API моделей исключение Http404 вместо ObjectDoesNotExist ?

Потому что это связывает уровень моделей с уровнем представления. Один из главных принципов проектирования Django – слабая связанность. Некоторая связанная функциональность находится в модуле django.shortcuts .

Существует также функция get_list_or_404() , которая работает аналогично get_object_or_404() , но использует filter() вместо get() . Вызывает Http404 , если получен пустой список.

Использование системы шаблонов¶

Вернемся к представлению detail() . Вот как может выглядеть наш шаблон polls/detail.html , использующий контекстную переменную question :

polls/templates/polls/detail.html

  question.question_text >>   for choice in question.choice_set.all %>  choice.choice_text >>   endfor %>  

Система шаблонов использует точку для доступа к атрибутам переменной. Например, для > Django сначала пытается обратиться к question как к словарю. При неудаче ищется атрибут переменной, в данном случае он и используется. Если атрибут не найден, будет искаться индекс в списке.

Подробности о шаблонах смотрите в разделе о Языке шаблонов Django.

Избавляемся от “хардкода” URL-ов в шаблонах¶

Помните, когда мы указывали ссылку в шаблоне polls/index.html , она была прописана прямо в коде:

Проблема в том, что нам будет очень сложно поменять URL-ы в проекте с большим количеством шаблонов. Однако, так как мы указали названия при вызове url() в модуле polls.urls , мы можем ссылаться на шаблоны URL-ов используя шаблонный тег :

Определение URL-а будет найдено в модуле polls.urls . Вот где определен наш URL с названием ‘detail’:

. # the 'name' value as called by the template tag url(r'^(?P[0-9]+)/$', views.detail, name='detail'), . 

Теперь, если вы захотите поменять URL, например на polls/specifics/12/ , вам не придется менять все шаблоны, вы можете сделать это в polls/urls.py :

. # added the word 'specifics' url(r'^specifics/(?P[0-9]+)/$', views.detail, name='detail'), . 

Пространства имен в названиях URL-ов¶

Наш проект содержит только одно приложение polls . В реальных проектах может быть 5, 10, 20 и больше приложений. Как же Django понимает где чей URL по его названию? Например, приложение polls содержит представление detail , аналогичное представление может быть и в приложении для блогов. Как же Django понимает для какого представления создается URL при использовании тега ?

Для этого используются пространства имен в URLconf. Изменим polls/urls.py и добавим пространство имен в app_name :

polls/urls.py

from django.conf.urls import url app_name = 'polls' urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^(?P[0-9]+)/$', views.detail, name='detail'), url(r'^(?P[0-9]+)/results/$', views.results, name='results'), url(r'^(?P[0-9]+)/vote/$', views.vote, name='vote'), ] 

Теперь поменяем в шаблоне polls/index.html :

polls/templates/polls/index.html

чтобы использовать пространство имен URL-ов:

polls/templates/polls/index.html

Научившись создавать представления, перейдем к четвёртой части учебника, чтобы научиться обрабатывать формы и использовать встроенные представления.

Оглавление

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *