Upload
technopark
View
268
Download
0
Embed Size (px)
Citation preview
Работа с базой. Django ORM
Александр Бекбулатов
На клиенте
• Cookie (до 4Кб)
• HTML5 Web Storage (до 5Мб)
• В памяти
• На диске
• На диске и в памяти
Где хранить данные
2
На сервере
1. Представление о СУБД
2. Проектирование баз данных
3. Основные операции SQL
4. Работа с базами данных в python
5. Работа с базами данных в django
Работа с базой
3
База данных
взаимосвязанная информация (данные) об
объектах, которая организованна специальным
образом и хранится на каком-либо носителе.
совокупность программных и лингвистических
средств общего или специального назначения,
обеспечивающих управление созданием и
использованием баз данных.
Представление о СУБД
4
СУБД
Функции СУБД
управление данными на дисках и в оперативной памяти
журнализация изменений, резервное копирование и
восстановление базы данных после сбоев;
поддержка языков БД (язык определения данных, язык
манипулирования данными).
Представление о СУБД
5
Таблица – отношение, 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
Реляционная модель данных
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
Задачи проектирования
Обеспечение хранения в БД всей необходимой информации.
Обеспечение возможности получения данных по всем
необходимым запросам.
Сокращение избыточности и дублирования данных.
Обеспечение целостности данных (правильности их
содержания): исключение противоречий в содержании данных,
исключение их потери и т.д.
Реляционная модель данных
8
Проектирование на практике
Логическое разделение сущностей
Выделение синтетических первичных ключей
Связи 1:N, N:1 реализуются через внешний ключ
Связи N:M реализуются через промежуточную таблицу
Атрибут с фиксированным числом значений – внешняя
таблица либо поле типа enum
Реляционная модель данных
9
Основные операции SQL
10
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
Агрегатные функции:
COUNT, SUM, AVG, GROUP_CONCAT
SELECT name, count(id) cnt
FROM users
GROUP BY name
ORDER BY cnt
HAVING cnt > 1
SELECT. Агрегация
12
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
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
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
Проектирование на практике
Создавать индексы для полей, по которым происходит JOIN
Создавать индексы для полей, по которым фильтруются записи (WHERE)
Создавать индексы для полей, по которым идет сортировка (ORDER)
Проверять план выполнения запроса (EXPLAIN)
Управление оптимизатором (принудительное использование индекса, порядок соединения таблиц)
Индексы
16
Работа с базами данных в
python
17
import MySQLdb
db = MySQLdb.connect(
host="localhost", user="joebob",
passwd="moonpie", db="thangs")
cursor = db.cursor()
MySQLdb
18
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
cursor.executemany(
"INSERT INTO users (name, age) VALUES (%s,
%s)",
[
("Igor", 18 ),
("Petr", 16 ),
("Dasha", 17 )
])
db.close()
MySQLdb
20
Зачем плейсхолдеры?
email = "' OR '1'='1"
cursor.execute("SELECT * FROM users WHERE email =
'%s'" % email)
Документация
http://mysql-python.sourceforge.net/MySQLdb.html
MySQLdb
21
Работа с базами данных в
django
22
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
>>> 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
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
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
Модели и типы данных
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
Свойства полей моделей
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
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
ForeignKey, OneToOneField
ForeignKey = IntegerField + Constraint
OneToOneField = ForeignKey + unique
post.category – связанный объект (отдельный запрос к
связанной сущности)post.category_id – значение атрибута модели (просто id)
В обратную сторону:
category.post_set.all()
Связи между таблицами
30
ForeignKey, OneToOneField
Изменение/удаление внешнего ключа
• RESTRICT -> models.PROTECT
• CASCADE -> models.CASCADE
• SET NULL -> models.SET_NULL
• NO ACTION -> models.DO_NOTHING
Связи между таблицами
31
Связи между таблицами
32
Post
id
title
content
creation_date
category
Tagidtitledescription
PostTag
post_idtag_id
ManyToManyField
ManyToManyField
post.tags – related managerpost.tags.all()
В обратную сторону:tag.post_set.all()
Связи между таблицами
33
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
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
>>> # Выборка
>>> 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
>>> 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
Debug Toolbarhttps://github.com/django-debug-
toolbar/django-debug-toolbar
38
Методы 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
Методы RelatedManager
.create(**kwargs)
.add(obj1[, obj2, ...])
.remove(obj1[, obj2, ...])
.clear()
Manager и RelatedManager
40
Queryset ленивый
qs = Category.objects.all()
if not user.is_admin:
qs = qs.filter(active=True)
print qs.count()
Особенности QuerySet
41
Избегайте лишних запросов в базу
Foreign key кешируется
post.category
Queryset – нет.
Если нужно использовать несколько раз – кешируйте явно
question_list = list(Question.objects.all())
Особенности QuerySet
42
Атомарное обновление
Question.objects.filter(pk=10) \
.update(rating=models.F('rating') + 1)
https://docs.djangoproject.com/en/dev/ref/models/querysets/
Особенности QuerySet
43
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
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ask_db',
'USER': 'ask_user',
'PASSWORD': 'secret',
'HOST': '',
'PORT': '',
}
}
Подключение базы
45
Проверка моделей
python manage.py validate
Вывод SQL
python manage.py sqlall <app_name>
Выполнение SQL в базе
python manage.py syncdb
Полезные команды
46
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
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
1. DROP DATABASE, CREATE DATABASE
2. DROP TABLE, CREATE TABLE
3. ALTER TABLE
4. South
Миграции
49
• Автоматическое создание миграций
• Поддержка различных СУБД
• Прямые и обратные миграции
South
50
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
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
1. Установить Django Debug Toolbar
2. Установить MySQL, python-mysqldb. Создать базу данных и пользователя для работы с базой
3. Описать модели для проекта «Вопросы и ответы»
4. Наполнить базу тестовыми данными
53
Спасибо за внимание
Александр Бекбулатов, [email protected]