Django пошаговое руководство

Writing your first Django app, part 1¶

Let’s learn by example.

Throughout this tutorial, we’ll walk you through the creation of a basic
poll application.

It’ll consist of two parts:

  • A public site that lets people view polls and vote in them.
  • An admin site that lets you add, change, and delete polls.

We’ll assume you have Django installed already. You can
tell Django is installed and which version by running the following command
in a shell prompt (indicated by the $ prefix):

/

$ python -m django --version
...> py -m django --version

If Django is installed, you should see the version of your installation. If it
isn’t, you’ll get an error telling “No module named django”.

This tutorial is written for Django 4.2, which supports Python 3.8 and
later. If the Django version doesn’t match, you can refer to the tutorial for
your version of Django by using the version switcher at the bottom right corner
of this page, or update Django to the newest version. If you’re using an older
version of Python, check What Python version can I use with Django? to find a compatible
version of Django.

See How to install Django for advice on how to remove
older versions of Django and install a newer one.

Where to get help:

If you’re having trouble going through this tutorial, please head over to
the Getting Help section of the FAQ.

Creating a project¶

If this is your first time using Django, you’ll have to take care of some
initial setup. Namely, you’ll need to auto-generate some code that establishes a
Django project – a collection of settings for an instance of Django,
including database configuration, Django-specific options and
application-specific settings.

From the command line, cd into a directory where you’d like to store your
code, then run the following command:

/

$ django-admin startproject mysite
...> django-admin startproject mysite

This will create a mysite directory in your current directory. If it didn’t
work, see Problems running django-admin.

Note

You’ll need to avoid naming projects after built-in Python or Django
components. In particular, this means you should avoid using names like
django (which will conflict with Django itself) or test (which
conflicts with a built-in Python package).

Where should this code live?

If your background is in plain old PHP (with no use of modern frameworks),
you’re probably used to putting code under the web server’s document root
(in a place such as /var/www). With Django, you don’t do that. It’s
not a good idea to put any of this Python code within your web server’s
document root, because it risks the possibility that people may be able
to view your code over the web. That’s not good for security.

Put your code in some directory outside of the document root, such as
/home/mycode.

Let’s look at what startproject created:

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

These files are:

  • The outer mysite/ root directory is a container for your project. Its
    name doesn’t matter to Django; you can rename it to anything you like.
  • manage.py: A command-line utility that lets you interact with this
    Django project in various ways. You can read all the details about
    manage.py in django-admin and manage.py.
  • The inner mysite/ directory is the actual Python package for your
    project. Its name is the Python package name you’ll need to use to import
    anything inside it (e.g. mysite.urls).
  • mysite/__init__.py: An empty file that tells Python that this
    directory should be considered a Python package. If you’re a Python beginner,
    read more about packages in the official Python docs.
  • mysite/settings.py: Settings/configuration for this Django
    project. Django settings will tell you all about how settings
    work.
  • mysite/urls.py: The URL declarations for this Django project; a
    “table of contents” of your Django-powered site. You can read more about
    URLs in URL dispatcher.
  • mysite/asgi.py: An entry-point for ASGI-compatible web servers to
    serve your project. See How to deploy with ASGI for more details.
  • mysite/wsgi.py: An entry-point for WSGI-compatible web servers to
    serve your project. See How to deploy with WSGI for more details.

The development server¶

Let’s verify your Django project works. Change into the outer mysite directory, if
you haven’t already, and run the following commands:

/

$ python manage.py runserver
...> py manage.py runserver

You’ll see the following output on the command line:

Performing system checks...

System check identified no issues (0 silenced).

You have unapplied migrations; your app may not work properly until they are applied.
Run 'python manage.py migrate' to apply them.

April 22, 2023 - 15:50:53
Django version 4.2, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Note

Ignore the warning about unapplied database migrations for now; we’ll deal
with the database shortly.

You’ve started the Django development server, a lightweight web server written
purely in Python. We’ve included this with Django so you can develop things
rapidly, without having to deal with configuring a production server – such as
Apache – until you’re ready for production.

Now’s a good time to note: don’t use this server in anything resembling a
production environment. It’s intended only for use while developing. (We’re in
the business of making web frameworks, not web servers.)

Now that the server’s running, visit http://127.0.0.1:8000/ with your web
browser. You’ll see a “Congratulations!” page, with a rocket taking off.
It worked!

Changing the port

By default, the runserver command starts the development server
on the internal IP at port 8000.

If you want to change the server’s port, pass
it as a command-line argument. For instance, this command starts the server
on port 8080:

/

$ python manage.py runserver 8080
...> py manage.py runserver 8080

If you want to change the server’s IP, pass it along with the port. For
example, to listen on all available public IPs (which is useful if you are
running Vagrant or want to show off your work on other computers on the
network), use:

/

$ python manage.py runserver 0.0.0.0:8000
...> py manage.py runserver 0.0.0.0:8000

Full docs for the development server can be found in the
runserver reference.

Automatic reloading of runserver

The development server automatically reloads Python code for each request
as needed. You don’t need to restart the server for code changes to take
effect. However, some actions like adding files don’t trigger a restart,
so you’ll have to restart the server in these cases.

Creating the Polls app¶

Now that your environment – a “project” – is set up, you’re set to start
doing work.

Each application you write in Django consists of a Python package that follows
a certain convention. Django comes with a utility that automatically generates
the basic directory structure of an app, so you can focus on writing code
rather than creating directories.

Projects vs. apps

What’s the difference between a project and an app? An app is a web
application that does something – e.g., a blog system, a database of
public records or a small poll app. A project is a collection of
configuration and apps for a particular website. A project can contain
multiple apps. An app can be in multiple projects.

Your apps can live anywhere on your Python path. In
this tutorial, we’ll create our poll app in the same directory as your
manage.py file so that it can be imported as its own top-level module,
rather than a submodule of mysite.

To create your app, make sure you’re in the same directory as manage.py
and type this command:

/

$ python manage.py startapp polls
...> py manage.py startapp polls

That’ll create a directory polls, which is laid out like this:

polls/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

This directory structure will house the poll application.

Write your first view¶

Let’s write the first view. Open the file polls/views.py
and put the following Python code in it:

polls/views.py

from django.http import HttpResponse


def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")

This is the simplest view possible in Django. To call the view, we need to map
it to a URL — and for this we need a URLconf.

To create a URLconf in the polls directory, create a file called urls.py.
Your app directory should now look like:

polls/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    urls.py
    views.py

In the polls/urls.py file include the following code:

polls/urls.py

from django.urls import path

from . import views

urlpatterns = [
    path("", views.index, name="index"),
]

The next step is to point the root URLconf at the polls.urls module. In
mysite/urls.py, add an import for django.urls.include and insert an
include() in the urlpatterns list, so you have:

mysite/urls.py

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("polls/", include("polls.urls")),
    path("admin/", admin.site.urls),
]

The include() function allows referencing other URLconfs.
Whenever Django encounters include(), it chops off whatever
part of the URL matched up to that point and sends the remaining string to the
included URLconf for further processing.

