68
Django. Дополнительные темы Александр Бекбулатов

Web осень 2013 лекция 8

Embed Size (px)

Citation preview

Page 1: Web осень 2013 лекция 8

Django. Дополнительн

ые темы

Александр Бекбулатов

Page 2: Web осень 2013 лекция 8

2

1. Скрипт управления django приложением.

2. Middleware.

3. Использование сессий.

4. Приложение auth.

5. Class Based Views. 

6. Расширение фильтров и тэгов в

шаблонизаторе.

7. Другие приложения из коробки.

8. Оптимизация производительности

План лекции

Page 3: Web осень 2013 лекция 8

3

Скрипт управления django приложением

Page 4: Web осень 2013 лекция 8

4

Зачем?

• Standalone скрипты

• Скрипты запуска по крону

Как?

• Ручная инициализация приложения

• Management команды

Управление django приложением

Page 5: Web осень 2013 лекция 8

5

import osimport sys

if __name__ == "__main__": lib_path = 'path/to/project' if not lib_path in sys.path: sys.path.append(lib_path)  os.environ['DJANGO_SETTINGS_MODULE'] = \ 'ask_pupkin.settings'  # from django.conf import settings from ask.models import User …

Ручная инициализация

Page 6: Web осень 2013 лекция 8

6

Куда поместить?

ask/ __init__.py models.py management/ __init__.py commands/ __init__.py fill_db.py tests.py views.py

Management команды

Page 7: Web осень 2013 лекция 8

7

class Command(BaseCommand): help = 'Fill database with test data'  def handle(self, *args, **options): verbosity = int(options.get('verbosity', 1)) for i in xrange(USER_COUNT): user = User( name=get_random_string(10), email=get_random_email() ) user.save()  if verbosity > 1: self.stdout.write('Successfully imported %d users' % USER_COUNT)

Management команды

Page 8: Web осень 2013 лекция 8

8

Возможности

• Запуск скриптов для конкретного

приложения (manage.py sqlall ask)

• Несколько команд в одном файле

(manage.py fill_db users, manage.py fill_db

questions)

• Дополнительные опции (--delete)

https

://docs.djangoproject.com/en/dev/howto/custom-man

agement-commands

/

Управление django приложением

Page 9: Web осень 2013 лекция 8

9

Middleware

Page 10: Web осень 2013 лекция 8

10

Middleware

Page 11: Web осень 2013 лекция 8

11

Примеры

• Обработка запроса

• Статистика

• Аутентификация

• Защита от CSRF

• Редиректы

• Кеширование

Middleware

Page 12: Web осень 2013 лекция 8

12

CSRF Атака

Page 13: Web осень 2013 лекция 8

13

• «Небезопасные» методы POST, PUT и

DELETE

• Установка cookie (csrftoken)

• Установка hidden поля

(csrfmiddlewaretoken) или заголовка (X-

CSRFToken)

CSRF в Django

Page 14: Web осень 2013 лекция 8

14

1. Для установки куки страница должна

отдаваться динамически

2. Кука может не ставиться, если передача

контекста идет через Context вместо

RequestContext

3. Скрытое поле ставится тегом {% csrf_token %},

используйте RequestContext (функция render)

4. Токен в ajax запросах удобнее передавать

заголовком

https://docs.djangoproject.com/en/dev/ref/contrib/csrf/

CSRF в Django

Page 15: Web осень 2013 лекция 8

15

Способы хранения

• Файловые сессии

• Сессии в БД

• Сессии в куках

Использование сессий

Page 16: Web осень 2013 лекция 8

16

def login(request): username = request.POST.get('username') try: user = User.objects.get(username=username) except User.DoesNotExist: return HttpResponse("Such user is not created.") # bad practice!!! if user.password == request.POST.get('password'): request.session['user_id'] = user.id return HttpResponse("You're logged in.") else: return HttpResponse("Your username and password didn't match.")

Использование сессий

Page 17: Web осень 2013 лекция 8

17

def logout(request): try: del request.session['user_id'] except KeyError: pass return HttpResponse("You're logged out.")

