Пособие по языку Python 3

    Данная книга является кратким и информативным пособием с большим количеством примеров по языку Python версии 3, по структуре разбита на три главы, разделенные по разделам.

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

    Первая глава посвящена общим возможностям и синтаксису конструкций языка Python.

    Вторая глава посвящена графическим приложениям.

    Третья глава посвящена django.

    Данную книгу я посвящаю своей  семье. Благодаря их терпению я смог выделить время для написания и составления примеров.

   В данной книге я по минимуму буду «разводить воду», больше будет упор на практические примеры, чтобы донести возможности языка. Все примеры выполнялись под операционной системой Windows 7,  но и без проблем применяемы мной в работе и на ОС FreeBSD и Linux.

  Взять дистрибутив можно с официального сайта: https://www.python.org/

  Данное пособие написано автором проекта http://snakeproject.ru/ Козловым Михаилом, Вы можете посредством обратной связи на сайте оставить отзыв или предложение.

 

Оглавление

1.     Вводная часть

1.0 Введение

1.1 Первая программа

1.2 Примеры с выводом на экран

1.3 Переменные и типы данных

1.4 Арифметические операторы

1.5 Интерактивный ввод

1.6 Работа со строками

1.7 Списки и кортежи

1.8 Циклы и условия

1.9 Функции

2.0 Базовые навыки работы с модулями.

2.1 Работа с файлами

2.2 Работа с ftp

2.3 Регулярные выражения

2.4 Прехват ошибки(try-except)

2.5 Встроенные функции

2.6 Основы ООП

2.7 Сокеты(пример простого сетевого приложения)

2.8 Основы работы с базами данных(sqlite)

2.     Графические приложения

2.0 PyQt: Знакомство

2.1 PyQt : Знакомство в ООП стиле

2.2 PyQt : Отцентровка, messagebox, контекстная подсказка

2.3 Визуальные эффекты, включение виджетов, выход из программы

2.4 PyQt : Позиционирование, буфер обмена

2.5 PyQt: меню, панель задач, строка состояния

2.6 PyQt : простой текстовой редактор, диалоговые окна

3.     Основы django

3.0 Установка django на примере windows 7

3.1 Простое приложение, простая модель

3.2 Изменения в базе данных

3.3 Админка

3.4 Сессии

3.5 Запросы и чистый SQL

3.6 Простые формы

 

 

1.     Вводная часть

    1.0 Введение

  Итак, поехали! Язык Python в изучении невероятно прост, после установки дистрибутива я буду работать либо посредством интерактивной среды разработки IDLE (Вы можете например найти ее в «пуске»), либо писать в скриптах с расширением .py или .pyw (варианты для отладки и без).

1.1  Первая программа

  Первая «классическая программа» с выводом строки на экран:

>>> print("Hello World!")

Hello World!

1.2  Примеры с выводом на экран

>>> 1+34

35

>>> print("123 "+" 456")

123  456

  Примеры с форматированием вывода(%s,%d,%f для работы со строками, целыми и числами с плавающей точкой):

>>> print("%s and %s" % ("str1", "str2"))

str1 and str2

>>> print("%12d and %0.2f" % (2014, 23.1234))

        2014 and 23.12

1.3  Переменные и типы данных

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

Частоиспользуемые типы данных в Python:

Категория

Тип

Описание

Числа

int

целые

 

float

с плавающей точкой

 

bool

логические(true\false)

 

complex

комплексные

Последовательности

str

строки

 

list

списки

 

typle

кортежи

None

Type(None)

пустой объект

 

  Рассмотрим примеры объявления переменных и работы с ними.

>>> per = "AnyString"

>>> perNew = "NewString"

>>> perMix = per+" "+perNew

>>> perMix

'AnyString NewString'

>>> per*3

'AnyStringAnyStringAnyString'

>>> per[3]

'S'

>>> per[3:5]

'St'

1.4  Арифметические операторы

Рассмотрим примеры с арифметическими выражениями.

>>> 2+2 #Сложение

4

>>> 5-3 #Вычитание

2

>>> 8/2 #Деление

4.0

>>> 45*3 #Умножение

135

>>> (5+5)*5 #Скобки

50

>>> 13%2 #Деление по модулю

1

>>> 9//2 #Деление с усечением

4

1.5  Интерактивный ввод

>>> a = input()

AnyString

>>> a

'AnyString'

1.6  Работа со строками

  Поиск и замена в строке

>>> 'первый и второй'.replace('второй', 'первый')

'первый и первый'

  Длина строки

>>> len(per)

9

  Вывод на нескольких строках

>>> print("""

String 1 1 1

    String 2 2 2

      String 3 3 3

""")

 

String 1 1 1

    String 2 2 2

      String 3 3 3

#Объединение строк используя «разделитель»

>>> s = ","

>>> s1 = "1"; s2 = "2"; s3 = "3";

>>> st = [s1,s2,s3]

>>> s.join(st)

'1,2,3'

#Перевод в большой и малые регистры

>>> s = "aBcD"

>>> s.upper()

'ABCD'

>>> s.lower()

'abcd'

#Проверка на:

>>> s = "123123"

#Все ли цифровые символы в строке

>>> s.isdigit()

True

#Все ли буквенные символы в строке

>>> s.isalpha()

False

#Все ли буквенно-цифровые символы в строке

>>> s.isalnum()

True

 

1.7  Списки и кортежи

Списки это фактически массивы, но типы значений могут различаться.

Кортежи по сути являются неизменяемыми конструкциями типа «ключ-значение».

Примеры объявления и распространенных действий со списками.

#Объявление

>>> a = ['1', '2', 1, 2]

>>> a

['1', '2', 1, 2]

#Обращение

>>> a[0]

'1'

>>> a[1:3]

['2', 1]

>>> a[2] = 123

>>> a[1:3]

['2', 123]

#Изменить значение

>>> a[:0] = [1212, '222']

>>> a

[1212, '222', '1', '2', 123, 2]

#Очистить

>>> a[:] = []

>>> a

[]

#Длина

>>> len(a)

0

#Добавление элемента

>>> a.append('555')

>>> a

['555']

#Варианты удаления элементов

>>> a.remove('555')

>>> del a[0]

#Посчитаем количество вхождений в список

>>> a = ['1', '2', 1, 2]

>>> a.count(2)

1

>>> a = ['1', '2', 1, 2, 2, 2, 3, 3]

>>> a.count(2)

3

#Применение некоторой функции ко всем элементам списка - map()

>>> a1 = [1, 2, 3, 4, 5, 6]

>>> a2 = [6, 5, 4, 3, 2, 1]

>>> print map(lambda x, y: x*y, a1, a2)

[6, 10, 12, 12, 10, 6]

#Удалим элемент по позиции

>>> a.pop(2)

1

>>> a

['1', '2', 2, 2, 2, 3, 3]

Примеры объявления и работы с кортежами.

#Объявление

>>> per = {'name': 'ira', 'lastname': 'lomova'}

#Добавить ключ и значение

>>> per['age'] = 25

#Обращение к значению ключа

>>> per['name']

'ira'

#Проверка на присутствие в кортеже ключа

>>> 'name' in per

True

#Перебор значений и ключей

>>> for key, value in per.items():

    print(key, value)

 

   

name ira

age 25

lastname lomova

1.8  Циклы и условия

Рассмотрим конструкции циклов while, for и оператора проверки условия(оператора ветвления)

While(«выполняй пока условие верно»)

>>> a=1

>>> while a!=3:

    print(a)

    a = a+1

 

   

1

2

 

>>> a=1

>>> while a!=3:

    print(a, end='   ')

    a=a+1

 

   

1   2

For(перебирает значения)

>>> a = ['1', '2', '3']

>>> for x in a:

    print(x)

   

1

2

3

#Вариант с генератором чисел range

>>> for i in range(3):

    print(i)

   

0

1

2

#Вариант с генератором чисел range с определенным диапазоном чисел

>>> for i in range(3, 7):

    print(i)

 

   

3

4

5

6

  IF(проверка условия)

  Имеет необязательные блоки elif и else. Количество дополнительных проверок elif может быть несколько или одно, блок else отработает в ситуации, когда ни одно условие не выполнилось.

>>> per = int(input('Введи число: '))

Введи число: 123

>>> if per > 100:

    print('per больше 100')

elif per < 100:

    print('per меньше 100')

else:

    print('per равно 0')

 

per больше 100

