Django

5 (100%) 1 vote[s]

Восьмое занятие по веб-програмированию с python 3, посвященное Django. Django — гораздо более тяжелый веб-фреймворк, чем Flask, с гораздо большим количеством готовых функций, которые пришлось бы создавать вручную и многократно с помощью микро-фреймворка, например, такого как Flask.

Используя Django

Django делит все свои веб-приложения на «проекты», состоящие из разных частей. Чтобы начать новый проект, запустите django-admin startproject projectname.

Компоненты проекта

Джанго создает ряд файлов с новым проектом:

  • __init__.py: определяет каталог projectnameкак «пакет» Python, набор из нескольких файлов Python
    • Django построен на идее пакетов. Веб-приложение может состоять из нескольких пакетов, каждый из которых выполняет несколько разные задачи, и Django поможет управлять ими.
  • manage.py : скрипт Python, который можно использовать для выполнения полезных операций в веб-приложении
  • settings.py : основные настройки, такие как часовой пояс, другие приложения, установленные в проекте, какая база данных используется и т. д.
  • urls.py : определяет, какие URL / маршруты могут быть доступны при использовании веб-приложения
  • wsgi.py : файл, который помогает развернуть приложение на веб-сервере
  • project_name/ : каталог для проекта, который содержит все вышеперечисленные файлы по умолчанию

Проект Django состоит из одного или нескольких приложений Django или приложений, которые служат определенной цели.

Основное применение

  • Чтобы создать приложение, в каталоге проекта запустите python manage.py startapp appname. Это создаст каталог appnameвнутри каталога проекта. appnameбудет содержать несколько файлов автоматически.
  • Внутри appname, views.pyаналогично application.pyприложению Flask. Он содержит код, который определяет, что пользователь видит на определенном маршруте. Сначала это будет выглядеть так:
    1.   from django.shortcuts import render
    2.  
    3.   # Create your views here.
  • Все функции просмотра должны принимать requestобъект в качестве аргумента. Как и во Flask, этот объект будет содержать информацию о том, какие аргументы были переданы в запрос и т. Д. Представление baisc может просто вернуть простой HTTP-ответ.
    1.   from django.http import HttpResponse
    2.   from django.shortcuts import render
    3.  
    4.   # Create your views here.
    5.   def index(request):
    6.       return HttpResponse("Hello, world!")
  • Однако этот базовый вид не определяет, по какому маршруту он идет. Для этого urls.pyв appnameкаталоге должен быть создан новый urls.pyфайл (он отличается от файла уровня проекта с тем же именем). Каждое приложение часто имеет свои собственные маршруты, и эти отдельные данные urls.pyпомогают сигнализировать об этих различиях в функциональности, упорядочивать вещи и упрощают повторное использование приложений в других проектах. appname/urls.pyможет выглядеть так:
    1.   from django.urls import path
    2.  
    3.   from . import views
    4.  
    5.   urlpatterns = [
    6.       path("", views.index),
    7.   ]
  • from . import viewsимпортирует views.pyиз appnameкаталога, так что URL-адреса могут быть связаны с представлениями.
  • urlpatterns список всех URL-адресов, поддерживаемых этим приложением
  • "" указывает на пустой маршрут.
  • Когда проект Django запускается, он будет проверять только urls.pyна уровне проекта. Итак, последний шаг перед тем, как это базовое приложение будет фактически пригодным для использования, appname/urls.pyдолжен быть связан с проектом urls.py, который начинается с некоторого кода в нем.
    1.   from django.contrib import admin
    2.   from django.urls import include, path
    3.  
    4.   urlpatterns = [
    5.       path("admin/", admin.site.urls)
    6.   ]
  • Чтобы связать новый путь, просто добавьте путь к urlpatterns:
    1.   urlpatterns = [
    2.       path("", include("appname.urls")),
    3.       path("admin/", admin.site.urls)
    4.   ]
    • Причиной такой очевидной сложности является возможность маршрутизации между несколькими различными приложениями. Это urls.pyслужит отправной точкой для всех этих urls.pyфайлов более низкого уровня .
  • Чтобы запустить приложение, запустите python manage.py runserver.