The idea behind include() is to make it easy to
plug-and-play URLs. Since polls are in their own URLconf
(polls/urls.py), they can be placed under “/polls/”, or under
“/fun_polls/”, or under “/content/polls/”, or any other path root, and the
app will still work.

When to use include()

You should always use include() when you include other URL patterns.
admin.site.urls is the only exception to this.

You have now wired an index view into the URLconf. Verify it’s working with
the following command:

/

$ python manage.py runserver
...> py manage.py runserver

Go to http://localhost:8000/polls/ in your browser, and you should see the
text “Hello, world. You’re at the polls index.”, which you defined in the
index view.

Page not found?

If you get an error page here, check that you’re going to
http://localhost:8000/polls/ and not http://localhost:8000/.

The path() function is passed four arguments, two required:
route and view, and two optional: kwargs, and name.
At this point, it’s worth reviewing what these arguments are for.

path() argument: route

route is a string that contains a URL pattern. When processing a request,
Django starts at the first pattern in urlpatterns and makes its way down
the list, comparing the requested URL against each pattern until it finds one
that matches.

Patterns don’t search GET and POST parameters, or the domain name. For example,
in a request to https://www.example.com/myapp/, the URLconf will look for
myapp/. In a request to https://www.example.com/myapp/?page=3, the
URLconf will also look for myapp/.

path() argument: view

When Django finds a matching pattern, it calls the specified view function with
an HttpRequest object as the first argument and any
“captured” values from the route as keyword arguments. We’ll give an example
of this in a bit.

path() argument: kwargs

Arbitrary keyword arguments can be passed in a dictionary to the target view. We
aren’t going to use this feature of Django in the tutorial.

path() argument: name

Naming your URL lets you refer to it unambiguously from elsewhere in Django,
especially from within templates. This powerful feature allows you to make
global changes to the URL patterns of your project while only touching a single
file.

When you’re comfortable with the basic request and response flow, read
part 2 of this tutorial to start working with the
database.

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

Обзор проекта

Мы создадим многопользовательский блог для клуба любителей задач Python Bytes. Вместе со стандартным пакетом Django будем использовать модули django-crispy-forms и Pillow. Реализуем всю функциональность, необходимую для:

  • регистрации и авторизации участников;
  • автоматического создания пользовательских профилей;
  • заполнения и изменения информации в профилях;
  • автоматического сжатия изображений для аватарок;
  • создания, редактирования и удаления записей со стороны фронтенда;
  • пагинации и вывода записей на страницах авторов.

Готовое приложение

Готовое приложение

Установим Django в виртуальное окружение с помощью менеджера pipenv:

        C:UsersUser>d:
D:>mkdir Django
D:>cd django
D:>mkdir .venv
D:django>pipenv install django

    

Размер пакета – чуть менее 9 Мб. Команда pipenv install django установит Django самой последней версии. Если нужна одна из предыдущих версий, следует явно указать ее номер: pipenv install django==3.2

Виртуальное окружение активируют командой pipenv shell, после чего перед названием директории появляется (.venv).

В дальнейшем перед началом работы над проектом нужно каждый раз активировать виртуальное окружение этой же командой, pipenv shell.

Создание проекта

Для автоматической генерации структуры и управляющих скриптов проекта выполняют команду: django-admin startproject my_site .

После чего папка my_site с базовой структурой появится в директории Django. Точка после команды предотвращает создание дополнительной вложенной папки в my_site. С другой стороны, если не использовать точку, все разрабатываемые приложения будут вложены в папку конкретного проекта, и во многих случаях такая структура удобнее, поскольку каждый проект может содержать множество приложений – блог, онлайн-магазин и т. д. Очень полезная особенность Django состоит в том, что все эти приложения будут вполне независимыми друг от друга, и например, однажды разработанный блог или магазин можно будет без проблем вставить в другой проект.

После создания проекта можно запустить сервер python manage.py runserver и открыть страницу в браузере:

Django успешно установлен

Django успешно установлен

При этом в терминале наверняка появится сообщение вроде этого:

        You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions. 
    

Пока что ничего с ним делать не нужно.

Первый этап разработки

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

Создание приложения, представлений и маршрутов

Чтобы создать папку и базовую структуру для будущего приложения, выполните python manage.py startapp blog. Название приложения не должно совпадать с названием папки проекта, иначе возникнет ошибка:

        CommandError: '%app%' conflicts with the name of an existing Python module and cannot be used as an app name. Please try another name.
    

То есть если вы назвали папку проекта my_site, приложение должно называться по-другому – например, blog. Чтобы посмотреть структуру проекта с вложенными в него приложениями, выполните tree.

Теперь открываем файл blogview.py. Здесь располагаются функции представления, которые обеспечивают функционирование логики приложения. В файле уже есть одна строка from django.shortcuts import render. Добавим обработку https запросов и функции представления для страниц Главная и Наш клуб. В итоге содержимое должно выглядеть так:

        from django.shortcuts import render
from django.http import HttpResponse
def home(request):
	return HttpResponse('<h1>Главная</h1>')
 
def about(request):
	return HttpResponse('<h1>Наш клуб</h1>')

    

Это тестовый код, в дальнейшем мы его изменим.

Теперь в папке blog создадим файл urls.py, чтобы приложение могло сопоставить маршруты и страницы. Добавим туда код:

        from django.urls import path
from . import views
urlpatterns = [
	path('', views.home, name='blog-home'),
	path('about/', views.about, name='about-club'),
]

    

После этого откройте файл urls.py, который находится в папке проекта my_site и добавьте в импорт include, а в urlpatterns – путь к ссылкам приложения blog:

        from django.contrib import admin
from django.urls import path, include
 
urlpatterns = [
	path('admin/', admin.site.urls),
	path('', include('blog.urls')),
]

    

Строка path('', include('blog.urls')) делает страницу блога домашней (главной). Если же блог является лишь одним из разделов портала, следует явно указывать маршрут к нему: path('blog', include('blog.urls')).

Запустим сервер python manage.py runserver и откроем адреса http://localhost:8000/ и http://localhost:8000/about/ – все работает: на домашней странице выводится надпись Главная, на странице about.html – название нашего клуба.

Шаблоны в Джанго

Чтобы страницы выглядели интереснее, чем простые надписи на белом фоне, нужно подключить шаблоны. По умолчанию Джанго будет искать шаблоны в папке templates директории blog. Создадим templates, a внутри нее поддиректорию с тем же названием, что и приложение – blog. Это стандартная практика: так Django понимает, что шаблоны относятся именно к приложению blog. Внутри папки templatesblog создайте три файла base.html, home.html и about.html. Сохраните в них код, который нужно взять здесь: base.html; home.html; about.html.

На одном уровне с templates создайте папку static, а внутри нее еще одну одноименную с приложением поддиректорию blog – в ней будeт размещаться css-файл main.css, который переопределяет стили Bootstrap. Подробный процесс создания шаблонов выходит за рамки этого туториала. На этом этапе достаточно знать, что шаблоны в Джанго состоят из комбинации html, css, JavaScript, логики и переменных, которые заключаются в фигурные скобки {% %} и {{ }} соответственно.