1.9  Функции

  Функции могут содержать инструкцию return, которая возвращает значение(его можно например занести в переменную).

  В другом случае функция может использоваться без ключевого слова return и отрабатывать как «кусок кода» или как «хранимая процедура».

  Помимо этого функция может принимать аргументы, иметь обязательные и аргументы с уже заданными значениями.

Примеры функций.

#Объявление функции с одним обязательным аргументом

#return не используется

>>> def func(x):

    if x>0:

        print('x > 0')

    else:

        print('x <= 0')

 

  #Вызов с передачей аргумента     

>>> func(3)

x > 0

#return возвратит значение, которое можно записать в переменную

>>> def func(x):

    if x>0:

        z = x + 1

        return z

    else:

        z = x - 1

        return z

 

   

>>>per =  func(3)

>>>per

4

Примеры с обязательными и необязательными аргументами.

>>> def func(a, b, c=4): # c - необязательный аргумент

    return a + b + c

 

>>> func(1, 2) # a = 1, b = 2, c = 4 (по умолчанию)

7

>>> func(1, 2, 3) # a = 1, b = 2, c = 3

6

>>> func(a=1, b=1) # a = 1, b = 1, c = 4

6

Произвольное количество аргументов.

>>> def func(*args):

    return args

 

>>> func(1,2,3,4,5)

(1,2,3,4,5)

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

>>> def func(**kwargs):

    return kwargs

 

>>> func(a=1, b=2, c=3)

{'a': 1, 'b': 2, 'c': 3}

2.0 Базовые навыки работы с модулями.

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

Модули представлены объектами-модулями, атрибутами которох являются имена, определенные в модулях

 

Модули по тематике из стандартной библиотеки Python:

Сервисы периода выполнения: sys, atexit, copy, traceback, math, cmath, random, time, calendar, datetime, sets, array, struct, itertools, locale, gettext.

Поддержка цикла разработки: pdb, hotshot, profile, unittest, pydoc. Пакеты docutils, distutils.

Взаимодействие с ОС (файлы, процессы): os, os.path, getopt, glob, popen2, shutil, select, signal, stat, tempfile.

Обработка текстов: string, re, StringIO, codecs, difflib, mmap, sgmllib, htmllib, htmlentitydefs. Пакет xml.

Многопоточные вычисления: threading, thread, Queue.

Хранение данных. Архивация: pickle, shelve, anydbm, gdbm, gzip, zlib, zipfile, bz2, csv, tarfile.

Платформо-зависимые модули. Для UNIX: commands, pwd, grp, fcntl, resource, termios, readline, rlcompleter. Для Windows: msvcrt, _winreg, winsound.

Поддержка сети. Протоколы Интернет: cgi, Cookie, urllib, urlparse, httplib, smtplib, poplib, telnetlib, socket, asyncore. Примеры серверов: SocketServer, BaseHTTPServer, xmlrpclib, asynchat.

Поддержка Internet. Форматы данных: quopri, uu, base64, binhex, binascii, rfc822, mimetools, MimeWriter, multifile, mailbox. Пакет email.

Для Python: parser, symbol, token, keyword, inspect, tokenize, pyclbr, py_compile, compileall, dis, compiler.

Графический интерфейс: Tkinter.

  В данном разделе будет показано, как импортировать и получать справку по модулям.

#Импортировать модуль(в нашем примере модуль sys)

>>> import sys

#Посмотрим пути, где питон смотрит наличие модулей

#Тут мы уже обращаемся к функционалу модуля

>>> sys.path

['', 'C:\Python33\Lib\idlelib', 'c:\Python27\egg\Lib\site-packages', 'c:\Python27\Lib\site-packages', 'C:\Windows\system32\python33.zip', 'C:\Python33\DLLs', 'C:\Python33\lib', 'C:\Python33', 'C:\Python33\lib\site-packages']

 

#Посмотрим, что есть в модуле sys

>>> dir(sys)