Авиабилеты пересмотрены

  • Чтобы продемонстрировать Django более полно, в следующем примере будет реконструировано и расширено приложение приложения Flight Manager, изначально созданное с помощью Flask. Имя проекта будет djangoair, и оно будет содержать приложение под названием flights.
  • Для начала flights/urls.py:
    1.   from django.urls import path
    2.  
    3.   from . import views
    4.  
    5.   urlpatterns = [
    6.       path("", views.index),
    7.   ]
    • Эти URL должны быть связаны так djangoair/urls.pyже, как и в предыдущем примере.
  • flights/views.py:
    1.   from django.http import HttpResponse
    2.   from django.shortcuts import render
    3.  
    4.   # Create your views here
    5.   def index(request):
    6.       return HttpResponse("Flights")
  • Это приложение теперь находится в той же точке, что и предыдущий пример. Следующим шагом является добавление базы данных. Django был разработан для взаимодействия с данными, поэтому это очень легко сделать. flights/models.pyвыглядит вот так прямо сейчас:
    1.   from django.db import models
    2.  
    3.   # Create your models here
    • Это файл для определения классов, которые будут определять типы данных, хранящихся в базе данных. Информация, которая будет содержаться здесь, очень похожа на информацию, созданную с помощью Flask-SQLAlchemy.
  • Модель для полета может выглядеть так:
    1.   class Flight(models.Model):
    2.       origin = models.CharField(max_length=64)
    3.       destination = models.CharField(max_length=64)
    4.       duration = models.IntegerField()
    • Инертинг models.Modelпросто устанавливает этот класс как модель Джанго.
    • В Django есть несколько встроенных типов полей, которые, например, отображаются на разные типы данных в базе данных SQL.
  • Теперь, как и с новыми URL-адресами, модели должны быть связаны с проектом Django. В djangoair/settings.pyсписке есть список INSTALLED_APPS, предварительно заполненный установленными приложениями Django. Чтобы добавить flightsприложение, flights.apps.FlightsConfigдолжен быть добавлен в этот список.
    1.   INSTALLED_APPS = [
    2.       'flights.apps.FlightsConfig',
    3.       'django.contrib.admin',
    4.       'django.contrib.auth',
    5.       'django.contrib.contenttypes',
    6.       'django.contrib.sessions',
    7.       'django.contrib.messages',
    8.       'django.contrib.staticfiles',
    9.   ]
  • FlightsConfigэто класс, который определяет настройки flightsприложения.

Миграции

  • При создании веб-приложения очень редко будут определены все таблицы с правильными столбцами с самого начала. Обычно таблицы создаются по мере роста приложения, и база данных будет изменена. Было бы утомительно изменять код модели Django и запускать команды SQL для изменения базы данных.
  • Решение Джанго этой проблемы «миграция». Django автоматически обнаруживает и изменяет models.pyи автоматически генерирует необходимый код SQL для внесения необходимых изменений.
  • Чтобы создать таблицу для управления полетами внутри базы данных, запустите python manage.py makemigrations. Это будет просматривать файлы модели на предмет любых изменений и генерировать «миграцию», которая представляет необходимые изменения для базы данных. Выполнение этой команды создаст файл migrations/0001_initial.py:
    1.   # Generated by Django 2.0 on 2018-07-19 22:14
    2.  
    3.   from django.db import migrations, models
    4.  
    5.   class Migration(migrations.Migration):
    6.  
    7.       initial = True
    8.  
    9.       dependencies = [
    10.       ]
    11.  
    12.       operations = [
    13.           migrations.CreateModel(
    14.               name='Flight',
    15.               fields=[
    16.                   ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
    17.                   ('origin', models.CharField(max_length=64)),
    18.                   ('destination', models.CharField(max_length=64)),
    19.                   ('duration', models.IntegerField()),
    20.               ],
    21.           ),
    22.       ]
    • Внутри класса Migrationесть список operations, который содержит все, что должно происходить с базой данных. В этом случае модель Flightдолжна быть создана, с полями id, origin, destination, и duration.
    • Обратите внимание, что idникогда не было указано в models.py. Django добавляет этот столбец по умолчанию.
  • Команда python manage.py sqlmigrate flights 0001создаст код SQL, который фактически соответствует этой миграции. Эту команду не нужно запускать, но она полезна для демонстрации того, что на самом деле происходит. Команда SQL очень похожа на ту, что была показана ранее, но ее не нужно было писать. Все это генерируется системой миграции Django.
  • Чтобы на самом деле применить эту миграцию к базе данных, запустите python manage.py migrate, которая будет применять новую миграцию, а также некоторые из них по умолчанию Django.
  • База данных , которая фактически используется здесь определяется djangoair/settings.pyв DATABASESсловаре. По умолчанию он использует SQLite 3 (другую версию SQL, которая использует локальный файл для базы данных) и файл базы данных db.sqlite3.

