Последнюю версию Python можно найти на http://www.python.org/download
pip install Django
Проверка версии Django
$ python -c "import django; print(django.get_version())"
Создание нового проекта
$ django-admin.py startproject mysite
Настройка проекта mysite/settings.py
LANGUAGE_CODE = 'ru'
TIME_ZONE = 'Europe/Moscow'
Запуск основных миграций
$ python manage.py migrate
Запуск сервера для разработки
$ python manage.py runserver
$ python manage.py runserver 8080
$ python manage.py runserver 0.0.0.0:8000
По умолчанию сервер доступен по адресу localhost:8000
При добавление новых файлов необходимо перегрузить сервер.
Cоздание нового приложения в проекте
$ python manage.py startapp polls
Подключение приложения к проекту mysite/settings.py
INSTALLED_APPS = (
# ...
'polls',
)
Модели создаются в polls/models.py
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
Создание миграции на основе моделей
$ python manage.py makemigrations polls
Просмотр того, что будет добавлено в базу из миграций
$ python manage.py sqlmigrate polls 0001
Поиск проблем в проекте не применяя миграции и не изменяя базу данных
$ python manage.py check
Применение миграции
$ python manage.py migrate
Тестирование API
$ python manage.py shell
>>> from polls.models import Question, Choice
# создать новый Question
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
# сохранить объект в базе данных
>>> q.save()
# доступ к полям
>>> q.id
>>> q.question_text
>>> q.pub_date
# меняем значение поля
>>> q.question_text = "What's up?"
>>> q.save()
# показать все вопросы в базе
>> Question.objects.all()
Изменение формата вывода в моделях polls/models.py
from django.db import models
class Question(models.Model):
# ...
def __str__(self):
return self.question_text
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text
Добавление своих методов polls/models.py
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
Тестирование API
>>> from polls.models import Question, Choice
>>> Question.objects.all()
# найти записи по определенному ключу
>>> Question.objects.filter(id=1)
>>> Question.objects.filter(question_text__startswith='What')
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
# поиск по первичному ключу
>>> Question.objects.get(pk=1)
# проверяем метод
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
# поиск по связанной таблице
>>> q = Question.objects.get(pk=1)
>>> q.choice_set.all()
# создание
>>> q.choice_set.create(choice_text='Not much', votes=0)
>>> q.choice_set.create(choice_text='The sky', votes=0)
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
# проверяем родителя
>>> c.question
# и наоборот
>>> q.choice_set.all()
>>> q.choice_set.count()
# поиск по связанной таблице
>>> Choice.objects.filter(question__pub_date__year=current_year)
# удаление
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
Создание суперпользователя
$ python manage.py createsuperuser
Теперь можно зайти в админку по адресу localhost:8000/admin
и авторизироваться
Регистрируем модели для админки polls/admin.py
from django.contrib import admin
from polls.models import Question
admin.site.register(Question)
Можно поменять порядок полей в админке
class QuestionAdmin(admin.ModelAdmin):
fields = ['pub_date', 'question_text']
admin.site.register(Question, QuestionAdmin)
Можно разбить форму на группу полей
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date']}),
]
Можно добавить HTML классы для каждой группы полей
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
from django.contrib import admin
from polls.models import Choice, Question
# ...
admin.site.register(Choice)
Теперь можно создавать choices и привязывать к ним questions
Но, удобнее будет добавлять варианты ответов пачками при создании Question:
from django.contrib import admin
from polls.models import Choice, Question
class ChoiceInline(admin.StackedInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline]
admin.site.register(Question, QuestionAdmin)
Теперь варианты ответов редактируются на странице вопроса. По умолчанию, будет отображваться 3 формы для добавления вариантов ответа.
Можно отображать их табами
class ChoiceInline(admin.TabularInline):
По умолчанию Django отображает результат выполнения str()
для каждого объекта.
Но чаще всего хочется показывать список полей.
class QuestionAdmin(admin.ModelAdmin):
# ...
list_display = ('question_text', 'pub_date')
Можно нажать на заголовок колонки чтобы отсортировать записи по полю – но не
для was_published_recently
. Добавляем в polls/models.py
:
class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
Добавляем на страницу списка вопросов фильтры polls/admin.py(QuestionAdmin)
:
list_filter = ['pub_date']
Теперь добавим поиск:
search_fields = ['question_text']
Страница списка объектов также содержит постраничное отображение. По умолчанию отображается 100 объектов на страницу. Можно:
- Поменять количество объектов на одной странице
- Поля для поиска
- Фильтры
- Добавить иерархию по дате
- Отображаемые поля
Создаем папку, как указано в mysite/settings.py
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]
# TODO: почему то заработало только так:
TEMPLATE_DIRS = [
os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
]
Узнать, где лежат исходники
python -c "import sys; sys.path = sys.path[1:]; import django; print(django.__path__)"
Копируем base_site.html
из встроенных шаблонов в исходниках Django
Меняем {{ site_header }}
При разработке проекта для этого обычно используют атрибут django.contrib.admin.AdminSite.site_header.
Любой шаблон интерфейса администратора можно переопределить.
Представления создаются в polls/views.py
:
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
Создать файл polls/urls.py
:
from django.conf.urls import patterns, url
from polls import views
urlpatterns = patterns('',
# ex: /polls/
url(r'^$', views.index, name='index'),
)
Отредактировать файл mysite/urls.py
:
from django.conf.urls import patterns, include, url
from django.contrib import admin
urlpatterns = patterns('',
url(r'^polls/', include('polls.urls')),
url(r'^admin/', include(admin.site.urls)),
)
Можно проверять: localhost:8000/polls
Отредактировать файл polls/views.py
:
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)
Отредактировать файл polls/urls.py
:
urlpatterns = patterns('',
#...
# ex: /polls/5/
url(r'^(?P<question_id>\d+)/$', views.detail, name='detail'),
# ex: /polls/5/results/
url(r'^(?P<question_id>\d+)/results/$', views.results, name='results'),
# ex: /polls/5/vote/
url(r'^(?P<question_id>\d+)/vote/$', views.vote, name='vote'),
)
Отредактировать polls/views.py
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([p.question_text for p in latest_question_list])
return HttpResponse(output)
Создать polls/templates/polls/index.html
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
Именить представление index
в polls/views.py
from django.http import HttpResponse
from django.template import RequestContext, loader
from polls.models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = RequestContext(request, {
'latest_question_list': latest_question_list,
})
return HttpResponse(template.render(context))
Функция render()
предназначна для объединения процесса загрузки шаблона,
добавления контекста и возврат объекта HttpResponse
.
from django.shortcuts import render
from polls.models import Question
def index(request):
latest_question_list = Question.objects.all().order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
Теперь создадим страницу опроса, которая отображает вопрос и варианты ответа:
Добавляем в polls/views.py
from django.http import Http404
from django.shortcuts import render
# ...
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404
return render(request, 'polls/detail.html', {'question': question})
Функция get_object_or_404()
упрощает обыденные операции:
from django.shortcuts import get_object_or_404, render
# ...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
Добавляем polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
Для {{ question.question_text }}
Django сначала пытается обратиться к
question
как к словарю. При неудаче ищется атрибут переменной, в данном случае
он и используется. Если атрибут не найден, будет искаться индекс в списке.
Так как мы указали названия при вызове url()
в модуле polls.urls
, мы можем
ссылаться на шаблоны URL-ов используя шаблонный тег {% url %}
:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
Добавим пространство имен к polls в mysite/urls.py
:
url(r'^polls/', include('polls.urls', namespace="polls")),
Теперь поменяем в шаблоне polls/index.html
:
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>