Использование сессий

Page 18: Web осень 2013 лекция 8

18

def makebold(fn): def wrapped(): return "<b>" + fn() + "</b>" return wrapped def makeitalic(fn): def wrapped(): return "<i>" + fn() + "</i>" return wrapped

Декораторы в python

Page 19: Web осень 2013 лекция 8

19

@makebold@makeitalicdef hello(): return "hello world" // hello = makebold(makeitalic(hello))  print hello() ## returns <b><i>hello world</i></b>

Декораторы в python

Page 20: Web осень 2013 лекция 8

20

@require_POSTdef vote_view(request): # only POST method is allowed pass либо url(r"^vote/", require_POST(vote)),

Декораторы для Views

Page 21: Web осень 2013 лекция 8

21

Примеры

Проверка HTTP методов

Проверка прав доступа

Кеширование

Django Views

Page 22: Web осень 2013 лекция 8

22

Django Auth

Page 23: Web осень 2013 лекция 8

23

Возможности

Пользователи

Права и группы доступа

Контроллеры login/logout

Тесная интеграция с админкой

Django Auth

Page 24: Web осень 2013 лекция 8

24

Модель User

username (обязательное поле)

first_name

last_name

email

password (обязательное поле)

is_staff

is_active

is_superuser

Django Auth

Page 25: Web осень 2013 лекция 8

25

Создание пользователей

from django.contrib.auth.models import User

user = User.objects.create_user('masha', '[email protected]', 'password')

Django Auth

Page 26: Web осень 2013 лекция 8

26

Login

def login_view(request): username = request.POST.get('username') password = request.POST.get('password') user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user) # Redirect to a success page. else: # 'disabled account' error message else: # 'invalid login' error message.

Django Auth

Page 27: Web осень 2013 лекция 8

27

Logout

def logout_view(request): logout(request) # Redirect to a success page.

Django Auth

Page 28: Web осень 2013 лекция 8

28

Login/Logout средствами django

1. Подключить в роутинге контроллеры входа и

выхода

(r'^accounts/login/$',

'django.contrib.auth.views.login')

(r'^accounts/logout/$',

'django.contrib.auth.views.logout')

2. Создать шаблоны

registration/login.html

registration/logged_out.html

3. GET параметр next для возврата

Django Auth

Page 29: Web осень 2013 лекция 8

29

Login/Logout средствами django

Страница авторизации:

LOGIN_URL = '/accounts/login/'

Страница профиля:

LOGIN_REDIRECT_URL = '/accounts/profile/'

Страница выхода:

LOGOUT_URL = '/accounts/logout/’

https://docs.djangoproject.com/en/dev/topics/auth/de

fault

/

Django Auth

Page 30: Web осень 2013 лекция 8

30

Проверка авторизации во views

def my_view(request): if not request.user.is_authenticated(): return redirect('/login/?next=%s' % request.path) user = request.user

@login_requireddef my_view(request): ...

Django Auth

Page 31: Web осень 2013 лекция 8

31

Проверка авторизации в шаблонах

{% if user.is_authenticated %} Welcome, {{ user.username }}{% else %} Please log in.{% endif %}

Django Auth

Page 32: Web осень 2013 лекция 8

32

Расширение текущего пользователя

from django.contrib.auth.models import User class UserProfile(models.Model): user = models.OneToOneField(User, related_name='profile') rating = models.PositiveIntegerField()

>>> u = User.objects.get(username='masha')>>> print u.profile.rating

Django Auth

Page 33: Web осень 2013 лекция 8

33

Расширение текущего пользователя

• Другой уникальный ключ пользователя (email вместо

username)

• Дополнительные поля (в т. ч. обязательные)

 

https://docs.djangoproject.com/en/dev/topics/auth/customizing

/#extending-the-existing-user-

model

Django Auth

Page 34: Web осень 2013 лекция 8

34

Class Based Views

Page 35: Web осень 2013 лекция 8

35

• TemplateView

• RedirectView

• ListView

• DetailView

• FormView