Джанго Шелл

  • Django предоставляет оболочку, похожую на интерпретатор Python, которая позволяет напрямую изменять базу данных. Запустите оболочку, запустив python manage.py shell. Внутри оболочки можно запускать команды Python.
  • Чтобы создать новый полет, внутри оболочки можно выполнить следующие команды.
    1.   from flights.models import Flight
    2.  
    3.   f = Flight(origin="New York", destination="London", duration=415)
    4.   f.save()
    5.  
    6.   Flight.objects.all()
    7.   # Returns <QuerySet [<Flight: Flight object(1)>]>
    • f.save()аналогично SQL COMMIT.
    • А QuerySet, как список, с добавленной функциональностью.
  • Представление, QuerySetкоторое возвращает оболочка, на самом деле не читабельно и не полезно. Чтобы получить более полезное строковое представление полета, __str__в Flightкласс можно добавить функцию flights/models.py.
    1.   def __str__(self):
    2.       return f"{self.id} - {self.origin} to {self.destination}"
    • Для любого класса, не только в Django, __str__функция определяет, как должен выглядеть объект при печати, на терминале, на странице HTML и т. Д.
  • Вернуться к оболочке:
    1.   Flight.objects.all()
    2.   # Returns <QuerySet [<Flight: 1 - New York to London>]>
    3.  
    4.   f = Flight.objects.first()
    5.  
    6.   f
    7.   # Returns <Flight: 1 - New York to London>
    8.  
    9.   f.origin()
    10.   # Returns 'New York'
    11.  
    12.   f.id
    13.   # Returns 1
    14.  
    15.   f.delete()
    16.   # Deletes the flight as expected

Лучшие Модели

  • Более надежный дизайн для Flightмодели будет иметь поле идентификатора, которое ссылается на таблицу аэропортов, а не просто текст для происхождения и пунктов назначения. Для этого Airportсначала необходимо создать новую модель.
    1.   class Airport(models.Model):
    2.       code = models.CharField(max_length=3)
    3.       city = models.CharField(max_length=64)
    4.  
    5.       def __str__(self):
    6.           return f"{self.city} ({self.code})"
  • Затем Flightмодель может быть изменена соответствующим образом, с исходной и конечной точками ForeignKeys.
    1.   class Flight(models.Model):
    2.       origin = models.ForeignKey(Airport, on_delete=models.CASCADE, related_name="departures")
    3.       destination = models.ForeignKey(Airport, on_delete=models.CASCADE, related_name="arrivals")
    • Модели Django допускают определенное поведение, например, при удалении аэропорта. on_delete=models.CASCADEозначает, что в случае удаления аэропорта все рейсы с этим аэропортом в качестве пункта отправления или назначения также будут удалены.
    • related_nameпозволяет получить доступ ко всем рейсам, вылетающим из или прибывающим в конкретный аэропорт, используя ключи deparaturesили arrivals.
    • Обратите внимание, что нет буквальных определений происхождения и назначения в качестве идентификаторов, а также каких-либо фактических команд для того, как связать две таблицы. Единственное, что указано, это то, что originи destinationдолжно быть Airports. Вся работа по выполнению этого поручена Джанго.
  • Чтобы применить эти изменения, они должны быть перенесены так же, как и раньше. Теперь в оболочке намного проще и понятнее создавать полеты.
    1.   from flights.models import Airport, Flight
    2.  
    3.   jfk = Airport(code="JFK", city="New York City")
    4.   lhr = Airport(code="LHR", city="London")
    5.   jfk.save()
    6.   lhr.save()
    7.  
    8.   f = Flight(origin=jfk, destination=lhr, duration=415)
    9.   f.save()
    10.  
    11.   f.origin
    12.   # Returns <Airport: New York City (JFK)>
    13.  
    14.   f.origin.code
    15.   # Returns 'JFK'
    16.  
    17.   jfk.departures.all()
    18.   # Returns <QuerySet [<Flight: 1 - New York City (JFK) to London (LHR)>]>