Рассмотрим несколько примеров.

Шаблон home.html начинается с {% extends "blog/base.html" %} – потому что основным шаблоном является base.html: в нем подключены стили, скрипты и шрифты. Чтобы не повторять этот код многократно, используется наследование, и шаблон home.html расширяет base.html, используя весь его код.

Блоки контента (шаблон может получать контент из других шаблонов) заключаются в скобки с процентным символом {% %}:

        {% block content %}
{% endblock %}

    

В отличие от Python, шаблонизатор Django нуждается в четком указании на окончание цикла:

        {% for post in posts %}
{% endfor %}

    

То же самое касается условий:

        {% if object.author == user %}
{% endif %}

    

Условия и циклы, как и в Python, можно комбинировать:

              	{% if messages %}
        	{% for message in messages %}
          	<div class="alert alert-{{ message.tags }}">
            	{{ message }}
              </div>
        	{% endfor %}
      	{% endif %}
    

Шаблонизатор использует свою систему фильтров данных по самым разным критериям; фильтр объявляется символом |:

        {{ post.date_posted|date:"F d, Y" }}
    

Переменные, которые Django получает из функций, классов или файлов конфигурации, вводятся в шаблон при помощи двойных фигурных скобок:

        {{ post.author }}
{{ title }}
{{ object.author }}

    

Логика шаблонизатора Django напоминает Python, но все же отличается от него. Для создания шаблона не нужно обладать всеми навыками фронтендера – всегда можно воспользоваться готовым Bootstrap шаблоном. Достаточно знать, как вставлять в готовые html-шаблоны логику и переменные, и как происходит наследование шаблонов и включение фрагментов контента из одного шаблона в другие. Наш шаблон основан на Bootstrap 4: ссылка на соответствующую версию подключается в head.

Базовая настройка конфигурации

Теперь займемся конфигурацией. Откройте файл blogapps.py и скопируйте оттуда название класса BlogConfig. Это название нужно вставить в файл settings.py нашего проекта my_site, как показано ниже:

        INSTALLED_APPS = [
	'blog.apps.BlogConfig',
	'django.contrib.admin',
	'django.contrib.auth',
	'django.contrib.contenttypes',
	'django.contrib.sessions',
	'django.contrib.messages',
	'django.contrib.staticfiles',
]

    

Откройте blogviews.py. Добавим тестовый контент и обработку шаблонов:

        from django.shortcuts import render
posts = [
	{
    	'author': 'Администратор',
    	'title': 'Это первый пост',
    	'content': 'Содержание первого поста.',
    	'date_posted': '12 мая, 2022'
	},
	{
    	'author': 'Пользователь',
    	'title': 'Это второй пост',
    	'content': 'Подробное содержание второго поста.',
    	'date_posted': '13 мая, 2022'
	}
]
 
def home(request):
	context = {
    	'posts': posts
	}
	return render(request, 'blog/home.html', context)
 
def about(request):
	return render(request, 'blog/about.html', {'title': 'О клубе Python Bytes'})

    

Шаблон home.html уже содержит ссылки на переменные, перечисленные в списке словарей posts. Запустим сервер и оценим работу шаблонов home.html и about.html. Напоминаем, что весь код для этого этапа можно взять здесь.

Вывод тестового контента

Вывод тестового контента

Подведем промежуточные итоги

У нас есть скелет приложения и основные шаблоны. На следующем этапе мы займемся администрированием, созданием учетных записей и ограничением доступа для неавторизованных пользователей.

***

Материалы по теме

  • 🐍 Самый полный видеокурс по Django от установки до проекта
  • 🐍 10 лучших материалов для изучения Django
  • 🔩 Полный фуллстек: пишем сайт на Django, Vue и GraphQL

Напишем простое веб-приложение на Django.

Джанго — это Open Source фреймворк для создания веб-приложений различной сложности на Python. Одним из его основных преимуществ является то, что вам нужно позаботиться только о логике будущего веб-приложения, остальное сделает Django.

Мы создадим приложение, у которого будет панель администратора и возможность загружать загадки, а у пользователей, соответственно, возможность отвечать на них. Во время разработки будут использоваться Python 3.4.3 и Django 1.9.1.

  1. Устанавливаем Django
  2. Создаём проект

Устанавливаем Django

Делается это очень просто, в командной строке нужно написать: pip install Django==1.9.1.

Создаём проект

Если вы правильно установили Django, то после запуска django-admin --version вы увидите текущую версию фреймворка. Теперь создадим проект. Это можно сделать следующим образом: django-admin startproject django_example.

Как только создание проекта будет завершено, взглянем на директорию нашего проекта:

  • django_example/__init__.py — пустой файл, который говорит Python, что данная директория должна восприниматься в качестве пакета.
  • django_example/settings.py содержит конфигурацию нашего проекта.
  • django_example/urls.py — здесь объявляются URL.
  • django_example/wsgi.py — с помощью него приложение может работать с веб-сервером по протоколу WSGI.
  • manage.py позволяет взаимодействовать с проектом.

Теперь пришло время запустить наше приложение. Для этого в командной строке нужно написать python manage.py runserver. После этого в адресной строке браузера нужно написать: http://127.0.0.1:8000/. Если вы увидели «You have unapplied migrations; your app may not work properly until they are applied.», то не волнуйтесь, мы вернемся к этому чуть позже.

Пишем веб-приложение на Django

Определим различие между проектом и приложением. Приложение — это программа, которая что-то делает, а проект — это группа приложений.

Итак, приступим к созданию приложения. Это делается следующим образом: python manage.py startapp riddles.
Как только создано веб-приложение, напишем вид, по правилам Джанго все виды должны храниться в файле views.py.

riddles/views.py

from django.http import HttpResponse


def index(request):
    return HttpResponse("Hello, World!")

Теперь, чтобы привязать наш вид к URL, создадим файл urls.py.

riddles/urls.py

from django.conf.urls import url

from . import views

app_name = 'riddles'

urlpatterns = [
    url(r'^$', views.index, name='index'),
]

В urls.py мы должны написать следующее:

django_example/urls.py

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^riddles/', include('riddles.urls')),
    url(r'^admin/', admin.site.urls),
]

Теперь, если мы запустим наше приложение http://127.0.0.1:8000/riddles/, мы увидим «Hello, World!».

Установка базы данных

По умолчанию в Django используется SQLite, если она вас не устраивает, то вы можете ознакомиться с нашей статьей, в которой мы рассказываем, как безболезненно перейти с SQLite на MySQL.

Теперь откроем django_example/settings.py и взглянем на переменную INSTALLED_APPS, она хранит все приложения, которые активны в текущем проекте. По умолчанию она содержит:

  • django.contrib.admin — админка, скоро мы ей воспользуемся.
  • django.contrib.auth — система аутентификации.
  • django.contrib.contenttypes — фреймворк для content types.
  • django.contrib.sessions — сессионный фреймворк.
  • django.contrib.messages — фреймворк для отправки сообщений.
  • django.contrib.staticfiles — фреймворк для работы со статичными файлами.