['__displayhook__', '__doc__', '__excepthook__', '__loader__', '__name__', '__package__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_getframe', '_home', '_mercurial', '_xoptions', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'getcheckinterval', 'getdefaultencoding', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'getwindowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'last_traceback', 'last_type', 'last_value', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'setcheckinterval', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'version', 'version_info', 'warnoptions', 'winver']

#Пример импортирования фукционала из модуля

>>> from sys import *

#После импортирования можно обращаться напрямую, а не через точку

>>> version

'3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:03:43) [MSC v.1600 32 bit (Intel)]'

#Посмотреть справку по модулю или отдельному функционалу:

>>> help(os)

>>> help(os.system)

2.1 Работа с файлами

#Копировать файл

>>> import shutil

>>> shutil.copyfile('C:/test/test.txt', 'C:/test/newtest.txt')

'C:/test/newtest.txt'

#Откроем файл на запись.

>>> f = open('C:/test/test.txt', 'w')

 

#Запишем в него несколько строк с переносом на другую строку "\r\n".

>>> f.write('string1 \r\n')

10

 

>>> f.write('string2')

7

 

#Закроем файл

>>> f.close()

 

#Пример с чтением файла по количеству байт, и "прочитать все"

>>> f = open('C:/test/test.txt', 'r')

>>> f.read(7)

'string1'

>>> f.read()

' \n\nstring2'

>>> f.close()

 

#Пример с редактированием файла по позиции байт

>>> f = open('C:/test/test.txt', 'w')

>>> f.write('abcdef')

6

>>> f.seek(3)

3

>>> f.write('CD')

2

>>> f.close()

>>> f = open('C:/test/test.txt', 'r')

>>> f.read()

'abcCDf'

 

#Еще пример чтения из файла

 

>>> f = open('C:/test/test.txt', 'w')

>>> f.write('string \r\n')

9

>>> f.write('string \r\n')

9

>>> f.write('string \r\n')

9

>>> f.close()

>>> f = open('C:/test/test.txt', 'r')

>>> f.readline()

'string \n'

>>> f.readlines()

['\n', 'string \n', '\n', 'string \n', '\n']

>>> f.close()

 

#Замена определенной строки на значение

>>> f = open('C:/test/test.txt', 'r')

>>> strings = f.readlines()

>>> f.close()

>>> strings[0] = 'STRING'

>>> f = open('C:/test/test.txt', 'w')

>>> f.writelines(strings)

>>> f.close()

2.2 Работа с ftp

#Импортируем библиотеки

>>> import os

>>> from ftplib import FTP

 

#Данные для подключения

>>> ftpresource = '192.168.10.102'

>>> ftplogin = 'anonymous'

>>> ftppassword = 'yourpass'

>>> todir = 'C:/2'

 

#Параметры подключения

>>> ftp = FTP(ftpresource)

>>> ftp.login(ftplogin, ftppassword)

'230 Anonymous user logged in.'

>>> ftp.cwd('/')

'250 CWD command successful.'

 

#Скачиваем все файлы с расширением .cfg

>>> for files in ftp.nlst('*.cfg'):

    ftp.retrbinary('RETR '+files, open(os.path.join(todir, files), 'wb').write, 1024)

 

'226 Transfer complete.'

'226 Transfer complete.'

'226 Transfer complete.'

 

#Закрываем соединение

>>> ftp.close()

 

2.3 Регулярные выражения

Регулярные выражения модуль - re

 Символы для шаблонов:

"."            Любой символ

"^"            Начало строки

"$"            Конец строки

"*"            Повторение фрагмента нуль или более раз

"+"            Повторение фрагмента один или более раз

"?"            Предыдущий фрагмент либо присутствует, либо отсутствует

"{m,n}"        Повторение предыдущего фрагмента от m до n раз включительно

"[...]"        Любой символ из набора в скобках.

"[^...]"    Любой символ не из набора в скобках

""            Обратная косая черта отменяет специальное значение следующего за ней символа

"|"            Фрагмент справа или фрагмент слева

"*?"        Повторение фрагмента нуль или более раз

"+?"        Повторение фрагмента один или более раз

"{m,n}?"    Повторение предыдущего фрагмента от m до n раз включительно

 

#Импортируем модуль

>>> import re

 

#Поиск всех совпадений в строке

>>> re.findall(r"[0-9]+", "123 abc 456AAA 789 def")

['123', '456', '789']

 

 #Разбивает строку на подстроки, разделенные подстроками, заданными шаблоном

 >>> re.split(r"[-_|/]", "123-abc_456AAA/789|def")

['123', 'abc', '456AAA', '789', 'def']

2.4 Прехват ошибки(try-except)

#Контроль ошибок

>>> try:

    zxc /cxz

except:

    print "Error"

 

Error

2.5 Встроенные функции

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

Встроенные функции

Тут можно посмотреть описание: http://ru.wikiversity.org/wiki/Программирование_и_научные_вычисления_на_языке_Python/§4/Приложение

 

Встроенные функции по тематике:

Функции преобразования типов и классы: coerce, str, repr, int, list, tuple, long, float, complex, dict, super, file, bool, object

Числовые и строковые функции: abs, divmod, ord, pow, len, chr, unichr, hex, oct, cmp, round, unicode

Функции обработки данных: apply, map, filter, reduce, zip, range, xrange, max, min, iter, enumerate, sum

Функции определения свойств: hash, id, callable, issubclass, isinstance, type

Функции для доступа к внутренним структурам: locals, globals, vars, intern, dir

Функции компиляции и исполнения: eval, execfile, reload, __import__, compile

Функции ввода-вывода: input, raw_input, open

Функции для работы с атрибутами: getattr, setattr, delattr, hasattr

Функции-"украшатели" методов классов: staticmethod, classmethod, property

Прочие функции: buffer, slice

 

 

 

2.6 Основы ООП

ООП

Все данные представляются объектами.

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

Каждый объект имеет собственную часть памяти и может состоять из других объектов.

Каждый объект имеет тип.

Все объекты одного типа могут принимать одни и те же сообщения (и выполнять одни и те же действия).

 

#Минимально возможное определение класса

>>> class A:

    pass

 

В Python члены класса называются атрибутами, функции класса — методами, поля класса — свойствами.   

   

Определения методов аналогичны определениям функций, методы всегда имеют первый аргумент, называемый по широко принятому соглашению self:

>>> class A:

    def m1(self, x):

        print (x)   

 

Создание экземпляра класса, изменение атрибутов и вызов метода

>>> class A:

    attr1 = 0

    attr2 = 0

    def m(self, x):

        print (self.attr1 * self.attr2 * x)

       

>>> A = A()

>>> A.attr1 = 2

>>> A.attr2 = 3

>>> A.m(10)

60

 

Конструктор класса - специальный метод, который не требует вызова, запускается при вызове класса автоматически,  носит имя __init__

>>> class B:

    def __init__(self,a,b):

        self.fname = a

        self.lname = b

        self.job = "Director: "+self.fname+" "+self.lname

    def m(self,d):

        self.department = self.job+" work in " + d + " dept"

        print (self.department)

 

>>> B = B("Mike", "Jagger")

>>> B.m("IT")

Director: Mike Jagger work in IT dept

2.7 Сокеты(пример простого сетевого приложения)

Для начала немного теории о сетевой модели

Уровни модели OSI:

 

Физический

Поток битов, передаваемых по физической линии. Определяет параметры физической линии.

 

Канальный (Ethernet, PPP, ATM и т.п.)

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

 

Сетевой (IP)

Маршрутизирует информационные пакеты от узла к узлу.

 

Транспортный (TCP, UDP и т.п.)

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

 

Сеансовый

Управляет сеансом соединения между участниками сети. Начинает, координирует и завершает соединения.

 

Представления

Обеспечивает независимость данных от формы их представления путем преобразования форматов. На этом уровне может выполняться прозрачное (с точки зрения вышележащего уровня) шифрование и дешифрование данных.

 

Приложений (HTTP, FTP, SMTP, NNTP, POP3, IMAP и т.д.)

Поддерживает конкретные сетевые приложения. Протокол зависит от типа сервиса.

Итак, пример простой передачи и возврата строки по сети.(приложение типа обмен данными между клиентом и сервером)

#Модуль socket

import socket

 

#Создание сокета

sock = socket.socket()

 

#Свяжем сокет с хостом и портом с помощью метода bind

sock.bind(('', 9999))

 

#С помощью метода listen запустим для сокета режим прослушивания.

sock.listen(1)

 

#Принимаем подключение с помощью метода accept, который возвращает кортеж с двумя элементами: новый сокет и адрес клиента.

conn, addr = sock.accept()

 

#Для получения данных воспользуемся методом recv, в качестве аргумента принимает количество байт. Будем читать 1024 байт.

#Получаем данные от клиента, и возвращаем приветствие

data = conn.recv(1024)

conn.send("Server:Hello, client!")

   

#Закрываем соединение

conn.close()

 

Файл server.py:

 

import socket

 

sock = socket.socket()

sock.bind(('', 9999))

sock.listen(1)

conn, addr = sock.accept()

 

print ('Client address:', addr)

 

data = conn.recv(1024)

print (data)

s = "Server:Hello, client!"

conn.send(bytes(s, 'UTF-8'))

 

conn.close()

Файл client.py

 

import socket

 

sock = socket.socket()

sock.connect(('localhost', 9999))

s = 'Client:Hello, server!'

sock.send(bytes(s, 'UTF-8'))

 

data = sock.recv(1024)

sock.close()

 

print (data)

Запустить можно например так:

Вызываем два окошка «cmd»

Пишем путь до питона и через пробел путь до скрипта

Сначала запускаем server.py

Затем client.py

2.8 Основы работы с базами данных(sqlite)

#sqlite3  простейший пример работы с базой данных из файла

>>> import sqlite3

 

#Соединение с базой методом connect

>>> conn = sqlite3.connect('C:\test\base.db')

#Соединение в результате успешного вызова функции connect(), имеет следующие методы:

#close() Закрывает соединение с базой данных.

#commit() Завершает транзакцию.

#rollback() Откатывает начатую транзакцию.

#cursor() Возвращает объект-курсор, использующий данное соединение.

 

>>> c = conn.cursor()

 

#execute - исполняет запрос к базе данных. Примеры:

 

#Создание таблицы

c.execute('''create table stocks (date text, trans text, symbol text, qty real, price real)''')

 

#Вставка значений

c.execute("""insert into stocks values ('2006-01-05','BUY','RHAT',100,35.14)""")

 

#Подтверждаем изменения

conn.commit()

 

#Сделаем выборку

>>> conn = sqlite3.connect('C:\test\base.db')

>>> c = conn.cursor()

>>> c.execute('select * from stocks order by price')

<sqlite3.Cursor object at 0x028517E0>

>>> for row in c:

    print(row)

 

(u'2006-01-05', u'BUY', u'RHAT', 100.0, 35.14)

 

#Закрываем соединение

c.close()

 

 

 

 

 

2.     Графические приложения

2.0 PyQt: Знакомство

Использована версия 4.

Официальный сайт: http://www.riverbankcomputing.com/software/pyqt/download5

PyQt4 является инструментом создания GUI приложений, представляет симбиоз языка Python и библиотеки Qt.

Модули в PyQt4:

QtCore предназначен для работы со файлами, каталогами, временем, URL, типами данных, потоками, процессами.

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

QtNetwork хранит классы сетевого программирования. Позволяет создать TCP/IP, UDP клиентские и серверные приложения.

QtSql хранит классы для работы с базами данных.

QtXml хранит классы для работы с xml.

QtSvg хранит компоненты для работы с масштабируемой векторной графикой (SVG),(двумерная графикаи графическими приложениями XML).

QtOpenGL предназначен для бесшовной интеграции QtGui и библиотеки OpenGL.

 

Первая «классическая программа» Hello World!

#Подключаем библиотеки, необходимые для создания программы

import sys

from PyQt4 import QtCore, QtGui

 

#Обязательное создание экземпляра основного приложения и передача параметров командной строки

app = QtGui.QApplication(sys.argv)

 

#Создаем объект окна, который наследует nрактически все классы, реализующие комnоненты графического интерфейса.

widget = QtGui.QWidget()

 

#Изменяем размеры окна с помощью метода resize()

widget.resize(300, 150)

 

#Зададим заголовок программы

widget.setWindowTitle('MyProgramm')

 

#Создадим надпись(можно использовать теги HTML)

label = QtGui.QLabel("<center>Hello!</center>")

 

#Создадим кнопку и присвоем ей надпись

btn = QtGui.QPushButton("CloseWindow")

 

#Создадим контейнер, в который помести надпись и кнопку

box = QtGui.QVBoxLayout()

box.addWidget(label)

box.addWidget(btn)

 

#Добавим контейнер в основное окно

widget.setLayout(box)

 

#Обработчик сигнала, генерируемый nри нажатии кноnки.

#Аргументы:

#btn - объект, генерируещий сигнал

#QtCore.SIGNAL("clicked()") - название сигнала

#QtGui.qApp - объект, nринимающий сигнал

#QtCore.SLOT("quit()") - метод объекта, который будет вызван nри вызове события

QtCore.QObject.connect(btn, QtCore.SIGNAL("clicked()"), QtGui.qApp, QtCore.SLOT("quit()"))

 

#Отобразим окно прогаммы с помощью метода show()

widget.show()

 

#Основной цикл обработки событий программы, получает и обрабатывает события окна системы, передает их виджетам.

#По окончании работы основного цикла, программа закончит работу. sys.exit() передает информацию ОС об оканчании работы приложения.

sys.exit(app.exec_())

 

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

 

 

2.1  PyQt : Знакомство в ООП стиле

Напишем вариант первой программы с помощью ООП стиля:

import sys

from PyQt4 import QtCore, QtGui

 

#ООП-стиль создания окна

#Создаем класс Prog

#Объявляем класс Prog производным от класса QtGui.QWidget

#Вызываем конструктор класса-родителя, передаем указатель на класс Prog, и указатель на родительский класс

class Prog(QtGui.QWidget):

    def __init__(self, parent=None):

        QtGui.QWidget.__init__(self, parent)

       

        #Зададим расположение окна и размеры

        self.setGeometry(650, 450, 150, 150)

       

        #Эти конструкции мы разбирали на прошлом уроке

        self.label = QtGui.QLabel("<center>Hello!</center>")

        self.btn = QtGui.QPushButton("CloseWindow")

        self.box = QtGui.QVBoxLayout()

        self.box.addWidget(self.label)

        self.box.addWidget(self.btn)

        self.setLayout(self.box)

        self.connect(self.btn, QtCore.SIGNAL("clicked()"), QtGui.qApp.quit)

 

 

app = QtGui.QApplication(sys.argv)

 

#Создаем экземпляр класса

prog = Prog()

 

#Устанавливаем свойства в т.ч. добавим иконку в окошко

prog.setWindowTitle("MyProgramm")

prog.setWindowIcon(QtGui.QIcon('lesson2.png'))

prog.show()

sys.exit(app.exec_())

2.2 PyQt : Отцентровка, messagebox, контекстная подсказка

import sys

from PyQt4 import QtCore, QtGui

 

class Prog(QtGui.QWidget):

    def __init__(self, parent=None):

        QtGui.QWidget.__init__(self, parent)

 

        #Задаем размеры окна и вызываем функцию отцентровки по дисплею

        self.setWindowTitle('center')

        self.resize(350, 250)

        self.center()

   

        #Эти конструкции мы разбирали на прошлом уроке

        self.label = QtGui.QLabel("<center>Hello!</center>")

        self.btn = QtGui.QPushButton("Edit setToolTip")

        self.box = QtGui.QVBoxLayout()

        self.box.addWidget(self.label)

        self.box.addWidget(self.btn)

        self.setLayout(self.box)

       

        #По клику вызовем связь с функцией(изменим подсказку)

        self.connect(self.btn, QtCore.SIGNAL("clicked()"), Prog.func)

       

        #Устанавливаем шрифт и размер подсказки

        QtGui.QToolTip.setFont(QtGui.QFont('verdana', 14))

   

    #При закрытии программы выведем окно с сообщением

    def closeEvent(self, event):

        reply = QtGui.QMessageBox.question(self, 'Message', "Are you sure to quit?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)

 

        if reply == QtGui.QMessageBox.Yes:

            event.accept()

        else:

            event.ignore()

   

    #Функция изменяющая подсказку

    def func():

        prog.label.setToolTip('Push button new!')

 

    #Функция, распологающая окно по центру дисплея, вычисляя его длинуширину

    def center(self):

        screen = QtGui.QDesktopWidget().screenGeometry()

        size =  self.geometry()

        self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)

 

app = QtGui.QApplication(sys.argv)

 

#Создаем экземпляр класса

prog = Prog()

 

#Устанавливаем контекстную подсказку

prog.label.setToolTip('Push button!')

prog.show()

sys.exit(app.exec_())

2.3 Визуальные эффекты, включение виджетов, выход из программы

Рассмотрим:

1. Включение\Выключение виджета

2. Имитацию процесса со строкой прогресса(не забудьте создать произвольный(например 150 на 50 пикселей серый фон) png файл для фона со строкой прогресса)

3. Скрыть\показать окно программы

4. Прозрачность

5. Смену цветов

6. Закрытие программы

 

from PyQt4 import QtCore, QtGui

from PyQt4.QtCore import Qt, SIGNAL

import sys, time

 

class Prog(QtGui.QWidget):

    def __init__(self, parent=None):

        QtGui.QWidget.__init__(self, parent)

 

        self.resize(350, 250)

        self.label = QtGui.QLabel("<center>Hello!</center>")

        self.btn = QtGui.QPushButton("On\Off label")

        self.btnProgress = QtGui.QPushButton("Progress")

        self.btnVis = QtGui.QPushButton("Visible")

        self.btnOpac = QtGui.QPushButton("Opacity")

        self.btnColor = QtGui.QPushButton("Color")

        self.btnClose = QtGui.QPushButton("Close")

        self.box = QtGui.QVBoxLayout()

        self.box.addWidget(self.label)

        self.box.addWidget(self.btn)

        self.box.addWidget(self.btnProgress)

        self.box.addWidget(self.btnVis)

        self.box.addWidget(self.btnOpac)

        self.box.addWidget(self.btnColor)

        self.box.addWidget(self.btnClose)

        self.setLayout(self.box)

       

        self.connect(self.btn, QtCore.SIGNAL("clicked()"), self.des)

        self.connect(self.btnProgress, QtCore.SIGNAL("clicked()"), self.desProg)

        self.connect(self.btnVis, QtCore.SIGNAL("clicked()"), self.desVis)

        self.connect(self.btnOpac, QtCore.SIGNAL("clicked()"), self.opac)

        self.connect(self.btnColor, QtCore.SIGNAL("clicked()"), self.color)

        self.connect(self.btnClose, QtCore.SIGNAL("clicked()"), self, QtCore.SLOT("close()"))

   

    #closeEvent()

    ev = 0

    def closeEvent(self, event):

        if self.ev == 3:

            event.accept()

        elif self.ev < 3:

            event.ignore()

            self.ev += 1

   

    #Color

    def color(self):

        pal = self.palette()

        pal.setColor(QtGui.QPalette.Normal, QtGui.QPalette.Window, QtGui.QColor("DarkGreen"))

        self.setPalette(pal)

        self.label.setStyleSheet("background-color: #ffffff;")

   

    #Opacity widget

    ix = 0.0

    def opac(self):

        while self.ix <= 1.0:

            time.sleep(1)

            self.setWindowOpacity(self.ix)

            self.ix += 0.25

   

    #visible widget

    def desVis(self):

        if self.label.isVisible() == True:

            self.label.setVisible(False)

        elif self.label.isVisible() == False:

            self.label.setVisible(True)

   

    #ON\OFF widget

    a = 1

    def des(self):

        if self.a == 1:

            self.label.setDisabled(True)

            self.a = 2

        elif self.a == 2:

            self.label.setDisabled(False)

            self.a = 1

   

    #inscription over the raster image (simulation progress)

    def desProg(self):

        splash = QtGui.QSplashScreen(QtGui.QPixmap("img.png"))

        splash. showMessage ("Load data... 0%",  Qt.AlignHCenter | Qt.AlignBottom, Qt.black)

        splash.show()

        for i in range(1, 6):

            time.sleep(1)

            splash.showMessage("Load data...{0}%".format(i*20), Qt.AlignHCenter | Qt.AlignBottom, Qt.black)

            QtGui.qApp.processEvents()

            splash.show()

        splash.finish(splash)

   

app = QtGui.QApplication(sys.argv)

prog = Prog()

prog.show()

sys.exit(app.exec_())

2.4 PyQt : Позиционирование, буфер обмена

1 В первой части раскоментируйте блок # #Absolute position для рассмотрения абсолютного(жесткого) позиционирования.

В данном случае элементы будут располагаться жестко по координатам.

2 Во второй части раскоментируйте блок # #clipboard для рассмотрения работы с буфером обмена(изначально скопируйти в буфер любую строку или слово).

3 В третьей части посмотрите «резиновое позиционирование»(не жесткое) элементов.

В данном случае можно менять размер окна, и Вы увидите «прижимание» элементов или их расползание относительно рамок программы.

from PyQt4 import QtCore, QtGui

from PyQt4.QtCore import Qt, SIGNAL

import sys, time

 

class Prog(QtGui.QWidget):

    def __init__(self, parent=None):

        QtGui.QWidget.__init__(self, parent)

       

        # #----------------------

        # #Absolute position

        # self.resize(350, 250)

        # self.label = QtGui.QLabel("<center>Hello!</center>", self)

        # self.btn = QtGui.QPushButton("clipboard", self)

        # self.label.setGeometry(30, 30, 300, 50) #width, height, x, y

        # self.btn.resize(70, 30) #width, height

        # self.btn.move(20, 150) #x, y

       

        # #----------------------

        # #clipboard

        # self.connect(self.btn, QtCore.SIGNAL("clicked()"), self.des)

       

        #----------------------

        #rubber position

        self.label1 = QtGui.QLabel("<center>l1</center>")

        self.label2 = QtGui.QLabel("<center>l2</center>")

        self.label3 = QtGui.QLabel("<center>l3</center>")

        self.btn1 = QtGui.QPushButton("b1")

        self.btn2= QtGui.QPushButton("b2")

        self.btn3= QtGui.QPushButton("b3")

       

        #Vertical

        #self.box = QtGui.QVBoxLayout()

        #Horisontal

        self.box = QtGui.QHBoxLayout()

        self.innerBox1 = QtGui.QHBoxLayout()

        self.innerBox2 = QtGui.QHBoxLayout()

       

        #alignment=QtCore.Qt. - align:

        #AlignLeft, AlignRight, AlignHcenter, AlignJustify, AlignTop, AlignBottom, AlignVcenter, AlignCenter

        self.box.addWidget(self.label1, alignment=QtCore.Qt.AlignTop)

        self.box.addWidget(self.label2, alignment=QtCore.Qt.AlignBottom)

        self.box.addWidget(self.btn1)

        self.box.addWidget(self.btn2)

       

        self.setLayout(self.box)

       

        #add widget on last position

        self.box.addWidget(self.label3)

       

        #add widget on defined position

        self.box.insertWidget(0, self.btn3)

        

        #Add container in container

        self.innerLabel1 = QtGui.QLabel("<center>innerLabel1</center>")

        self.innerLabel2 = QtGui.QLabel("<center>innerLabel2</center>")

        self.innerBox1.addWidget(self.innerLabel1)

        self.innerBox2.addWidget(self.innerLabel2)

       

        self.box.addLayout(self.innerBox1)

        self.box.insertLayout(0, self.innerBox2)

       

        #Add empty space (static)

        self.box.addSpacing(100)

        self.box.insertSpacing(0, 100)

       

   

    def des(self):

        clipboard = QtGui.QApplication.clipboard()

        self.label.setText(clipboard.text())

   

app = QtGui.QApplication(sys.argv)

prog = Prog()

prog.show()

sys.exit(app.exec_())

2.5 PyQt: меню, панель задач, строка состояния

Для иконки в меню создайте маленький файл 'exit.png'

import sys, time

from PyQt4.QtGui import *

from PyQt4 import QtGui, QtCore

 

class Prog(QtGui.QMainWindow):

    def __init__(self, parent=None):

        QtGui.QWidget.__init__(self, parent)

       

        self.resize(350, 250)

        self.setWindowTitle('MyProg')

        self.label = QtGui.QLabel("label", self)

        self.label.setGeometry(70, 70, 23, 23)

       

        #menu

        #menu icon and text

        exit = QtGui.QAction(QtGui.QIcon('exit.png'), 'Exit', self)

        #hot keys

        exit.setShortcut('Ctrl+Q')

        #signal onclick

        self.connect(exit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))

       

        AnyNews1 = QtGui.QAction('AnyNews1', self)

        AnyNews2 = QtGui.QAction('AnyNews2', self)

     

        self.connect(AnyNews1, QtCore.SIGNAL('triggered()'), self.des1)

        self.connect(AnyNews2, QtCore.SIGNAL('triggered()'), self.des2)

       

        #create menu and actions

        menubar = self.menuBar()

        file = menubar.addMenu('&File')

        news = menubar.addMenu('&News')

        file.addAction(exit)

        news.addAction(AnyNews1)

        news.addAction(AnyNews2)

       

        #toolbars

        self.toolbar = self.addToolBar('Exit')

        self.toolbar.addAction(exit)

        self.toolbar.addAction(AnyNews1)

        self.toolbar.addAction(AnyNews2)

       

   

    def des1(self):

        self.label.setStyleSheet("background-color: #ffffff;")

   

    def des2(self):

        self.label.setStyleSheet("background-color: DarkGreen;")

   

    #statusbar  

    i = 1   

    def enterEvent(self, event):

        self.statusBar().setVisible(True)

        self.statusBar().showMessage('Statusbar count: {0}'.format(self.i))

        self.i += 1

       

    

    def leaveEvent(self, event):

         self.statusBar().setVisible(False)

 