Шаблоны рендеринга

  • Подобно Flask, для рендеринга HTML-шаблона, отрендеренный шаблон должен возвращаться функцией, которая обрабатывает маршрут. Для Джанго это в flights/views.py.
    1.   def index(request)
    2.       return render(request, "flights/index.html")
    • Второй аргумент render— это просто путь к шаблону, который будет отображаться.
    • Они должны храниться в пути примерно так: flights/templates/flights/index.html. Обратите внимание, что renderпуть начинается с templateпапки. Очевидная избыточность этого пути, хотя и не является строго необходимой в этом примере, является хорошей практикой, позволяющей избежать проблем, когда у нескольких приложений могут быть свои собственные index.html.
  • index.html может быть простым на данный момент.
    <html>
          <head>
              <title>Flights</title>
          </head>
          <body>
              <h1>Flights</h1>
          </body>
      </html>
  • Для отображения информации о рейсах можно использовать систему шаблонов Django, которая очень похожа на Jinja. Джанго передает информацию в шаблон через contextсловарь.
    1.   from .models import Flight
    2.  
    3.   def index(request)
    4.       context = {
    5.           "flights": Flights.objects.all()
    6.       }
    7.       return render(request, "flights/index.html", context)
    <body>
          <h1>Flights</h1>
          <ul>
                
              {% for flight in flights %}
                  <li>
                      {{ flight }}
                  </li>
              {% endfor %}
                
          </ul>
      </body>

Администратор

  • Admin — это встроенное приложение Django, которое позволяет легко добавлять или изменять существующие данные на веб-странице. Обратите внимание, что это задача, которая требует много кода во Flask. Это, пожалуй, одна из самых мощных функций Django, особенно когда речь идет о работе с данными и манипулировании ими.
  • flights/admin.py начинается так
    1.   from django.contrib import admin
    2.  
    3.   # Register your models here.
  • Добавить Airportи Flightмодели просто.
    1.   from django.contrib import admin
    2.  
    3.   from .models import Airpot, Flight
    4.  
    5.   # Register your models here.
    6.   admin.site.register(Airport)
    7.   admin.site.register(Flight)
    • Это позволяет администратору приложения управлять аэропортами и рейсами.
  • Чтобы получить доступ к сайту администратора через Интернет, пользователь должен войти в систему. Это одна задача, которая будет довольно утомительной во Flask, но, опять же, Django поставляется с этой встроенной функциональностью. Первый шаг заключается в создании «суперпользователя» счет с доступом ко всему: python manage.py createsuperuser. Затем Django запросит имя пользователя, адрес электронной почты и пароль. Затем эти данные будут занесены в таблицу пользователей, за которой полностью следит Django.
  • Сайт администратора уже связан по умолчанию в проекте urls.pyна admin/маршруте. На сайте администратора пользователь может войти в систему и манипулировать данными. Интерфейс администратора прост и удобен в навигации. Обратите внимание, что этот интерфейс администратора предназначен не для использования всеми пользователями веб-сайта, а скорее просто для управления контентом для таких вещей, как заполнение моделей и добавление информации, тогда как пользователи будут просматривать эту информацию на отдельно отображаемой странице.

Добавление большего количества маршрутов

  • Например, чтобы добавить больше маршрутов для конкретной информации о рейсе, нужно просто добавить URL-адреса flights/urls.pyвместе с соответствующим представлением flights/views.pyи шаблоном в templates/flights.
    1.   urlpatterns = [
    2.       path("", views.index),
    3.       path("<int:flight_id>", views.flight),
    4.   ]
    • Синтаксис для создания маршрутов, которые принимают аргументы, очень похож на синтаксис Flask.
      1.   def flight(request, flight_id):
      2.   try:
      3.       flight = Flight.objects.get(pk=flight_id)
      4.   except Flight.DoesNotExist:
      5.       raise Http404("Flight does not exist")
      6.   context = {
      7.       "flight": flight,
      8.   }
      9.   return render(request, "flights/flight.html", context)
    • Потому что flight_idбыл параметром в URL, flight_idпередается в flightпредставление.
    • pk обозначает «первичный ключ».
    • DoesNotExist это специальное исключение, встроенное в модели Django.
    • Http404это еще одна встроенная функция Django (импортированная из django.http), которая просто вызывает ошибку 404. « `html

    Flight {{flight.id}}

    • Происхождение: {{flight.origin}}
    • Пункт назначения: {{flight.destination}}

    « `

    • headсодержимое может быть таким же, как и index.htmlсейчас. Обратите внимание на текущую избыточность в шаблонах HTML.