Некоторые из этих приложений используют базы данных, но они еще не установлены, поэтому мы и видели «You have unapplied migrations; your app may not work properly until they are applied.». Поправить это можно следующим образом: python manage.py migrate. Вы должны увидеть следующее:

Operations to perform:
  Apply all migrations: admin, sessions, auth, contenttypes
Running migrations:
  Rendering model states... DONE
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying sessions.0001_initial... OK

Теперь создадим нашу модель. Для начала создадим Riddle и Option. В Riddle будет содержаться загадка, в Option — один из возможных ответов на нее.

riddles/models.py

from django.db import models


class Riddle(models.Model):
    riddle_text = models.CharField(max_length=255)
    pub_date = models.DateTimeField('date published')


class Option(models.Model):
    riddle = models.ForeignKey(Riddle, on_delete=models.CASCADE)
    text = models.CharField(max_length=255)
    correct = models.BooleanField(default=False)

Данная модель обеспечивает Django информацией, необходимой для создания схемы базы данных и database-access API для доступа к объектам. Теперь нам нужно привязать наше приложение к нашему проекту, делается это следующим образом:

django_example/settings.py

INSTALLED_APPS = [
    'riddles.apps.RiddlesConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

После этого нужно сделать миграцию: python manage.py makemigrations riddles. Вы должны увидеть следующее:

Migrations for 'riddles':
  0001_initial.py:
    - Create model Option
    - Create model Riddle
    - Add field riddle to option

Так мы говорим Django, что в моделях были сделаны некоторые изменения, и их нужно сохранить в качестве миграции.

Проверить, что сделает миграция, можно так: python manage.py sqlmigrate riddles 0001 (0001 — версия миграции, которую мы хотим проверить). На выходе мы получим:

BEGIN;
--
-- Create model Option
--
CREATE TABLE "riddles_option" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "text" varchar(255) NOT NULL, "correct" bool NOT NULL);
--
-- Create model Riddle
--
CREATE TABLE "riddles_riddle" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "riddle_text" varchar(255) NOT NULL, "pub_date" datetime NOT NULL);
--
-- Add field riddle to option
--
ALTER TABLE "riddles_option" RENAME TO "riddles_option__old";
CREATE TABLE "riddles_option" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "text" varchar(255) NOT NULL, "correct" bool NOT NULL, "riddle_id" integer NOT NULL REFERENCES "riddles_riddle" ("id"));
INSERT INTO "riddles_option" ("riddle_id", "id", "text", "correct") SELECT NULL, "id", "text", "correct" FROM "riddles_option__old";
DROP TABLE "riddles_option__old";
CREATE INDEX "riddles_option_a7c97949" ON "riddles_option" ("riddle_id");

COMMIT;

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

Теперь мы можем начать пользоваться панелью администратора. Но для этого нам нужен пользователь. Создать его можно следующим образом: python manage.py createsuperuser. После этого запускаем сервер, если он не запущен, и переходим на http://127.0.0.1:8000/admin/. Вы увидите следующее:
Форма логина

Теперь дадим админу возможность изменять наши модели. Делается это так:

riddles/admin.py

from django.contrib import admin

from .models import Option, Riddle

admin.site.register(Riddle)
admin.site.register(Option)

Вот что получится в итоге:

Панель администратора

Возьмите небольшую паузу и поиграйтесь с панелью администратора. Вы будете приятно удивлены тем, что умеет Джанго.

Главная страница

Что нам нужно для создания главной страницы?

  • Templates: скелет нашей страницы.
  • Views: функция на Python для отображения контента.

Начнем с шаблонов. Создадим папку templates внутри папки riddle, а в ней создадим index.html.

riddles/templates/index.html

<h1>Available Riddles</h1>

{% if message %}
    <p><strong>{{ message }}</strong></p>
{% endif %}

{% if latest_riddles %}

    <ul>
        {% for riddle in latest_riddles %}
            <li>
                <a href="/riddles/{{ riddle.id }}/">
                    {{ riddle.riddle_text }}
                </a>
            </li>
        {% endfor %}
    </ul>

{% else %}
    <p>No riddles are available right now.</p>
{% endif %}

Теперь создадим макет для ответов:

riddles/templates/answer.html

<h1>{{ riddle.riddle_text }}</h1>

{% if error_message %}
    <p>
        <strong>{{ error_message }}</strong>
    </p>
{% endif %}

<form action="answer' riddle.id %}" method="post">
    {% csrf_token %}
    {% for option in riddle.option_set.all %}
        <input type="radio" name="option" id="option{{ forloop.counter }}" value="{{ option.id }}" />
        <label for="option{{ forloop.counter }}">{{ option.text }}</label><br>
    {% endfor %}
    <input type="submit" value="Answer" />
</form>

Здесь мы используем csrf_token, он нужен для защиты от межсайтовой подделки запроса, каждая внутренняя форма должна его использовать. Теперь напишем виды для рендеринга наших шаблонов:

riddles/views.py

from django.http.response import HttpResponse
from django.shortcuts import get_object_or_404, render

from .models import Riddle, Option


def index(request):
    return render(request, "index.html", {"latest_riddles": Riddle.objects.order_by('-pub_date')[:5]})


def detail(request, riddle_id):
    return render(request, "answer.html", {"riddle": get_object_or_404(Riddle, pk=riddle_id)})


def answer(request, riddle_id):
    riddle = get_object_or_404(Riddle, pk=riddle_id)
    try:
        option = riddle.option_set.get(pk=request.POST['option'])
    except (KeyError, Option.DoesNotExist):
        return render(request, 'answer.html', {'riddle': riddle, 'error_message': 'Option does not exist'})
    else:
        if option.correct:
            return render(request, "index.html", {"latest_riddles": Riddle.objects.order_by('-pub_date')[:5], "message": "Nice! Choose another one!"})
        else:
            return render(request, 'answer.html', {'riddle': riddle, 'error_message': 'Wrong Answer!'})

  Давайте пройдемся по каждой функции веб-приложения на Django отдельно:

  • index: Index использует функцию render. На вход она получает HttpRequest, местонахождение шаблона и его содержимое, а возвращает HttpResponse с окончательным html.
  • detail: Detail делает практически то же самое, но только функция get_object_or_404 возвращает HttpResponse404, если нужный объект не был найден.
  • answer: Answer ищет предоставленную загадку (и возвращает 404, если она не найдена) и проверяет правильность ответа.

Теперь добавим наши функции в urls.py:

riddles/urls.py

from django.conf.urls import url

from . import views

app_name = 'riddles'

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^(?P[0-9]+)/$', views.detail, name='detail'),
    url(r'^(?P[0-9]+)/answer/$', views.answer, name='answer')
]

Стили