app = QtGui.QApplication(sys.argv)

prog = Prog()

prog.show()

sys.exit(app.exec_())

2.6 PyQt : простой текстовой редактор, диалоговые окна

import sys, time

from PyQt4.QtGui import *

from PyQt4 import QtGui, QtCore

 

class Prog(QtGui.QWidget):

    def __init__(self, parent=None):

        QtGui.QWidget.__init__(self, parent)

       

        self.setWindowTitle('grid layout')

 

        #Craete line and text area

        self.Line = QtGui.QLabel('Line')

        self.Text = QtGui.QLabel('Text')

 

        self.LineEdit = QtGui.QLineEdit()

        self.TextEdit = QtGui.QTextEdit()

       

        #checkered layout, 5 - cell spacing

        grid = QtGui.QGridLayout()

        grid.setSpacing(5)

 

        grid.addWidget(self.Line, 1, 0) #1 and 0 - coordinates

        grid.addWidget(self.LineEdit, 1, 1)

 

        grid.addWidget(self.Text, 3, 0)

        grid.addWidget(self.TextEdit, 3, 1, 5, 1) # 5,1 - number of columns and cells

 

        self.setLayout(grid)

       

        #dialog window

        self.button = QtGui.QPushButton('editLine', self)

        grid.addWidget(self.button, 12, 1)

        self.connect(self.button, QtCore.SIGNAL('clicked()'), self.editLine)

       

        self.resize(350, 300)

   

 

    def editLine(self):

        text, ok = QtGui.QInputDialog.getText(self, 'Input in line', 'Enter string:')

 

        if ok:

            self.LineEdit.setText(text)

   