Наследование шаблонов

  • Наследование шаблонов для HTML-страниц в Django работает почти так же, как и во Flask. Вот как base.htmlможет выглядеть универсальный шаблон :
    1.   <html>
    2.       <head>
    3.           <title>{% block title %}{% endblock %}</title>
    4.       </head>
    5.       <body>
    6.           {% block body %}
    7.           {% endblock %}
    8.       </body>
    9.   </html>
  • Теперь index.htmlи flight.htmlможно упростить.
    1.   {% extends "flight/base.html" %}
    2.  
    3.   {% block title %}
    4.       Flights
    5.   {% endblock %}
    6.  
    7.   {% body block %}
    8.       <h1>Flights</h1>
    9.       <uL>
    10.           {% for flight in flights $}
    11.               <li>
    12.                   <a href="{% for flight in flights $}
    13.               <li>
    14.                   <a href="{% url 'flight' flight.id %}">{{ flight }}</a>
    15.               </li>
    16.           {% endfor %}
    17.       </ul>
    18.   {% endblock %}

    и

    1.   {% extends "flight/base.html" %}
    2.  
    3.   {% block title %}
    4.       Flight {{ flight.id }}
    5.   {% endblock %}
    6.       <h1>Flight {{ flight.id }}</h1>
    7.       <ul>
    8.           <li>Origin: {{ flight.origin }}</li>
    9.           <li>Destination: {{ flight.destination }}</li>
    10.       </ul>
    11.       <a href="{% url 'index' %}">Back to full listing</a>
    12.   {% block body %}
    13.  
    14.   {% endblock %}

Модельные Отношения

  • Раньше с помощью Flask и SQL для связи пассажиров с рейсами в таблице пассажиров был столбец идентификатора рейса, чтобы каждый пассажир мог быть связан с рейсом. Проблема этого подхода заключается в том, что каждый пассажир может находиться только на одном рейсе. Что является более желательным, так это отношения «многие ко многим», когда пассажир может совершать несколько рейсов, а рейс может иметь несколько пассажиров. Обычной парадигмой для этого является реализация «промежуточной таблицы», которая просто имеет два столбца, один для идентификатора пассажира и один для идентификатора рейса, с таким количеством строк, сколько необходимо. Django допускает это, но выполняет автоматическую реализацию промежуточной таблицы.
  • Первым шагом является внедрение модели пассажира в России flights/models.py.
    1.   class Passenger(models.Model):
    2.       first = models.CharField(max_length=64)
    3.       last = models.CharField(max_length=64)
    4.       flights = models.ManyToManyField(Flight, blank=True, related_name="passengers")
    5.  
    6.       def __str__(self):
    7.           return f"{self.first} {self.last}"
    • Раньше, когда связывались две таблицы, models.ForeignKeyиспользовался. models.ManyToManyFieldучитывает желаемое поведение отношений «многие ко многим».
    • blank=True позволяет пассажиру быть связанным без полетов.
    • Как и раньше, related_nameпозволяет опрашивать всех пассажиров данного рейса.
  • Обновление базы данных, как и прежде, с python manage.py makemigrationsпроверкой SQL и проверкой на python manage.py sqlmigrate flights 0003наличие кода позволяет выявить код для создания flights_passengersуказанной таблицы , а также таблицу flights_passengers_flights, которая не была указана, но является таблицей, созданной автоматически.
  • После завершения миграции python manage.py migrateможно использовать оболочку, чтобы опробовать эти новые модели.
    1.   from flights.models import Flight, Passenger
    2.  
    3.   f = Flight.objects.get(pk=1)
    4.   f
    5.   # Returns <Flight: 1 - New York City (JFK) to London (LHR)>
    6.  
    7.   p = Passenger(first="Alice", last="Adams")
    8.   p.save()
    9.  
    10.   p.flights.add(f)
    11.   p.flights.all()
    12.   # Returns <QuerySet [<Flight: 1 - New York City (JFK) to London (LHR)>]>
    13.  
    14.   f.passengers.all()
    15.   # Returns <QuerySet [<Passenger: Alice Adams>]>
  • flightВид и соответствующий HTML могут быть обновлены до сих пор отображения пассажирской информации.
    1.   def flight(request, flight_id):
    2.       try:
    3.           flight = Flight.objects.get(pk=flight_id)
    4.       except Flight.DoesNotExist:
    5.           raise Http404("Flight does not exist")
    6.       context = {
    7.           "flight": flight,
    8.           "passengers": flight.passengers.all(),
    9.       }
    10.       return render(request, "flights/flight.html", context)

    и

    1.   <h2>Passengers</h2>
    2.   <ul>
    3.       {% for passenger in passengers %}
    4.           <li>{{ passenger }}</li>
    5.       {% empty %}
    6.           <li>No passengers</li>
    7.       {% endfor %}
    8.   </ul>
    • {% empty %}выполняется если passengersпусто
  • PassengerМодель также может быть добавлен администратором и изменение приложения администратора в то же самое было и раньше.