Для начала создадим директорию static, а в ней создадим файл main.css.

riddles/static/main.css

body{
    margin:40px auto;
    max-width:650px;
    line-height:1.6;
    font-size:18px;
    color:#444;
    padding:0 10px;
}
h1,h2,h3{
    line-height:1.2;
    text-align: center;
}
a {
    color: blue;
}

form {
    margin: 0 auto;
    padding: 1em;
    border: 1px solid #CCC;
    border-radius: 1em;
}
form div + div {
    margin-top: 1em;
}
label {
    display: inline-block;
    text-align: center;
    width: 40%;
}
input {
    font: 1em sans-serif;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    border: 1px solid #999;
    width: 50%;
}
input:focus {
    border-color: #000;
}
p, div.button {
    text-align: center;
}

p.error-message {
    color: lightcoral;
}

Немного изменим наши шаблоны:

riddles/templates/index.html

{% load staticfiles %}

<link rel="stylesheet" type="text/css" href="{% static 'main.css' %}" />

<h1>Available Riddles</h1>

{% if message %}
    <p><strong>{{ message }}</strong></p>
{% endif %}

{% if latest_riddles %}

    <ul>
        {% for riddle in latest_riddles %}
            <li>
                <a href="/riddles/{{ riddle.id }}/">
                    {{ riddle.riddle_text }}
                </a>
            </li>
        {% endfor %}
    </ul>

{% else %}
    <p>No riddles are available right now.</p>
{% endif %}

riddles/templates/answer.html

{% load staticfiles %}

<link rel="stylesheet" type="text/css" href="{% static 'main.css' %}" />

<h1>{{ riddle.riddle_text }}</h1>

{% if error_message %}
    <p>
        <strong>{{ error_message }}</strong>
    </p>
{% endif %}

<form action="answer' riddle.id %}" method="post">
    {% csrf_token %}
    {% for option in riddle.option_set.all %}
        <input type="radio" name="option" id="option{{ forloop.counter }}" value="{{ option.id }}" />
        <label for="option{{ forloop.counter }}">{{ option.text }}</label><br>
    {% endfor %}
    <input type="submit" value="Answer" />
</form>

Первая строка загружает статические файлы, потом мы используем {% static '#' %}, где # — путь к вашему файлу. Аналогичная процедура проводится и для JavaScript.

Теперь вы можете создавать свои веб-приложения на Django. В качестве подсказки на старте работы с фреймворком воспользуйтесь одной из наших шпаргалок по Python.

Исходный код нашего приложения можно скачать по этой ссылке.

Если этот веб-проект на Django показался сложным, попробуйте пройти двухчасовой видеокурс. На нём вы пошагово создадите 3 веб-приложения: сокращатель ссылок, ToDo List и словарь английских слов.

Перевод статьи «Python Django Tutorial»

Последнее обновление: 26.08.2022

Содержание руководства по созданию веб-приложений на языке Python с помощью фреймворка Django.

  1. Глава 1. Введение в Django

    1. Что такое Django

    2. Установка и настройка Django

    3. Создание первого проекта

    4. Создание первого приложения

  2. Глава 2. Представления и маршрутизация

    1. Обработка запроса

    2. Определение маршрутов и функции path и re_path

    3. Получение данных запроса. HttpRequest

    4. HttpResponse и отправка ответа

    5. Параметры представлений

    6. Вложенные маршруты и функция include

    7. Параметры строки запроса

    8. Переадресация и отправка статусных кодов

    9. Отправка json

    10. Отправка и получение кук

  3. Глава 3. Шаблоны

    1. Создание и использование шаблонов

    2. Передача данных в шаблоны

    3. Встроенные теги шаблонов

    4. Фильтры шаблонов

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

    6. TemplateView

    7. Конфигурация шаблонов

    8. Расширение шаблонов и фильтр extends

    9. Вложенные шаблоны и фильтр include

  4. Глава 4. Работа с формами

    1. Отправка форм

    2. Определение форм Django

    3. Типы полей формы

    4. Настройка формы и ее полей

    5. Валидация данных

    6. Детальная настройка полей формы

    7. Стилизация полей форм

  5. Глава 5. Модели

    1. Подключение к базе данных

    2. Создание моделей

    3. Типы полей моделей

    4. QuerySet API

    5. Создание и получение объектов модели

    6. Редактирование и удаление объектов модели

    7. Фильтрация

    8. values и values_list и сортировка

    9. Операции с множествами

    10. Получение отдельных объектов и проверка их наличия

    11. Агрегатные операции

    12. Выполнение SQL-выражений

    13. CRUD. Все базовые операции с моделями в веб-приложении

    14. Отношение один ко многим (One to Many)

    15. Практический пример связи один ко многим

    16. Отношение многие ко многим (Many to Many)

    17. Отношение многие ко многим (Many to Many)

    18. Отношение один к одному (One to one)

Время на прочтение
14 мин

Количество просмотров 286K

Представляю вам перевод статей о Django с сайта effectivedjango.com. Наткнулся я на этот сайт во время изучения данного фреймворка. Информация размещенная на этом ресурсе показалась мне полезной, но так как нигде не нашел перевода на русский, решил сделать сие доброе дело сам. Этот цикл статей, как мне думается, будет полезен веб-разработчикам, которые делают только первые шаги в изучении Django.


Оглавление

  • Введение
  • Эффективный Django. Руководство
    • Глава 1. Приступая к работе
    • Глава 2. Используем модель
    • Глава 3. Пишем представление
    • Глава 4. Используем статические ресурсы
    • Глава 5. Дополнительные базовые представления
    • Глава 6. Основы форм
    • Глава 7. Связанные модели
    • Глава 8. Обработка аутентификации и авторизации
  • Тестирование в Django
  • Понимание Middleware’ов
  • Базы данных и модели
  • Представления-классы (CBV)
  • Формы

Введение ⇧

Django — это популярный, мощный фреймворк на языке Python. Он имеет множество «батареек«, и позволяет сразу начать разработку. Однако вся эта мощь означает, что вы можете написать низкопробный код, который будет казаться рабочим. Так что же подразумевается под Эффективным Django? Под Эффективным Django будем понимать использование Django таким образом, чтобы написанный код был связным, тестируемым и масштабируемым. Что же каждое из этих слов значит?

«Связный» код — это код, который сосредоточен на выполнении одной вещи, только одной единственной вещи. Это значит, что когда вы пишете функцию или метод — написанный вами код должен делать что-то одно и делать это хорошо.

Это непосредственно относится к написанию тестируемого кода: код, который делает много вещей, достаточно часто является чересчур сложным для тестирования. Когда я ловлю себя на мысли: «Хорошо, этот кусок кода слишком сложен, чтобы писать для него тесты — это просто не стоит потраченных усилий» — вот сигнал к тому, чтобы вернутся назад и сосредоточиться на упрощении. Тестируемый код — такой код, который позволяет просто писать для него тесты; код, в котором легко найти проблемы.