app = QtGui.QApplication(sys.argv)

prog = Prog()

prog.show()

sys.exit(app.exec_())

3  Основы Django

 

3.0  Установка django на примере windows 7

 

Примеры были написаны на Python 3.3 и Setup Tools (второе можно взять отсюда: https://pypi.python.org/pypi/setuptools установка после разархивации C:\Python33\python.exe C:\setup_tools\setup.py install)

 

Приступим, первым делом - установка!

 

Идем на сайт: https://www.djangoproject.com/download/

 

В данном примере я просто скачал архивную версию, распаковал ее в папку C:\test\

 

Далее запускаем командную строку, или проще говоря «cmd».

 

У меня на компьютере был установлен Python 3, в cmd (запускаем с правами администратора) действия следующие:

 

1. cd C:\test\

 

2. C:\Python33\python.exe C:\test\setup.py install

 

После этого проверим (уже в Python):

 

>>> import django

>>> print(django.get_version())

1.7.1

3.1 Hello, world! Передача аргументов. Шаблоны.

После установки django,  создаем проект:

 

cd C:\django_code\

 

Создаем проект командой «startproject»

C:\Python33\python.exe C:\Python33\Lib\site-packages\Django-1.7.1-py3.3.egg\django\bin\django-admin.py startproject first

 

Далее для теста нам хватит минимального предустановленного функционала с базой данных sqlite, для работы создадим все нужные файлы (настройки, для которых создаются файлы базы данных и учетные данные хранятся в созданном файле проекта "settings.py"):

C:\Python33\python.exe C:\django_code\first\manage.py migrate

 

Запускаем сервер(По умолчанию работает на адресе http://127.0.0.1:8000/)

C:\Python33\python.exe C:\django_code\first\manage.py runserver

 

Что мы создадим в этой главе:

 

1. Первую классическую программу "Hello World!"

 

2. Научимся передавать аргументы в URL запроса

 

3. Выведем страницу с помощью шаблона

 

Итак, давайте создадим обработчики запросов для нашего сервера:

 

C:\django_code\first\first\urls.py

from django.conf.urls import patterns, include, url

from . import views

 

urlpatterns = patterns('',

    #^ - "начинается с", $ - "окончание строки"

    url(r'^hello/$', views.hello),

    #\d - числовой символ, представление(функция) принимает аргумент из "()"

    url(r'^dtime/(\d)/$', views.dtime),

    #\w+ - Буквенный или цифровой символ или знак подчёркивания ноль или более раз

    url(r'^templ/(\w+)/$', views.templ),

)

 

Надо сказать следущее, первый url обрабатывает запрос к "Hello World!" - http://127.0.0.1:8000/hello/ ,

 

второй к http://127.0.0.1:8000/dtime/1/ , тут "1" - передаваемый аргумент,

 

третий к http://127.0.0.1:8000/templ/3/ , тут передаваемый аргумент - "3"

 

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

 

строка "from . import views" - импортирует файл представлений:

 

C:\django_code\first\first\views.py

#Представление(view) — это функция, которая получает аргумент HttpReqeust и возвращает объект HttpResponse

from django.http import HttpResponse

 

###Первая программа

def hello( request ) :

    return HttpResponse( u'Hello World!' )

 

###Принимаем аргумент и вывод 404 ошибки

from django.http import Http404

from datetime import *

 

#offset - принимаемый аргумент из "()"

def dtime( request, offset ) :

    try :

        offset = int(offset)

        dt = datetime.now() + timedelta( hours = offset )

        result = HttpResponse( u"<html><body>%s</body></html>" % dt )

        return result

    except ValueError :

        raise Http404

 

###Шаблон и контекст

from django.shortcuts import render

 

def templ( request, arg ) :

    localarg = '' # вызовет блок else в шаблоне

    localarg = 'in templ'

    #render() - выполняет указанный шаблон с переданным словарем контекста, возвращает HttpResponse с полученным содержимым.

    context = {'context_arg': arg, 'templ_arg': localarg, 'incontext': [ '1 arg', '2 arg' ] }

   

    return render( request, 'templ.html', context )

 

В нем мы описали логику обработки аргументов, другие переменные и передачу итоговых данных для шаблонов.

 

Но для работы шаблона нам нужно в файле настроек C:\django_code\first\first\settings.py внести блок:

#Укажем папку для шаблонов

TEMPLATE_DIRS = (

    'C:\\django_code\\first\\templates\\' ,

)

 

После чего функция "render" найдет шаблон по этому пути  'templ.html',

 

Сам шаблон выводит две переменные, и переменны из списка с помощью перебора:

<html><body>

<!-- Если пришел словарь с таким именем -->

{% if context_arg and templ_arg %}

        <!-- Обратимся к именам переменных -->

        context_arg is: {{ context_arg }}

        <br />

        templ_arg  is: {{ templ_arg }}

        <hr />

        <!-- Переберем элементы списка {{ forloop.counter }} - счетчик(псевдопеременная) -->

        {% for inarg in incontext %}

           incontext_arg {{ forloop.counter }} is: {{ inarg }}<br />

        {% endfor %}

{% else %}

    <!-- Если нет - ошибка -->

    Error!

{% endif %}

</body></html>

В переборе участвует псевдопеременная forloop.counter, переданные переменные для django обрабляются в двойные кавычки.

 

Заметьте, если Вы закоментируете  localarg = 'in templ', то отработает блок "else" нашего шаблона.

 

3.1  Простое приложение, простая модель

 

Приложение создается с помощью команды "startapp ", которой передается имя будущего приложения:

 

c:\django_code\first>C:\Python33\python.exe C:\django_code\first\manage.py startapp firstapp

 

Далее в настройках "C:\django_code\first\first\settings.py" добавим наше приложение:

 

INSTALLED_APPS = (

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

    'firstapp',

)

 

Создадим обработчик запроса для приложения в главном urls нашего проекта:

 

C:\django_code\first\first\urls.py

from django.conf.urls import patterns, include, url

 

urlpatterns = patterns('',

    #Добавим приложение "firstapp"

    #Приложение будет срабатывать по запросу: http://127.0.0.1:8000/firstapp/generic/

    #Первая часть запроса обрабатывается в C:\django_code\first\first\urls.py проекта

    #Вторая часть запроса обрабатывается в C:\django_code\first\firstapp\urls.py приложения

    url(r'^firstapp/', include( 'firstapp.urls' ) ),

)

Создадим обработчик в urls нашего приложения:

 

C:\django_code\first\firstapp\urls.py

from django.conf.urls import patterns, url

from . import views

 

urlpatterns = patterns('',

    ( r'generic/$', views.generic ),

)

 

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

C:\django_code\first\firstapp\views.py

from django.http import HttpResponse

 

def generic( request ) :

    return HttpResponse( u'Works!' )

 

А теперь создадим простую модель.

 

Модель по сути является схемой базы данных:

 

C:\django_code\first\firstapp\models.py

from django.db import models

 

#Модель — это класс, являющийся подклассом django.db.models.Model

#Атрибуты модели - отдельные поля базы данных

class dept ( models.Model ):

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

    #Список типов полей в Django: https://docs.djangoproject.com/en/dev/ref/models/fields/

    name       = models.CharField(max_length=15)

 

class workers ( models.Model ):

    dept       = models.ForeignKey(dept)

    name       = models.TextField()

    birthday   = models.DateTimeField()

 

После создания модели приведем в порядок базу данных командой "syncdb":

 

C:\django_code\first>C:\Python33\python.exe C:\django_code\first\manage.py syncdb

 

Запускаем сервер и проверяем:

 

C:\django_code\first>C:\Python33\python.exe C:\django_code\first\manage.py runserver

 

http://127.0.0.1:8000/firstapp/generic/

 

 

3.2  Изменения в базе данных

В этой статье мы научимся вносить изменения в базу данных на примере добавления поля "boss"

Изменяем модель(например добавим поле "boss"):

C:\django_code\first\firstapp\models.py

from django.db import models

 

class dept ( models.Model ):

    name       = models.CharField(max_length=15)

 

class workers ( models.Model ):

    dept       = models.ForeignKey(dept)

    name       = models.TextField()

    birthday   = models.DateTimeField()

    boss       = models.CharField(max_length=12)

 

Команда makemigrations - cоздает новые миграции на основе изменений, обнаруженных в вашей модели.

C:\django_code\first>C:\Python33\python.exe C:\django_code\first\manage.py makemigrations

 

Команда syncdb анализирует значение INSTALLED_APPS и создает все необходимые таблицы в базе данных используя настройки базы данных из файла settings.py.

C:\django_code\first>C:\Python33\python.exe C:\django_code\first\manage.py syncdb

 

Возникла проблема с dbshell: "sqlite3" не является внутренней или внешней командой, исполняемой программой или пакетным файлом

качаем sqlite-shell-win32-x86-3080701.zip с http://sqlite.org/download.html   

распаковываем "экзешник" из архива например в "C\Python33\",

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

 

Теперь запускаем dbshell

c:\django_code>C:\Python33\python.exe C:\django_code\first\manage.py dbshell

 

Помощь по командам

sqlite> .help

.backup ?DB? FILE      Backup DB (default "main") to FILE

.bail on|off           Stop after hitting an error.  Default OFF

.clone NEWDB           Clone data into NEWDB from the existing database

.databases             List names and files of attached databases

.dump ?TABLE? ...      Dump the database in an SQL text format

                         If TABLE specified, only dump tables matching

                         LIKE pattern TABLE.

.echo on|off           Turn command echo on or off

.eqp on|off            Enable or disable automatic EXPLAIN QUERY PLAN

.exit                  Exit this program

.explain ?on|off?      Turn output mode suitable for EXPLAIN on or off.

                         With no args, it turns EXPLAIN on.

.fullschema            Show schema and the content of sqlite_stat tables

.headers on|off        Turn display of headers on or off

.help                  Show this message

.import FILE TABLE     Import data from FILE into TABLE

.indices ?TABLE?       Show names of all indices

                         If TABLE specified, only show indices for tables

                         matching LIKE pattern TABLE.

.load FILE ?ENTRY?     Load an extension library

.log FILE|off          Turn logging on or off.  FILE can be stderr/stdout

.mode MODE ?TABLE?     Set output mode where MODE is one of:

                         csv      Comma-separated values

                         column   Left-aligned columns.  (See .width)

                         html     HTML <table> code

                         insert   SQL insert statements for TABLE

                         line     One value per line

                         list     Values delimited by .separator string

                         tabs     Tab-separated values

                         tcl      TCL list elements

.nullvalue STRING      Use STRING in place of NULL values

.once FILENAME         Output for the next SQL command only to FILENAME

.open ?FILENAME?       Close existing database and reopen FILENAME

.output ?FILENAME?     Send output to FILENAME or stdout

.print STRING...       Print literal STRING

.prompt MAIN CONTINUE  Replace the standard prompts

.quit                  Exit this program

.read FILENAME         Execute SQL in FILENAME

.restore ?DB? FILE     Restore content of DB (default "main") from FILE

.save FILE             Write in-memory database into FILE

.schema ?TABLE?        Show the CREATE statements

                         If TABLE specified, only show tables matching

                         LIKE pattern TABLE.

.separator STRING ?NL? Change separator used by output mode and .import

                         NL is the end-of-line mark for CSV

.shell CMD ARGS...     Run CMD ARGS... in a system shell

.show                  Show the current values for various settings

.stats on|off          Turn stats on or off

.system CMD ARGS...    Run CMD ARGS... in a system shell

.tables ?TABLE?        List names of tables

                         If TABLE specified, only list tables matching

                         LIKE pattern TABLE.

.timeout MS            Try opening locked tables for MS milliseconds

.timer on|off          Turn SQL timer on or off

.trace FILE|off        Output each SQL statement as it is run

.vfsname ?AUX?         Print the name of the VFS stack

.width NUM1 NUM2 ...   Set column widths for "column" mode

                         Negative values right-justify

                        

посмотрим названия таблиц

 

sqlite> .tables

auth_group                  django_admin_log

auth_group_permissions      django_content_type

auth_permission             django_migrations

auth_user                   django_session

auth_user_groups            firstapp_dept

auth_user_user_permissions  firstapp_workers

Проверим нашу таблицу

sqlite> .schema firstapp_workers

CREATE TABLE "firstapp_workers" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" text NOT NULL, "birthday" datetime NOT NU

LL, "dept_id" integer NOT NULL REFERENCES "firstapp_dept" ("id"), "boss" varchar(12) NOT NULL);

CREATE INDEX firstapp_workers_b5a9fd30 ON "firstapp_workers" ("dept_id");

 

Выйдем

sqlite> .exit

 

3.3  Админка

 

Минимальные действия для запуска админки

в C:\django_code\first\first\settings.py

в разделе INSTALLED_APPS раскометнтировать 'django.contrib.admin',

 

Когда Django загружает URLconf от urls.py при запуске сервера, он выполняет admin.autodiscover (),

эта функция перебирает установки INSTALLED_APPS и ищет файл с именем admin.py на каждом из установленных приложений.

Если admin.py существует в данном приложении, он выполняет код в этом файле.

 

C:\django_code\first\first\urls.py

from django.conf.urls import patterns, include, url

from django.contrib import admin

 

admin.autodiscover()

 

urlpatterns = patterns('',

    url(r'^firstapp/', include( 'firstapp.urls' ) ),

    url(r'^admin/', include(admin.site.urls)),

)

 

теперь зарегистрируем наши модели

C:\django_code\first\firstapp\admin.py

 

from django.contrib import admin

from firstapp.models import dept, workers

 

admin.site.register(dept)

admin.site.register(workers)

 

Теперь добавим удобства

 

C:\django_code\first\firstapp\admin.py

 

1. добавим заголовок админки

from django.contrib import admin

from firstapp.models import dept, workers

 

#Заголовок админки

admin.AdminSite.site_header = 'Заголовок админки'

 

admin.site.register(dept)

admin.site.register(workers) 

 

2.     после добавления записей, мы видим неудобнуое отображение в списке добавленных записей,

http://snakeproject.ru/rubric/files/django_my_4/1.jpg

 

Выведем их в "человеческом виде"

C:\django_code\first\firstapp\models.py

from django.db import models

 

class dept ( models.Model ):

    def __str__(self):

        return self.name

    name       = models.CharField(max_length=15)

   

class workers ( models.Model ):

    def __str__(self):

        return self.name

    dept       = models.ForeignKey(dept)

    name       = models.TextField()

    birthday   = models.DateTimeField()

    boss       = models.CharField(max_length=12)

3. изменение порядка полей и скрытие

http://snakeproject.ru/rubric/files/django_my_4/2.jpg

 

C:\django_code\first\firstapp\admin.py

from django.contrib import admin

from firstapp.models import dept, workers

 

#Заголовок админки

admin.AdminSite.site_header = 'Заголовок админки'

 

class WorkersAdmin(admin.ModelAdmin):

    #fieldsets - название группы полей.

    #В fields передаем поля из модели.

    #Во второй строке класс "collapse", отображает группу полей изначально скрытой.

    fieldsets = [

        (None,               {'fields': ['dept']}),

        ('Информация о работнике', {'fields': ['name', 'birthday', 'boss'], 'classes': ['collapse']}),

    ]

 

admin.site.register(dept)

#WorkersAdmin передается как настройка для класса workers

admin.site.register(workers, WorkersAdmin) 

 

4.     Отображение доп.полей в отображении списка работников

 

http://snakeproject.ru/rubric/files/django_my_4/3.jpg

 

C:\django_code\first\firstapp\admin.py

 

from django.contrib import admin

from firstapp.models import dept, workers

 

#Заголовок админки

admin.AdminSite.site_header = 'Заголовок админки'

 

class WorkersAdmin(admin.ModelAdmin):

    fieldsets = [

        (None,               {'fields': ['dept']}),

        ('Информация о работнике', {'fields': ['name', 'birthday', 'boss'], 'classes': ['collapse']}),

    ]

    #Отображение доп.полей в отображении списка работников

    #http://127.0.0.1:8000/admin/firstapp/workers/

    list_display = ('name', 'dept', 'birthday')

 

admin.site.register(dept)

admin.site.register(workers, WorkersAdmin) 

 

5. Добавим поле поиска(поиск по указанному полю):

http://snakeproject.ru/rubric/files/django_my_4/4.jpg

C:\django_code\first\firstapp\admin.py

 

from django.contrib import admin

from firstapp.models import dept, workers

 

#Заголовок админки

admin.AdminSite.site_header = 'Заголовок админки'

 

class WorkersAdmin(admin.ModelAdmin):

    fieldsets = [

        (None,               {'fields': ['dept']}),

        ('Информация о работнике', {'fields': ['name', 'birthday', 'boss'], 'classes': ['collapse']}),

    ]

    list_display = ('name', 'dept', 'birthday')

    #Добавим поле поиска(будет искать по указанному полю):

    search_fields = ['name']

 

admin.site.register(dept)

admin.site.register(workers, WorkersAdmin) 

 

6. Добавления связанных объектов

Добавим возможность добавлять сотрудников из формы добавления департамента

http://snakeproject.ru/rubric/files/django_my_4/5.jpg

C:\django_code\first\firstapp\admin.py

from django.contrib import admin

from firstapp.models import dept, workers

 

admin.AdminSite.site_header = 'Заголовок админки'

 

#Добавления связанных объектов (отобразим функционал добавления workers в dept)

#Варианты отображения TabularInline и StackedInline

class WorkersInline(admin.TabularInline):

#class ChoiceInline(admin.StackedInline):

    model = workers

    #Показать 3 формы для добавления работников в департамент.

    extra = 3

 

class DeptAdmin(admin.ModelAdmin):

    #функционал добавления workers в dept

    inlines = [WorkersInline]

 

class WorkersAdmin(admin.ModelAdmin):

    fieldsets = [

        (None,               {'fields': ['dept']}),

        ('Информация о работнике', {'fields': ['name', 'birthday', 'boss'], 'classes': ['collapse']}),

    ]

    list_display = ('name', 'dept', 'birthday')

    search_fields = ['name']

 

admin.site.register(dept, DeptAdmin)

admin.site.register(workers, WorkersAdmin) 

 

3.4 Сессии

 

Для начала внесем изменения в C:\django_code\first\first\settings.py нашего проекта из прошлых уроков:

 

1. Измените параметр MIDDLEWARE_CLASSES, добавив в него значение django.contrib.sessions.middleware.SessionMiddleware.

 

2. Внесите в параметр INSTALLED_APPS значение django.contrib.sessions.

 

3. После того, как вы завершили настройку, запустите manage.py migrate для создания таблицы базы данных, в которой хранятся данные сессии.

 

Приведем C:\django_code\first\firstapp\urls.py к такому виду:

from django.conf.urls import patterns, url

from . import views

 

urlpatterns = patterns('',

    ( r'ses1/$', views.ses1 ),

    ( r'ses2/$', views.ses2 ),

    ( r'delses/$', views.delses ),

    ( r'getses/$', views.getses ),

    ( r'giveses/$', views.giveses ),

)

А теперь сами представления:

from django.http import HttpResponse

 

#Оф.Документация по сессиям Django 1.7 http://djbook.ru/rel1.7/topics/http/sessions.html#module-django.contrib.sessions

 

def ses1( request ) :

    request.session[0] = 'sessionbar'

    # Получим значение ключа из сессии

    per = "Key '0' is: "+request.session[0]

    return HttpResponse( per+' <a href="http://127.0.0.1:8000/firstapp/ses2/">ses2</a>'+

    ' <a href="http://127.0.0.1:8000/firstapp/delses/">delses</a>'+

    ' <a href="http://127.0.0.1:8000/firstapp/getses/">getses</a>'+

    " <a href='http://127.0.0.1:8000/firstapp/setlogin/'>setlogin</a>")

 

def ses2( request ) :

    #per = request.session[0] Вызовет ошибку

    # Проверка наличия ключа в сессии:

    if '0' in request.session:

        per = "Key '0' is: "+request.session['0']

    else :

        per = "Key '0' is clean! "

       

    return HttpResponse( per+' <a href="http://127.0.0.1:8000/firstapp/ses1/">ses1</a>'+

    ' <a href="http://127.0.0.1:8000/firstapp/delses/">delses</a>'+

    ' <a href="http://127.0.0.1:8000/firstapp/getses/">getses</a>'+

    " <a href='http://127.0.0.1:8000/firstapp/setlogin/'>setlogin</a>")

 

def delses( request ) :

    # Чистим значение ключа в сессии:

    del request.session['0']

 

    return HttpResponse( "Key '0' is clean! Back to ses2: "+' <a href="http://127.0.0.1:8000/firstapp/ses2/">ses2</a>' )

 

def getses( request ) :

    per = request.session['ses'] = 2

   

    # Проверка значения в сессии методом get

    if request.session.get( 'ses' ) == 1 :

        return HttpResponse( 'ses = 1' )

    else :

        return HttpResponse( 'ses != 1' )

   

def giveses( request ) :

    #сессия является моделью Django, определённой в django.contrib.sessions.models

    #сессия идентифицировануется 32символьным хэшем, который хранится в cookie

    #доступ к сесси можно получить с помощью стандартного API для доступа к базам данных

    from django.contrib.sessions.backends.db import SessionStore

    #Стартуем сессию

    s = SessionStore()

    #Устанавливаем переменную сессии и значение

    s['bar'] = '123'

    #Сохраняем

    s.save()

    #Получаем доступ к сессии

    sk = SessionStore( session_key = s.session_key )

    #Выводим переменную из сессии с полученным доступом

    return HttpResponse( 'session_key is: '+s.session_key+' sk_bar value is: '+sk['bar'] )

 

Все примеры снабжены подробными коментариями, но в двух словах:

ses1 - Установка и получение значения сессии

ses2 - Обращение и проверка значения сессии

delses - Очистка значения

getses - Проверка значения в сессии методом get

giveses - доступ к сесси с помощью стандартного API для доступа к базам данных

 

3.5 Запросы и чистый SQL

Приводим наш C:\django_code\first\firstapp\urls.py к виду:

from django.conf.urls import patterns, url

from . import views

 

urlpatterns = patterns('',

    url(r'^sel/(?P<id>\d+)/$', views.sel),

    url(r'^ins/$', views.ins),

    url(r'^upd/$', views.upd),

    url(r'^delete/$', views.delete),

    url(r'^mraw/$', views.mraw),

    url(r'^cursor/$', views.cursor),

)

Напоминаю, какая модель была на прошлых уроках(добавьте, если нет тестовые данные C:\django_code\first\firstapp\models.py):

from django.db import models

 

class dept ( models.Model ):

    def __str__(self):

        return self.name

    name       = models.CharField(max_length=15)

   

 

class workers ( models.Model ):

    def __str__(self):

        return self.name

    dept       = models.ForeignKey(dept)

    name       = models.TextField()

    birthday   = models.DateTimeField()

    boss       = models.CharField(max_length=12)

 

Теперь сами модели C:\django_code\first\firstapp\views.py:

from django.http import HttpResponse

 

from firstapp.models import dept

 

#Примеры SQL-запросов в оф.документации: https://docs.djangoproject.com/en/1.7/topics/db/queries/

#Примеры чистых SQL-запросов в оф.документации:https://docs.djangoproject.com/en/1.7/topics/db/sql/

 

#SELECT SQL-запрос

def sel( request, id ) :

    d_id = dept.objects.get(pk=id) # найти объект по полю id

    #Django не выполнит запрос, пока не будет вызван метод save()

    d_id.save()

    d_name = dept.objects.get(name="sale") # найти запись по полю name

    d_name.save()

    d_all = dept.objects.all() # все записи

    return HttpResponse( "select id: %s select name: %s select count: %s" % (d_id.id, d_name.name, d_all.count()) )  

 

#INSERT SQL-запрос

def ins( request ) :

    d = dept(name='New department')

    d.save()

    d_name = dept.objects.get(name="New department")

    d_name.save()

    return HttpResponse( "select name: %s" % d_name.name )

   

#UPDATE SQL-запрос

def upd( request ) :

    #UPDATE с условием

    d = dept.objects.filter(id=3).update(name='id3_name')

    d_id = dept.objects.get(pk=3)

    d_id.save()

    return HttpResponse( "select id: %s" % d_id.name )

   

#DELETE SQL-запрос

def delete( request ) :

    dept.objects.filter(name="New department").delete()

    return HttpResponse( "New department is delete")

   

#SQL с помощью Manager.raw

def mraw( request ):

    #Manager.raw  принимает чистый SQL запрос, выполняет, возвращает экземпляр django.db.models.query.RawQuerySet

    html = ''

    #Raw query must include the primary key \ Raw query должен включать первичный ключ

    for dname in dept.objects.raw('SELECT id, name FROM firstapp_dept'):

        html = html+dname.name+'<br />'

    return HttpResponse(html)

   

#SQL с помощью объекта Объект django.db.connection

def cursor( request ):

    #Подключение к базе данных и получение объекта указателя с помощью вызова connection.cursor()

    #cursor.execute(sql, [params]) для выполнения SQL-запросов

    #cursor.fetchone() или cursor.fetchall() для получения результата

    from django.db import connection

   

    cursor = connection.cursor()   

    cursor.execute("SELECT id, name FROM firstapp_dept WHERE id = %s", [3])

    row = cursor.fetchone()

 

    return HttpResponse(row[1])

 

Теперь проверяем:

http://127.0.0.1:8000/firstapp/sel/2/

http://127.0.0.1:8000/firstapp/ins/

http://127.0.0.1:8000/firstapp/upd/

http://127.0.0.1:8000/firstapp/delete/

 

Последние два примера уже с чистыми SQL запросами

http://127.0.0.1:8000/firstapp/mraw/

http://127.0.0.1:8000/firstapp/cursor/

 

3.6 Простые формы

Задачи:

1. Создать форму

2. Ввести простые проверки корректной заполненности полей формы

3. Получить доступ к отправленным данным

 

В файле C:\django_code\first\first\settings.py установлен путь для шаблонов

TEMPLATE_DIRS = (

    'C:\\django_code\\forms\\' ,

)

Пропишем в C:\django_code\first\firstapp\urls.py обработчик для запроса

from django.conf.urls import patterns, url

from . import views

 

urlpatterns = patterns('',

    url(r'^form/$', views.form),

)

Теперь наше представление C:\django_code\first\firstapp\views.py

from django.shortcuts import render

from django.http import HttpResponse

 

#django.forms – библиотека django для работы с формами

from django import forms

 

#Форма с несколькими разнотипными полями

class NameOfForm(forms.Form):

    FormField1 = forms.CharField(label='Your name?', max_length=100)

    FormField2 = forms.EmailField()

    FormField3 = forms.BooleanField(required=False)

 

def form(request):

    # Если отработал метод POST

    if request.method == 'POST':

        form = NameOfForm(request.POST)

        # is_valid - проверка заполнения полей формы

        # при успехе возвращает True и добавляет данные формы в атрибут cleaned_data

        if form.is_valid(): 

            data = ""

            # покажем введенные данные

            for x in form.cleaned_data:

                data = data + str(form.cleaned_data[x]) + "<br />"

            return HttpResponse(data)

    else:

        form = NameOfForm()

    # Вывод формы

    return render(request, 'form.html', {'form': form})

И сам шаблончик для вывода формы C:\django_code\forms\form.html:

<form action="/firstapp/form/" method="post">

    {% csrf_token %}

    {{ form.as_p }}

    <input type="submit" value="Submit" />

</form>

Проверяем: http://127.0.0.1:8000/firstapp/form/