Регистрация пользователя

  • Первым шагом к созданию веб-интерфейса пользователя для использования регистрации полета может быть создание нового маршрута вместе с соответствующим представлением и шаблоном HTML.
    1.   urlpatterns = [
    2.       path("", views.index, name="index"),
    3.       path("<int:flight_id>", views.flight, name="flight"),
    4.       path("<int:flight_id>/book", views.book, name="book")
    5.   ]
    1.   def book(request, flight_id):
    2.       try:
    3.           passenger_id = int(request.POST["passenger"])
    4.           flight = Flight.objects.get(pk=flight_id)
    5.           passenger = Passenger.objects.get(pk=passenger_id)
    6.       except KeyError:
    7.           return render(request, "flights/error.html", {"message": "No selection."})
    8.       except Flight.DoesNotExist:
    9.           return render(request, "flights/error.html", {"message": "No flight."})
    10.       except Passenger.DoesNotExist:
    11.           return render(request, "flights/error.html", {"message": "No passenger."})
    12.       passenger.flights.add(flight)
    13.       return HttpResponseRedirect(reverse("flight", args=(flight_id,)))
    • Этот код написан в предположении, что пользователь отправит веб-форму через POSTзапрос с именем одного аргумента passenger.
    • A KeyErrorбудет сгенерирован, если либо POSTзапрос не был отправлен, либо passengerаргумент не был предоставлен, не оставляя данных для извлечения.
    • flights/error.html будет новый общий шаблон для отображения любого количества сообщений об ошибках.
    • HttpResponseRedirect(импортировано из django.http) используется для отправки пользователя на его страницу полета после его регистрации.
    • reverse()(импортировано из django.urls) возвращает URL с указанием имени маршрута. Аргументы также могут быть переданы в виде кортежа.
  • Предполагая, что создание пассажира — это отдельный процесс от регистрации пассажира на рейс, когда пользователь собирается зарегистрироваться на рейс, он должен иметь возможность выбирать только из созданных пассажиров. Для этого все «не пассажиры» на рейсе должны быть переданы в flight.htmlшаблон.
    1.   def flight(request, flight_id):
    2.       try:
    3.           flight = Flight.objects.get(pk=flight_id)
    4.       except Flight.DoesNotExist:
    5.           raise Http404("Flight does not exist")
    6.       context = {
    7.           "flight": flight,
    8.           "passengers": flight.passengers.all(),
    9.           "non_passengers": Passenger.objects.exclude(flights=flight).all()
    10.       }
    11.       return render(request, "flights/flight.html", context)
    • Passenger.objectsвозвращает все пассажирские объекты, которые затем могут быть отфильтрованы различными способами. excludeудаляет объекты с определенным свойством; в этом случае все пассажиры на текущем рейсе исключаются.
  1. {% if non_passengers %}
  2.     <h2>Add a Passenger</h2>
  3.     <form action="{% url 'book' flight.id %}" method="post">
  4.         <select name="passenger">
  5.             {% for passenger in non_passengers %}
  6.                 <option value="{{ passenger.id }}">{{ passenger }}</option>
  7.             {% endfor %}
  8.         </select>
  9.         <input type="submit" value="Book Flight" />
  10.     </form>
  11. {% else %}
  12.     <div>No passengers to add.</div>
  13. {% endif %}
  • Вмещающий ifблок допускает регистрацию, только если есть кто-то, чтобы зарегистрироваться.
  • Здесь passenger selectэлементом являются соответствующие данные, которые отправляются обратно в bookпредставление, а внутри passengerpassenger.idэто то, что ожидается.