И наконец, мы хотим писать масштабируемый код. Это означает не просто масштабировать его в терминах исполнения, но так же увеличивать в терминах команды и командного понимания. Хорошо протестированные приложения проще для понимания другими (и проще для изменения ими), что подразумевает большую возможность улучшить ваше приложение, путем добавления новых инженеров.

Моя цель — убедить вас в важности этих принципов, и предоставить примеры того, как следуя им, построить более стойкое Django-приложение. Я собираюсь последовательно пройти через процесс построения приложения для управления контактами, рассказывая про решения и стратегию тестирования, которые я использую.

Эти документы являются сочетанием заметок и примеров подготовленных для PyCon 2012, PyOhio 2012, и PyCon 2013, а также для web-разработки Eventbrite. Я все еще работаю над объединением их в один документ, но надеюсь вы найдете их полезными.

Примеры кода для этого руководства доступны на github’е. Отзывы, предложения и вопросы можете присылать на nathan@yergler.net.
Этот документ доступен на сайте, а также в форматах PDF и EPub.

Видео этого руководства с PyCon можно посмотреть на YouTube.

Глава 1. Приступая к работе ⇧

1.1. Ваша среда разработки

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

Изоляция

означает, что вы не сможете случайно воспользоватся инструментами или пакетами установленными вне вашего окружения. Это особенно важно, когда подобное происходит с чем-то, похожим на пакеты Python с расширениями написанными на C: если вы используете что-то установленное на системном уровне и не знаете об этом, то при развертывании или распространении своего кода вы можете обнаружить, что он работает не так как предполагалось. Инструменты наподобие virtualenv могут помочь создать нечто похожее на изолированную среду.

Ваша среда

предопределена

, если вы уверены в том, на какую версию ваших зависимостей вы полагаетесь и сможете ли вы наверняка воспроизвести системное окружение.

И на конец,

сходство

с производственной средой или средой сервера разработки означает, что везде установлена одна и та же операционная система (возможно даже одинаковый выпуск) и вы используете одинаковые инструменты как для конфигурирования вашей среды разработки, так и для конфигурирования вашей производственной среды. Это отнюдь не необходимость, но если вы строите большое и сложное программное обеспечение — сходство будет полезно для уверенности в том, что все проблемы, которые вы можете увидеть на «боевом» сервере, воспроизводимы в той среде, где вы ведете разработку. К тому же

сходство

ограничивает область исследования вашего кода.

1.1.1. Изоляция

  • Мы хотим избежать использования неизвестных зависимостей или неизвестных версий.
  • virtualenv предоставляет простой путь для работы над проектом, без использования системных site-packages.

1.1.2. Предопределенность

  • Предопределенность означает управление зависимостями.
  • Выберете один из инструментов и используйте как при разработке, так на «боевом» сервере:
    • pip и специальные файлы зависимостей;
    • buildout;
    • install-requires в setup.py.
  • Определите точные версии зависимостей.

Вы можете точно определить версии используя либо версию пакета на PyPI, либо же определенную ревизию (SHA в git, номер ревизии в Subversion и т. д.). Это гарантирует вам возможность получить в точности те же версии пакетов, которые вы используете при тестировании.

1.1.3. Сходство

  • Работа в среде, похожей на ту, где вы будете разворачивать ваше приложение и пытаться обнаружить проблемы.
  • Если вы разрабатываете что-то, требующее дополнительных сервисов — сходство становится еще более важным.
  • Vagrant — это инструмент для управления виртуальными машинами, позволяющий вам легко создавать окружение отделенное от вашего повседневного окружения.

1.2. Настройка вашего окружения

1.2.1. Создание чистого рабочего пространства

Примечание переводчика:
Для начала создадим каталог (tutorial), в котором будем работать:

~$ mkdir tutorial
~$ cd tutorial
~/tutorial$ mkdir venv project

В каталоге venv будет находится наше виртуальное окружение, а в каталоге project — Django-проект

~/tutorial$ virtualenv --prompt="(venv:tutorial)" ./venv/

New python executable in ./venv/bin/python
Installing setuptools............done.
Installing pip...............done.

~/tutorial$ source ./venv/bin/activate
(venv:tutorial)~/tutorial$

1.2.2. Создание файла зависимостей

Создайте файл requirements.txt в директории tutorial с единственной строкой (зависимостью) в нем:

Django==1.6.7

Примечание переводчика:
В случае, если вы хотите использовать последнюю версию Django (1.7 — на момент написания перевода) — вместо строки Django==1.6.7 оставьте просто Django — pip установит последнюю доступную версию.

1.2.3. Установка зависимостей

А теперь мы можем использовать pip для установки зависимостей:

(venv:tutorial)~/tutorial$ pip install -U -r requirements.txt

Downloadping/unpacking Django==1.6.7 (from -r requirements.txt (line 1))
  Downloading Django-1.6.7.tar.gz (6.6MB): 6.6MB downloaded
  Running setup.py egg_info for package Django

    warning: no previously-included files matching ’__pycache__’ found under directory ’*’
    warning: no previously-included files matching ’*.py[co]’ found under directory ’*’
Installing collected packages: Django
  Running setup.py install for Django
    changing mode of build/scripts-2.7/django-admin.py from 644 to 755

    warning: no previously-included files matching ’__pycache__’ found under directory ’*’
    warning: no previously-included files matching ’*.py[co]’ found under directory ’*’
    changing mode of /home/nathan/p/edt/bin/django-admin.py to 755
Successfully installed Django
Cleaning up...

1.3. Начало проекта Django

Когда здание находится в процессе постройки, строительные леса часто используются для поддержания структуры до того как строительство будет завершено. Строительные леса могут быть временными или они могут служить частью фундамента здания, но несмотря на это, они представляют некоторую поддержку когда вы только начинаете работу.

Django, как и многие web-фреймворки, представляет скаффолдинг для вашей разработки. Это происходит при помощи принятия решений и предоставления отправной точки для вашего кода, что позволяет вам сосредоточится на проблеме, которую вы пытаетесь решить, а не на том, как разобрать HTTP-запрос. Django предоставляет скаффолдинг как для работы с HTTP, так и для работы с файловой системой.

HTTP-скаффолдинг управляет, например, преобразованием HTTP-запроса в объект языка Python, а также предоставляет инструменты для более простого создания серверных ответов. Скаффолдинг файловой системы иной: это набор соглашений по организации вашего кода. Эти соглашения облегчают добавление новых инженеров в проект, так как инженеры (гипотетически) уже понимают как организован код. В терминах Django, проект — это конечный продукт, и он объединяет внутри себя одно или несколько приложений. В Django 1.4 было изменено то, как проекты и приложения размещаются на диске, что облегчило разъединение и повторное использование приложений в разных проектах.

1.3.1. Создание проекта

Django устанавливает в систему скрипт django-admin.py для обработки задач скаффолдинга. Для создания файлов проекта используется задача startproject. Мы определим имя проекта и имя директории, в которой хотим разместить проект. Так как, мы уже находимся в изолированной среде, можно просто написать:

Примечание переводчика:
Перейдем директорию ~/tutorial/project/ и в дальнейшем будем работать только из этой директории (под $ далее будем подразумевать ~/tutorial/project/$):

(venv:tutorial)~/tutorial/$ cd project

(venv:tutorial)$ django-admin.py startproject addressbook .

Созданный проект имеет следующую структуру

manage.py
./addressbook
    __init__.py
    settings.py
    urls.py
    wsgi.py

1.3.2. Скаффолдинг проекта

  • manage.py — является ссылкой на скрипт django-admin, но с уже предустановленными переменными окружения, указывающими на ваш проект, как для чтения настроек оттуда, так и для управления им при необходимости;
  • settings.py — здесь находятся настройки вашего проекта. Файл уже содержит несколько разумных настроек, но база данных не указана;
  • urls.py — содержит URL’ы для маппирования (отображения) представлений: мы вскоре (в дальнейших главах) поговорим об этом подробнее;
  • wsgi.py — это WSGI обёртка для вашего приложения. Этот файл используется сервером разработки Django и возможно другими контейнерами, такими как mod_wsgi, uwsgi и др. на «боевом» сервере.

1.3.3. Создание приложения

(venv:tutorial)$ python ./manage.py startapp contacts

Созданное приложение имеет следующую структуру:

./contacts
    __init__.py
    models.py
    tests.py
    views.py

  • Начиная с Django 1.4, приложения размещаются внутри пакета с проектом. Это замечательное улучшение, особенно когда приходит время разворачивать проект на «боевом» сервере;
  • models.py будет содержать Django ORM-модели для вашего приложения;
  • views.py будет содержать код представлений;
  • tests.py будет содержать написанные вами модульные и интеграционные тесты.
  • Django 1.7: admin.py будет содержать модель для административного интерфейса.
  • Django 1.7: migrations/ содержит файлы миграций

Примечание переводчика:
На текущий момент наша директория ~/tutorial/ содержит файл зависимостей (requirements.txt), директорию с виртуальным окружением (venv/), один проект (project/addressbook), одно приложение (project/contacts) и имеет следующее содержание:

~/tutorial/
	requirements.txt
	venv/
		...
	project/
		manage.py
		addressbook/
			__init__.py
			settings.py
			urls.py
			wsgi.py
		contacts/
			__init__.py
			models.py
			tests.py
			views.py

Глава 2. Используем модель ⇧

2.1. Конфигурирование базы данных

Django поддерживает «из коробки» MySQL, PostgreSQL, SQLite3 и Oracle. SQLite3 входит в состав Python начиная с версии 2.5, так что мы будем использовать его в нашем проекте (для простоты). Если вы хотите, к примеру, использовать MySQL, то нужно добавить mysql-python в ваш requirements.txt.

Для того чтобы в качестве базы данных использовать SQLite, отредактируйте определение DATABASES в файле addressbook/settings.py. Файл settings.py содержит настройки Django для нашего проекта. В нем есть несколько настроек, которые вы обязаны указать — например DATABASES — а так же другие, необязательные, настройки. Django устанавливает некоторые настройки сам, когда генерирует проект. Документация содержит полный список настроек. К тому же вы можете добавить свои собственные настройки, если это необходимо.

Для использования SQLite нам нужно указать движок (ENGINE) и имя базы (NAME). SQLite интерпертирует имя базы как имя файла для базы данных:

DATABASES = {
    'defaults': {
	    'ENGINE': 'django.db.backends.sqlite3,' # ’postgresql_psycopg2’, ’mysql’, ’sqlite3’ or ’oracle'.
		'NAME': os.path.join(BASE_DIR, 'address.db'),
		'USER': '',     # Not used with sqlite3.
		'PASSWORD': '', # Not used with sqlite3.
		'HOST': '',     # Set to empty string for localhost. Not used with sqlite3.
		'PORT': '',     # Set to empty string for default. Not used with sqlite3.
	}
}

Заметьте, что движок базы данных указан строкой, а не прямой ссылкой на объект Python. Это сделано по той причине, что файл настроек должен быть легко импортирован не вызывая сторонних эффектов. Вы должны избегать добавления вызовов import в этот файл.

Вам редко придется непосредственно импортировать файл настроек: Django импортирует его за вас, и делает настройки доступными как django.conf.settings. Вы, как правило, импортируете настройки из django.conf:

from django.conf import settings

2.2. Создание модели

Модели Django отображают (грубо говоря) таблицы базы данных, и предоставляют место для инкапсулирования бизнес-логики. Все модели являются наследниками базового класса Model и содержат поля определений. Давайте создадим простую модель Contacts для нашего приложения в файле contacts/models.py:

from django.db import models

class Contact(models.Model):

    first_name = models.CharField(
        max_length=255,
    )
    last_name = models.CharField(
        max_length=255,
    )
	
    email = models.EmailField()

	def __str__(self):

	    return ' '.join([
            self.first_name,
            self.last_name,
        ])

Django предоставляет набор полей для отображения типов данных и различных правил валидации. К примеру, EmailField, который мы использовали, является отображением на колонку с типом CharField, но добавляет валидацию данных.

После того, как вы создали модель, необходимо дополнить вашу базу данных новыми таблицами. Команда Django syncdb смотрит установленные модели и создает (если нужно) таблицы для них:

Примечание переводчика:
Django предложит создать суперпользователя для андминки, которая включена в этой версии по умолчанию. Воспользуйтесь его предложением.

Примечание переводчика:
С версии Django 1.7 во фреймворк добавлена нативная поддержка миграций и команда syncdb объявлена устаревшей. Так что будьте так любезны, воспользуйтесь командой migrate вместо syncdb.

(venv:tutorial)$ python ./manage.py syncdb

Creating tables ...
Creating table django_admin_log
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (leave blank to use 'bjakushka'):
Email address: 
Password:
Password (again):
Superuser created successfully.
Installing custom SQL ...
installing indexes ...
Installed 0 object(s) from 0 fixture(s)

(venv:tutorial)$

Примечание переводчика:
Если вы используете Django версии 1.7 и выше — вывод будет следующий:

(venv:tutorial)$ python ./manage.py migrate

Opperation to perform:
    Apply all migrations: admin, contenttypes, auth, sessions
Running migrations:
    Applying contenttypes.0001_initial... OK
    Applying auth.0001_initial... OK
    Applying admin.0001_initial... OK
    Applying sessions.0001_initial... OK

(venv:tutorial)$ 

Однако нашей таблицы с контактами нигде не видно. Причина этого состоит в том, что нам нужно еще указать проекту использовать приложение.

Настройка INSTALLED_APPS содержит список приложений, используемых в проекте. Этот список содержит в себе строки, которые отображают пакеты Python. Django будет импортировать каждый из указанных пакетов, а потом смотреть модуль models. Давайте добавим наше приложение contacts в настройки проекта (addressbook/settings.py):

INSTALLED_APPS = (
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
  
  'contacts',
)

После этого запустите syncdb снова:

