54
Работа с базой. Django ORM Александр Бекбулатов

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

Embed Size (px)

Citation preview

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

Работа с базой. Django ORM

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

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

На клиенте

• Cookie (до 4Кб)

• HTML5 Web Storage (до 5Мб)

• В памяти

• На диске

• На диске и в памяти

Где хранить данные

2

На сервере

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

1. Представление о СУБД

2. Проектирование баз данных

3. Основные операции SQL

4. Работа с базами данных в python

5. Работа с базами данных в django

Работа с базой

3

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

База данных

взаимосвязанная информация (данные) об

объектах, которая организованна специальным

образом и хранится на каком-либо носителе.

совокупность программных и лингвистических

средств общего или специального назначения,

обеспечивающих управление созданием и

использованием баз данных.

Представление о СУБД

4

СУБД

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

Функции СУБД

управление данными на дисках и в оперативной памяти

журнализация изменений, резервное копирование и

восстановление базы данных после сбоев;

поддержка языков БД (язык определения данных, язык

манипулирования данными).

Представление о СУБД

5

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

Таблица – отношение, relation

Строка – кортеж, tuple

Столбец – атрибут, column

Реляционная модель данных

6

Car

Key Model Color Year

1 Toyota Camry 1 2010

2 Audi A4 2 2013

3 Honda Civic 2 2013

Color

Key Name

1 Black

2 Pink

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

Реляционная модель данных

7

Cousine

Key Name Type

1 Baked fish Main Course

2 Pork Chops Main Course

CousineIngredient

CousineKey IngredientKey

1 3

2 1

Ingredient

Key Name

1 Pork

2 Lamb

3 Salmon

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

Задачи проектирования

Обеспечение хранения в БД всей необходимой информации.

Обеспечение возможности получения данных по всем

необходимым запросам.

Сокращение избыточности и дублирования данных.

Обеспечение целостности данных (правильности их

содержания): исключение противоречий в содержании данных,

исключение их потери и т.д.

Реляционная модель данных

8

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

Проектирование на практике

Логическое разделение сущностей

Выделение синтетических первичных ключей

Связи 1:N, N:1 реализуются через внешний ключ

Связи N:M реализуются через промежуточную таблицу

Атрибут с фиксированным числом значений – внешняя

таблица либо поле типа enum

Реляционная модель данных

9

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

Основные операции SQL

10

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

SELECT * FROM users WHERE age > 10;

SELECT * FROM users WHERE name = 'masha';

SELECT max(age) FROM users;

SELECT id, name, length(name) AS len

FROM users

WHERE email LIKE '%@mail.ru' AND age > 10

ORDER BY name DESC

LIMIT 10 OFFSET 15

SELECT

11

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

Агрегатные функции:

COUNT, SUM, AVG, GROUP_CONCAT

SELECT name, count(id) cnt

FROM users

GROUP BY name

ORDER BY cnt

HAVING cnt > 1

SELECT. Агрегация

12

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

SELECT h.name, a.name

FROM heroes h, abilities a

WHERE h.id = a.hero_id

SELECT h.name, a.name

FROM heroes h

INNER JOIN abilities a ON h.id = a.hero_id

SELECT h.name, a.name

FROM heroes h

LEFT JOIN abilities a ON h.id = a.hero_id

SELECT. JOIN

13

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

SELECT title

FROM article t1

JOIN (

SELECT rubric_id, MAX(id) max_id

FROM article

GROUP BY rubric_id LIMIT 5

) t2

ON t1.id = t2.max_id;

SELECT. Вложенные запросы

14

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

INSERT INTO users (name, age) VALUES ('Petr', 10);

UPDATE users SET age = 20 WHERE name = 'Petr';

UPDATE users SET rating = rating + 1;

DELETE FROM users WHERE name = 'Masha';

DELETE FROM users WHERE age > 150;

INSERT, UPDATE, DELETE

15

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

Проектирование на практике

Создавать индексы для полей, по которым происходит JOIN

Создавать индексы для полей, по которым фильтруются записи (WHERE)

Создавать индексы для полей, по которым идет сортировка (ORDER)

Проверять план выполнения запроса (EXPLAIN)

Управление оптимизатором (принудительное использование индекса, порядок соединения таблиц)

Индексы

16

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

Работа с базами данных в

python

17

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

import MySQLdb

db = MySQLdb.connect(

host="localhost", user="joebob",

passwd="moonpie", db="thangs")

cursor = db.cursor()

MySQLdb

18

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