Подделка межсайтовых запросов

  • Несмотря на то, что функциональность бронирования выглядит почти полной, при отправке регистрационной формы Django не разрешит перенаправить пользователя на страницу своего рейса и вместо этого выдаст 403 Запрещенную ошибку: CSRF verification failed. Request aborted.CSRF (Подделка межсайтовых запросов) — потенциальная защита уязвимость в формах, из-за которой кто-то может подделать, откуда исходит форма. Django встроен для защиты от подобных атак. Тем не менее, чтобы учесть это, при работе с формой в Django нужно добавить немного дополнительного синтаксиса.
  1. <form action="{% url 'book' flight.id %}" method="post">
  2.     {% csrf_token %}
  3.     <select name="passenger">
  4.         {% for passenger in non_passengers %}
  5.             <option value="{{ passenger.id }}">{{ passenger }}</option>
  6.         {% endfor %}
  7.     </select>
  8.     <input type="submit" value="Book Flight" />
  9. </form>
  • Когда форма отправляется, вместе с ней передается токен CSRF, чтобы Django мог проверить, действительно ли веб-приложение отправляет запрос.

Модификация Admin

  • Интерфейс администратора Django может быть расширен, чтобы учесть пользовательское поведение. Возвращаясь к примеру с рейсами, вот как это flights/admin.pyможно изменить.
    1.   from django.contrib import admin
    2.  
    3.   from .models import Airport, Flight, Passenger
    4.  
    5.   # Register your models here.
    6.  
    7.   class PassengerInline(admin.StackedInline):
    8.       model = Passenger.flights.through
    9.       extra = 1
    10.  
    11.   class FlightAdmin(admin.ModelAdmin):
    12.       inlines = [PassengerInline]
    13.  
    14.   class PassengerAdmin(admin.ModelAdmin):
    15.       filter_horizontal = ("flights",)
    16.  
    17.   admin.site.register(Airport)
    18.   admin.site.register(Flight, FlightAdmin)
    19.   admin.site.register(Passenger, PassengerAdmin)
    • Поскольку Flightsмодель не имеет ссылки на Passengers, управление полетами в приложении администратора не позволяет добавлять или удалять пассажиров так же, как рейсы могут быть добавлены или удалены пассажиру. Это может быть решено путем создания PassengerInlineкласса, который наследуется от встроенного класса, StackedInlineкоторый позволяет добавлять новые отношения между объектами. PassengerInlineпредставляет собой место в пользовательском интерфейсе, где пассажиры рейса могут быть изменены.
    • Passenger.flights.throughотносится к промежуточной таблице, связывающей рейсы и пассажиров. При установке modelэтой промежуточной таблицы эта таблица ассоциируется с PassengerInline.
    • extra = 1 устанавливает количество пассажиров, которое может быть отредактировано за один раз, до 1.
    • FlightAdminэто новый класс, который наследуется от ModelAdminи содержит специальный набор конфигураций, которые будут использоваться только при редактировании пассажиров. Эти параметры применяются при пропускании FlightAdminкadmin.site.regiser.
    • inlinesсодержит все дополнительные встроенные разделы модификации для страницы администратора, которая в данном случае содержит только PassengerInline.
    • filter_horizontalпомогает управлять рейсами пассажира. Он просто позволяет добавить дополнительный элемент пользовательского интерфейса в приложение администратора, чтобы упростить добавление или удаление рейсов, на которых находится пассажир.