Примечание переводчика:
Для Django версии 1.7 и выше вам нужно будет запустить сначала команду makemigrations — для создания миграций на основе изменений в моделях, а после этого выполнить команду migrate — для того чтобы применить созданные миграции.

(venv:tutorial)$ python ./manage.py syncdb

Creating tables ...
Creating table contacts_contact
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

(venv:tutorial)$

Примечание переводчика:
Вывод для Django 1.7 и выше:

(venv:tutorial)$ python ./manage.py makemigrations

Migrations for 'contacts':
    0001_initial.py:
        - Create model Contact

(venv:tutorial)$ python ./manage.py migrate

Opperation to perform:
    Apply all migrations: admin, contenttypes, sessions, auth, contacts
Running migrations:
    Applying contacts.0001_initial... OK

(venv:tutorial)$ 

Заметьте, что Django создает таблицу с именем contacts_contact: по умолчанию Dj ango дает таблицам имена используя комбинацию имени приложения и имени модели. Вы можете изменить это с помощью опций модели Meta.

2.3. Взаимодействие с моделью

Теперь, когда модель синхронизирована с базой данных мы можем взаимодействовать с нею используя интерактивную оболочку:

(venv:tutorial)$ python ./manage.py shell
Python 2.7.3 (default, Mar 14 2014, 11:57:14)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from contacts.models import Contact
>>> Contact.objects.all()
[]
>>> Contact.objects.create(first_name='Nathan', last_name='Yergler')
<Contact: Nathan Yergler>
>>> Contact.objects.all()
[<Contact: Nathan Yergler>]
>>> nathan = Contact.objects.get(first_name='Nathan')
>>> nathan
<Contact: Nathan Yergler>
>>> print nathan
Nathan Yergler
>>> nathan.id
1

Здесь использовалось несколько новых штук. Во-первых, команда manage.py shell запускает для нас интерактивную оболочку Python’а с правильно установленными путями для Django. Если вы попробуете запустить интерпретатор Python и просто импортировать ваше приложения, будет выброшено исключение, потому что Django не знает, какие настройки использовать, и не может отобразить экземпляры модели на базу данных.

Во-вторых, здесь использовалось свойство objects нашей модели. Это менеджер модели. Так, если один экземпляр модели является аналогией для строки в базе, то менеджер модели — аналогией для таблицы. По умолчанию менеджер модели предоставляет функциональность запросов и может быть настроен. Когда мы вызываем all(), filter() или сам менеджер, возвращается объект QuerySet. QuerySet является итерируемым объектом и загружает данные из базы по необходимости.

И последнее — выше использовалось поле с именем id, которое мы не определяли в нашей модели. Django добавляет это поле как первичный ключ для модели, но только в том случае если вы сами не определили какое поле будет первичным ключом.

2.4. Написание тестов

В нашей модели определен один метод, __str__, так что настало время писать тесты. Метод __str__ будет использоваться всего лишь в нескольких местах, и, вполне возможно, полностью будет показан конечному пользователю. Для этого метода стоит написать тест, пока мы понимаем как он работает. Django создал файл tests.py когда создавал приложение, так что мы добавим первый тест в этот файл, приложения contacts.

from django.test import TestCase

from contacts.models import Contact

class ContactTests(TestCase):
    """Contact model tests."""
	
    def test_str(self):
	
        contact = Contact(first_name='John', last_name='Smith')
        self.assertEquals(
            str(contact),
            'John Smith',
        )

Вы можете запустить тесты для вашего приложения используя команду manage.py test:

(venv:tutorial)$ python ./manage.py test

Если вы запустите это, то увидите что выполнилось около 420 тестов. Это удивляет, так как мы написали только один. Произошло это потому, что по умолчанию Django запускает тесты для всех установленных приложений. Когда вы добавляли приложение contacts в наш проект, то могли увидеть, что там по умолчанию были добавлены несколько встроенных приложений Django. Дополнительные 419 тестов были взяты оттуда.

Примечание переводчика:
В нашем случае (при использовании версии Django 1.6.7) предыдущий абзац несколько устарел: запустится только один тест — тот который мы создали. Вывод команды будет такой как указано ниже.

Если же вы захотите запустить тесты для определенного приложения — укажите имя приложения в команде:

(venv:tutorial)$ python manage.py test contacts

Creating test database for alias ’default’...
.
----------------------------------------------------------------------
Ran 1 tests in 0.001s

OK
Destroying test database for alias ’default’...

(venv:tutorial)$

Еще одна интересная вещь на заметку, прежде чем двигаться дальше — первая и последняя строка вывода: Creating test database и Destroying test database. Некоторым тестам необходим доступ к базе данных, и поскольку мы не хотим мешать тестовые данные с «реальными» (по разным причинам, не последней из которых является предопределенность), Django услужливо создает тестовую базу для нас, прежде чем запускать тесты. По существу, создается новая база данных, и потом запускается syncdb для нее. Если тестовый класс является потомком класса TestCase (как у нас), Django так же сбросит данные в значения по умолчанию после запуска каждого теста, так что изменения в одном из тестов не затронут другие.

2.5. Резюме

  • Модель определяет поля в таблице, и содержит бизнес-логику.
  • Команда syncdb создает таблицы в вашей базе данных из моделей. В Django версии 1.7 и выше вместо команды syncdb необходимо использовать сначала команду makemigrations — для создания миграций, а после этого команду migrate — для внесение изменений в базу.
  • Менеджер модели позволяет вам оперировать коллекциями экземпляров: запросы, создание и т. д..
  • Пишите модульные тесты для методов, которые вы добавили в модель.
  • Команда управления test запускает модульные тесты на выполнение.

Примечание переводчика:
Для того чтобы протестировать наше, пока еще пустое, приложение нужно выполнить следующую команду:

(venv:tutorial)$ python ./manage.py runserver 0.0.0.0:8080

Это запустит встроенный сервер, функционал которого любезно предоставляет нам Django. В параметрах после runserver указывается ip-адрес и порт, который будет слушаться работающим сервер. В нашем случае сервер будет принимать запросы от всех ip-адресов при обращении на 8080 порт.

Я использую для разработки домашний сервер с внутренним IP 192.168.1.51. Так что для того что-бы увидеть результат работы сервера разработки в браузере я захожу по адресу http://192.168.1.51:8080/. Вы же должны подставить адрес своего сервера.


Как думаете, нужно ли продолжать перевод остальных глав? Оказался ли перевод для Вас полезен?
Буду рад конструктивной критике в комментариях.
Об ошибках и неточностях перевода прошу сообщать в личном сообщении.

Использованное в начале поста изображение создано как вариация изображения пользователя MaGIc2laNTern

Понравилась статья? Поделить с друзьями:
  • Рандеву возбудитель для женщин инструкция по применению
  • От чего таблетки лактофильтрум в таблетках взрослым инструкция по применению
  • Руководство омвд ноябрьска
  • Внутренняя инженерия путь радости практическое руководство от йога садхгуру читать
  • Руководство к практическим занятиям по ботанике