• CreateView

• UpdateView

• DeleteView

• ArchiveIndexView

• YearArchiveView

• …

Class Based Views

Page 36: Web осень 2013 лекция 8

36

Контроллер-функция (пример 1)def post_detail(request, pk): try: object = Post.objects.get(pk=pk) except Post.DoesNotExist: raise Http404 return render( request, 'blog/post_detail.html', {'object': object} ) urlpatterns = patterns('', url(r'^post/(?P<pk>\d+)/$', post_detail, name='post_detail'),)

Class Based Views

Page 37: Web осень 2013 лекция 8

37

Контроллер-класс (пример 1)

class PostDetail(generic.DetailView): model=Post 

urlpatterns = patterns('', url(r'^post/(?P<pk>\d+)/$', PostDetail.as_view(), name='post_detail'),)

Class Based Views

Page 38: Web осень 2013 лекция 8

38

Контроллер-функция (пример 2)def post_list(request): paginator = Paginator(Post.objects.all(), 25)  page = request.GET.get('page') try: posts = paginator.page(page) except PageNotAnInteger: posts = paginator.page(1) except EmptyPage: posts = paginator.page(paginator.num_pages) return render( request, 'blog/post_list.html', {'object_list': posts} )

Class Based Views

Page 39: Web осень 2013 лекция 8

39

Контроллер-класс (пример 2)

class PostList(generic.ListView): model = Post paginate_by = 25

Class Based Views

Page 40: Web осень 2013 лекция 8

40

Контроллер-функция (пример 3)

@login_requireddef category(request, pk): cat = get_object_or_404(Category, pk=pk) post_list = Post.objects.filter(category=cat) return render(request, 'blog/category.html', { 'category': cat, 'post_list' : post_list })

Class Based Views

Page 41: Web осень 2013 лекция 8

41

Контроллер-класс (пример 3)class CategoryListView(generic.ListView): template_name = 'blog/category.html’

def get_queryset(self): self.cat = get_object_or_404(Category, pk=self.kwargs['pk']) return Post.objects.filter(category=self.cat)

@method_decorator(login_required) def dispatch(self, *args, **kwargs): return super(CategoryListView, self).dispatch(*args, **kwargs)

def get_context_data(self, **kwargs): context = super(CategoryListView, self).get_context_data(**kwargs) context['category'] = self.cat return context

Class Based Views

Page 42: Web осень 2013 лекция 8

42

Class Based Views

http://ccbv.co.uk/

Page 43: Web осень 2013 лекция 8

43

Фильтры и теги в шаблонизаторе

Page 44: Web осень 2013 лекция 8

44

Модель

class Post(models.Model): …  @models.permalink def get_absolute_url(self): return ('post_detail', (self.pk,))   # либо def get_absolute_url(self): return reverse('post_detail', args=(self.pk,))

Построение урлов

Page 45: Web осень 2013 лекция 8

45

Роутинг

url(r'^(?P<pk>\d+)/$', 'post_detail', name='post_detail'), Шаблоны <a href="{{ post.get_absolute_url }}">{{ post }}</a>

<a href="{% url 'post_detail' post.pk %}">{{ post }}</a>

Построение урлов

Page 46: Web осень 2013 лекция 8

46

Фильтр

{{ post.content|cut:"<cut>" }}

 

Simple Tag

{% current_time "%Y-%m-%d %I:%M %p" %}

 

Inclusion tag

{% popular_tags 20 %}

Фильтры и теги в шаблонизаторе

Page 47: Web осень 2013 лекция 8

47

Assignment tags

{% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}

 

Блок с закрывающим тегом

{% switch %} {% endswitch %}

Фильтры и теги в шаблонизаторе

Page 48: Web осень 2013 лекция 8

48

Добавление тега

blog/ __init__.py models.py templatetags/ __init__.py blog_tags.py tests.py views.py

Фильтры и теги в шаблонизаторе

Page 49: Web осень 2013 лекция 8

49

from django import templatefrom blog.models import Post