Статические файлы

  • Чтобы использовать внешние статические файлы, такие как .cssили .jsфайлы, необходимо использовать специальный синтаксис Django. Базовый шаблон со статическими файлами может выглядеть так:
  1. {% load static %}
  2.  
  3. <span class="cp"><!DOCTYPE html>
  4. <html>
  5.     <head>
  6.         <title>{% block title %}{% endblock %}</title>
  7.         <link rel="stylesheet" href="{% static 'flights/styles.css' %}"/>
  8.     </head>
  9.     <body>
  10.         {% block body %}
  11.         {% endblock %}
  12.     </body>
  13. </html>
  1. * `{% load static %}` allows for the use of static files.
  2. * Any static file must have its `href` formattaed as `"{% static 'path/static.css' %}"`. * Inside of the application directory (e.g. `flights`), there should be a `static` directory containing a directory for the application which in turn contains any static files. So, the entire hierarchy would look like `flights/static/flights/styles.css`. This is exactly analogous to how templates are stored.

Логин и Аутентификация

  • Аутентификация и авторизация — это встроенное приложение, предназначенное для обработки учетных записей пользователей и входа в систему. Этот последний пример показывает эту систему учетных записей в приложении под названием users. users/urls.pyвыглядит так:
    1.   from django.urls import path
    2.  
    3.   from . import views
    4.  
    5.   urlpatterns = [
    6.       path("", views.index, name="index"),
    7.       path("login", views.login_view, name="login"),
    8.       path("logout", views.logout_view, name="logout")
  • users/views.py:
    1.   from django.contrib.auth import authenticate, login, logout
    2.   from django.http import HttpResponse, HttpResponseRedirect
    3.   from django.shortcuts import render
    4.   from django.urls import reverse
    5.  
    6.   # Create your views here.
    7.  
    8.   def index(request):
    9.       if <span class="ow">not request.user.is_authenticated:
    10.           return render(request, "users/login.html", {"message": None})
    11.       context = {
    12.           "user": request.user
    13.       }
    14.       return render(request, "users/user.html", context)
    15.  
    16.   def login_view(request):
    17.       username = request.POST["username"]
    18.       password = request.POST["password"]
    19.       user = authenticate(request, username=username, password=password)
    20.       if user <span class="ow">is <span class="ow">not None:
    21.           login(request, user)
    22.           return HttpResponseRedirect(reverse("index"))
    23.       else:
    24.           return render(request, "users/login.html", {"message": "Invalid credentials."})
    25.  
    26.   def logout_view(request):
    27.       logout(request)
    28.       return render(request, "users/login.html", {"message": "Logged out."})
    • django.contrib.authявляется пакет аутентификации Джанго, который содержит Userмодель, наряду с функциями authenticate, loginи logout.
    • request.user.is_authenticatedявляется trueли пользователь вошел в систему . Если они не вошли в систему , они redirectd на страницу входа в систему . Если они есть, пользователь направляется на свою страницу пользователя.
    • login_viewсначала проверяет, существует ли пользователь authenticate, принимает имя пользователя и пароль и возвращает этот объект пользователя.
    • login берет пользователя и регистрирует его в системе аутентификации.
    • logout просто выходит из системы
  • login.html:
  1. {% block body %}
  2. <h1>Login</h1>
  3. {% if message %}
  4.     <div>
  5.         {{ message }}
  6.     </div>
  7. {% endif %}
  8. <form action="{% url 'login' %}" method="post">
  9.     {% csrf_token %}
  10.     <input name="username" type="text"/>
  11.     <input name="password" type="password"/>
  12.     <input type="submit" value="Login"/>
  13. </form>
  14. {% endblock %}
  • user.html:
  1. {% block body %}
  2. <h1>Hello, {{ user.first_name }}</h1>
  3. <ul>
  4.     <li>Currently logged in as: {{ user.username }}</li>
  5.     <li><a href="{% url 'logout' %}">Logout</a></li>
  6. </ul>
  7. {% endblock %}
  • UserСодержит поля , такие как first_name, last_name, usernameи т.д., но также может быть продлен.
  • Регистрация нового пользователя влечет за собой добавление нового пользователя в базу данных. Это можно сделать через интерфейс администратора с учетной записью суперпользователя или с помощью оболочки:
    1.   from django.contrib.auth.models import User
    2.  
    3.   user = User.objects.create_user("alice", "alice@something.com", "alice12345")
    4.  
    5.   user.first_name = "Alice"
    6.  
    7.   user.save()
  • create_user принимает аргументы имя пользователя, адрес электронной почты, пароль.

Читайте больше по теме:

Подписаться
Уведомление о
guest
0 комментариев
Inline Feedbacks
View all comments
Просмотры: 335

Популярные записи