cursor.execute('update users set age = age + 1

where name = %s', (name,))

cursor.execute('select * from users')

users = cursor.fetchall()

cursor.execute('select * from users where name =

%s', (name,))

user = cursor.fetchone()

MySQLdb

19

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

cursor.executemany(

"INSERT INTO users (name, age) VALUES (%s,

%s)",

[

("Igor", 18 ),

("Petr", 16 ),

("Dasha", 17 )

])

db.close()

MySQLdb

20

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

Зачем плейсхолдеры?

email = "' OR '1'='1"

cursor.execute("SELECT * FROM users WHERE email =

'%s'" % email)

Документация

http://mysql-python.sourceforge.net/MySQLdb.html

MySQLdb

21

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

Работа с базами данных в

django

22

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

class Employee(object):

def __init__(self, name, salary):

self.name = name

self.salary = salary

def __unicode__(self):

return unicode(self.name)

def get_info(self):

return "Name : %s, Salary: %s" % (self.name,

self.salary)

class Programmer(Employee):

def __init__(self, name, salary, lang):

super(Programmer, self).__init__(name,

salary)

self.lang = lang

Классы в Python

23

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

>>> e1 = Programmer(u'Vasya', 100, 'VB')

>>> print u'Welcome %s' % e1

Welcome Vasya

>>> e1.get_info()

u'Name : Vasya, Salary: 100'

>>> e1.lang

'VB'

Классы в Python

24

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

cursor.execute('select * from users where age >

18')

for user in cursor.fetchall():

pk, name, age = user

print name

VS

for user in User.objects.filter(age__gt=18):

print user.name

Raw SQL vs ORM

25

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

class Post(models.Model):

title = models.CharField(max_length=255)

content = models.TextField()

creation_date =

models.DateTimeField(default=datetime.datetime.now)

def __unicode__(self):

return self.title

def get_absolute_url(self):

return '/post/%d/' % self.pk

def get_next_post(self):

"""Return the next entry"""

class Meta:

ordering = ['-creation_date’]

Модели и типы данных

26

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

Модели и типы данных

27

Типы данных Mysql Типы полей Django

varchar(N) CharField

EmailField

SlugField

ImageField

longtext TextField

tinyint(1) BooleanField

int(11) IntegerField

smallint(5) unsigned PositiveSmallIntegerField

date DateField

datetime DateTimeField

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

Свойства полей моделей

null, blank, choices, db_index, default, editable,

help_text, max_length, primary_key, unique, unique_for_date,

unique_for_month, unique_for_year, verbose_name

https://docs.djangoproject.com/en/dev/ref/models/fields/

Модели и типы данных

28

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

class Post(models.Model):

title = models.CharField(max_length=255)

content = models.TextField()

creation_date =

models.DateTimeField(default=datetime.datetime.now)

category = models.ForeignKey(Category,

on_delete=models.SET_NULL)

tags = models.ManyToManyField(Tag)

Связи между таблицами

29

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

ForeignKey, OneToOneField

ForeignKey = IntegerField + Constraint

OneToOneField = ForeignKey + unique

post.category – связанный объект (отдельный запрос к

связанной сущности)post.category_id – значение атрибута модели (просто id)

В обратную сторону:

category.post_set.all()

Связи между таблицами

30

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

ForeignKey, OneToOneField

Изменение/удаление внешнего ключа

• RESTRICT -> models.PROTECT

• CASCADE -> models.CASCADE

• SET NULL -> models.SET_NULL

• NO ACTION -> models.DO_NOTHING

Связи между таблицами

31

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

Связи между таблицами

32

Post

id

title

content

creation_date

category

Tagidtitledescription

PostTag

post_idtag_id

ManyToManyField

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

ManyToManyField

post.tags – related managerpost.tags.all()

В обратную сторону:tag.post_set.all()

Связи между таблицами

33

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

python manage.py shell

>>> from blog.models import Category, Post

>>> from django.db import connection

>>> # Вставка и замена

>>> c = Category(title="Python")

>>> c.save()

>>> c.id

1

>>> c.title="About Python"

>>> c.save()

ORM API

34

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

python manage.py shell

>>> print '\n'.join(q['sql'] for q in

connection.queries)

INSERT INTO `blog_category` (`title`,

`description`) VALUES ('Python', '')

SELECT (1) AS `a` FROM `blog_category` WHERE

`blog_category`.`id` = 1 LIMIT 1

UPDATE `blog_category` SET `title` = 'About

Python', `description` = '' WHERE

`blog_category`.`id` = 1

ORM API

35

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

>>> # Выборка

>>> Category.objects.all()

[<Category: About Python>]

>>> print Category.objects.all().query

SELECT `blog_category`.`id`,

`blog_category`.`title`,

`blog_category`.`description` FROM `blog_category`

>>> Category.objects.filter(id=1)

[<Category: About Python>]

>>> c = Category.objects.get(id=1)

>>> c

<Category: About Python>

>>> c.post_set.all()

[]

ORM API

36

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

>>> c.post_set.create(title="New post",

content="Many words")

<Post: New post>

>>> c.post_set.count()

1

>>> p = Post.objects.get(title="New post")

>>> p.category

<Category: About Python>

>>> p.category_id

1

>>> Post.objects.filter(category__title="About

Python")

<Post: New post>

>>> c.delete()

ORM API

37

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

Debug Toolbarhttps://github.com/django-debug-

toolbar/django-debug-toolbar

38

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

Методы Manager

slice [10:20]

.all(), .filter(), .exclude(), .order_by()

.values(), .values_list()

.get(), .get_or_create(), .count(), .exists()

.select_related(), .prefetch_related()

.update(), .delete()

Manager и RelatedManager

39

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

Методы RelatedManager

.create(**kwargs)

.add(obj1[, obj2, ...])

.remove(obj1[, obj2, ...])

.clear()

Manager и RelatedManager

40

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

Queryset ленивый

qs = Category.objects.all()

if not user.is_admin:

qs = qs.filter(active=True)

print qs.count()

Особенности QuerySet

41

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

Избегайте лишних запросов в базу

Foreign key кешируется

post.category

Queryset – нет.

Если нужно использовать несколько раз – кешируйте явно

question_list = list(Question.objects.all())

Особенности QuerySet

42

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

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

Question.objects.filter(pk=10) \

.update(rating=models.F('rating') + 1)

https://docs.djangoproject.com/en/dev/ref/models/querysets/

Особенности QuerySet

43

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

CREATE DATABASE ask_db CHARACTER SET utf8

COLLATE utf8_general_ci;

GRANT ALL PRIVILEGES ON ask_db.* TO

ask_user@localhost identified BY 'secret';

Создание базы

44

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

DATABASES = {

'default': {

'ENGINE': 'django.db.backends.mysql',

'NAME': 'ask_db',

'USER': 'ask_user',

'PASSWORD': 'secret',

'HOST': '',

'PORT': '',

}

}

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

45

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

Проверка моделей

python manage.py validate

Вывод SQL

python manage.py sqlall <app_name>

Выполнение SQL в базе

python manage.py syncdb

Полезные команды

46

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

CREATE TABLE `blog_post` (

`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,

`title` varchar(255) NOT NULL,

`content` longtext NOT NULL,

`creation_date` datetime NOT NULL,

`category_id` integer NOT NULL

)

;

ALTER TABLE `blog_post` ADD CONSTRAINT

`category_id_refs_id_e0428883` FOREIGN KEY

(`category_id`) REFERENCES `blog_category` (`id`);

ALTER TABLE `blog_post_tags` ADD CONSTRAINT

`post_id_refs_id_c9e37cca` FOREIGN KEY (`post_id`)

REFERENCES `blog_post` (`id`);

CREATE INDEX `blog_post_42dc49bc` ON `blog_post`

(`category_id`);

SQL. Создание таблиц

47

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

DROP TABLE blog_post;

ALTER TABLE users ADD COLUMN language

enum('ru', 'en') NOT NULL DEFAULT 'ru' after

name;

ALTER TABLE users DROP COLUMN langauge;

ALTER TABLE users ADD INDEX ('name');

ALTER TABLE users CHANGE nickname fullname

varchar(255) NOT NULL;

SQL. Удаление и изменение таблиц

48

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

1. DROP DATABASE, CREATE DATABASE

2. DROP TABLE, CREATE TABLE

3. ALTER TABLE

4. South

Миграции

49

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

• Автоматическое создание миграций

• Поддержка различных СУБД

• Прямые и обратные миграции

South

50

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

1. Создать миграцию

./manage.py schemamigration ask --initial

2. Применить миграцию

./manage.py migrate ask

3. Изменить модель

4. Создать миграцию

./manage.py schemamigration ask --auto

5. Применить миграцию

./manage.py migrate ask

South Workflow

51

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

1. MySQL http://dev.mysql.com/doc/refman/5.5/en/index.html

2. Mysqldb http://mysql-python.sourceforge.net/MySQLdb.html

3. Django http://docs.djangoproject.com/en/dev/

4. Django Debug Toolbar https://github.com/django-debug-toolbar/django-debug-toolbar

52

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

1. Установить Django Debug Toolbar

2. Установить MySQL, python-mysqldb. Создать базу данных и пользователя для работы с базой

3. Описать модели для проекта «Вопросы и ответы»

4. Наполнить базу тестовыми данными

53

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

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

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