register = template.Library() @register.inclusion_tag('blog/tags/lastposts.html')def last_posts():    return {'post_list': Post.objects.all()[:5]}

Фильтры и теги в шаблонизаторе

Page 50: Web осень 2013 лекция 8

50

Шаблон

<ul>{% for object in post_list %} <li><a href="{{ object.get_absolute_url}}">{{ object }}</a></li>{% endfor %}</ul>

Подключение{% load blog_tags %}{% last_posts %}

https://docs.djangoproject.com/en/dev/howto/custom-template-tags/

Фильтры и теги в шаблонизаторе

Page 51: Web осень 2013 лекция 8

51

Приложения из коробки

Page 52: Web осень 2013 лекция 8

52

Подключение

from django.conf.urls import patterns, include, url # Uncomment the next two lines to enable the admin:from django.contrib import adminadmin.autodiscover() urlpatterns = patterns('',  … # Uncomment the next line to enable the admin: url(r'^admin/', include(admin.site.urls)),)

Административная консоль

Page 53: Web осень 2013 лекция 8

53

Подключение

from blog.models import Category, Postfrom django.contrib import admin class PostAdmin(admin.ModelAdmin): date_hierarchy = 'creation_date' list_display = ('title', 'category') list_filter = ('category',)  search_fields = ('title',) admin.site.register(Category)admin.site.register(Post, PostAdmin)

Административная консоль

Page 54: Web осень 2013 лекция 8

54

Административная консоль

Page 55: Web осень 2013 лекция 8

55

Административная консоль

Page 56: Web осень 2013 лекция 8

56

Административная консоль

Page 57: Web осень 2013 лекция 8

57

Возможности

Сбор статики

Отдача статики (???)

Шаблонные теги

Сбор статики

STATIC_ROOT = "/var/www/blog.me/static/"

python manage.py collectstatic

Static Files

Page 58: Web осень 2013 лекция 8

58

ContentTypes framework

Article

id

title

Photo

idtitle

Tag

id

title

TaggedItem

id

content_type_idobject_id

tag_id

Page 59: Web осень 2013 лекция 8

59

Оптимизация

производительности

Page 60: Web осень 2013 лекция 8

60

Схема кеширования

Ищем значение в кеше

Если находим:

возвращаем значение из кеша

Если нет:

генерируем значение

сохраняем в кеш

возвращаем значение

Кеширование

Page 61: Web осень 2013 лекция 8

61

Условия кеширования

1. Быстрый доступ к кешу

2. Высокая вероятность использования кеша

3. Временное хранилище

Кеширование

Page 62: Web осень 2013 лекция 8

62

Поддержка

1. Memcached

2. База данных

3. Файловая система

4. Локальная память

5. Dummy (для разработки)

Кеширование в Django

Page 63: Web осень 2013 лекция 8

63

Уровни кеширования

1. Весь сайт

2. Контроллер

3. Часть шаблона

4. Часть данных (ручное управление)

Кеширование в Django

Page 64: Web осень 2013 лекция 8

64

Premature optimization is the root of all evil in programming.

• Оптимизация запросов к базе данных

• Кеширование данных

• Кеширование шаблонов

Производительность Django

Page 65: Web осень 2013 лекция 8

65

• Профилируйте запросы с Django Debug Toolbar

• Используйте правильные индексы (db_index)

• Делайте выборки по тем полям, которые вам

нужны (методы only, values and values_list)

• Не делайте лишних запросов к БД (методы

select_related и prefetch_related, тег {% with %},

внешние ключи)

• Python не должен делать работу за БД (методы

count, exist)

Производительность Django

Page 66: Web осень 2013 лекция 8

66

Избегайте дублирования кода DRY

Делайте короче и проще KISS

Полезные советы

Page 67: Web осень 2013 лекция 8

67

1. Авторизация и регистрация пользователей на сайте

2. Блок с последними зарегистрированными пользователями

 

http://tp.mail.ru/blog/Web/935.html

Домашнее задание

Page 68: Web осень 2013 лекция 8

Спасибо за внимание

Александр Бекбулатов, [email protected]

u