РАЗРАБОТКА АРХИТЕКТУРЫ ЗАКРЫТОЙ КОРПОРАТИВНОЙ СЕТИ С ИСПОЛЬЗОВАНИЕМ ФРЕЙМВОРКА DJANGO

МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ

Федеральное государственное бюджетное образовательное учреждение

высшего профессионального образования

«КУБАНСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ»

(ФГБОУ ВПО «КубГУ»)

Кафедра математического моделирования

ДОПУСТИТЬ К ЗАЩИТЕ В ГАК

Заведующий кафедрой

академик РАН, д-р физ.-мат наук

В.А.Бабешко

(подпись) (инициалы, фамилия)

 2014 г.

ВЫПУСКНАЯ КВАЛИФИКАЦИОННАЯ (ДИПЛОМНАЯ)

РАБОТА

РАЗРАБОТКА АРХИТЕКТУРЫ ЗАКРЫТОЙ КОРПОРАТИВНОЙ СЕТИ С ИСПОЛЬЗОВАНИЕМ ФРЕЙМВОРКА DJANGO

Работу выполнил В.Д. Михно

(подпись, дата) (инициалы, фамилия)

Факультет компьютерных технологий и прикладной математики 

Специальность 010501 – Прикладная математика и информатика

Научный руководитель,

доцент, канд. физ.-мат наук       С.Е.Рубцов

(подпись, дата) (инициалы, фамилия)

Нормоконтролер

канд. физ.-мат наук, доцент М.С.Капустин

(подпись, дата) (инициалы, фамилия)

Краснодар 2014


РЕФЕРАТ

Дипломная работа 56 с., 11 рис., 12 источников, 3 приложения.

DJANGO, MODEL-VIEW-CONTROLLER, CLASS-BASE-VIEW, МОДЕЛЬНЫЕ ФОРМЫ, МИГРАЦИИ.

Работа посвящена разработке веб-сайта с помощью свободно распространяемого фреймворка Django.

Цель работы – создание корпоративной сети и ее административной части для организации ККМОО «Молодежная лига развития национальных культур Кубани».

Задачи работы: с помощью свободно распространяемого фреймворка Django для веб-приложений, на языке Python, разработать веб-приложение, для фирмы ККМОО «Молодежная лига развития национальных культур Кубани», реализующее четвертый и пятый разделы технического задания; реализовать главную страница пользователя, возможность загружать документы себе на страницу и скачивать со страниц других пользователей; реализовать личную ленту новостей и страницу новостей всех пользователей, с возможностью поиска новости по словам в тексте и заголовке, фильтрация по тегам и по датам; переписать уже реализованный функционал сайта и дописать новый, используя Class-Base-View (CBV-способ описания view с помощью классов); подключить библиотеку south, для осуществления динамического изменения структуры базы данных; подключить библиотеки grapelli, для придания административной части гибкости и дружественного интерфейса; подключить библиотеку filebrowser, для множественной загрузки файлов; реализовать структуру базы данных в модельной части проекта; реализовать функциональную часть проекта(VIEW); реализовать интерфейс пользователя с помощью html и css.

Для реализации проекта используется язык Python и СУБД PostreSQL.


СОДЕРЖАНИЕ

ВВЕДЕНИЕ 4

1 Анализ корпоративных сетей. 5

1.1 ASmallWorld 5

1.2 Decayenne 6

1.3 Evrika 7

2 Структура web-приложения 8

3 База данных и административная часть 10

4 Class-Base-View 19

5 Логическая часть приложения и отображение данных на страницах 21

ЗАКЛЮЧЕНИЕ 26

СПИСОК ИСПОЛЬЗУЕМОЙ ЛИТЕРАТУРЫ 27

ПРИЛОЖЕНИЕ А 28

ПРИЛОЖЕНИЕ Б 29

ПРИЛОЖЕНИЕ В 56


ВВЕДЕНИЕ

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

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

Для обеспечения защиты данных в корпоративных сетях могут использоваться различные организационно – технические методы (выделение ответственных специалистов, применение списков контроля доступа, использование VPN и т.п.). Их совокупность называется комплексной системой защиты информации.

Некоторые работодатели запрещают пользоваться обычными социальными сетями в рабочее время – не только ради экономии времени, но и чтобы воспрепятствовать утечке информации.

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


1 Анализ корпоративных сетей

Кроме общедоступных «В Контакте», «Facebook», «Одноклассники», существуют корпоративные сети, членство в которых доступно только для избранных или для людей с определенной профессией, ограниченные в доступе и возможностях обмена информации. Рассмотрим некоторые из них.

1.1 ASmallWorld

Рисунок 1 – Корпоративная сеть ASmallWorld

Одна из самых первых эксклюзивных европейских социальных сетей, принимающая только «людей из мира высокого искусства, которые определяются по трем параметрам». Вы должны быть приглашены кем-то из существующих членов данной сети, но даже в этом случае нет никакой гарантии, что вас примут. Руководит сетью 25 – летний швейцарец Патрик Лиотард–Войт (Patrick Liotard-Vogt).

1.2 Decayenne

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

Создатели сети описывают ее как «оазис вдохновения и развлечений» для «космополитичного, независимого, значимого, толерантного, либерального нонконформиста».

Рисунок 2 – Корпоративная сеть Decayenne

1.3 Evrika

Evrika –корпоративная сеть для российских врачей. Принадлежит медиа – группе "MedInform Healthcare Communications". Все страницы сайта, кроме главной, не индексируются поисковиками и доступны только зарегистрированным пользователям. Для получения доступа нужно быть действующим врачом, способным подтвердить свои профессиональные знания и факт работы в медицинском учреждении.

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

По нашему мнению, сайт нацелен на доходы от продвижения лекарств, медоборудования и других изделий для здравоохранения в профессиональную среду. Это подтверждает его интеграция с ресурсом "МедМнение". Последний в интересах фармацевтических компаний проводит опросы среди врачей и платит деньги за участие в них.


2 Структура web–приложения

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

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

Весь функционал сайта разбит на 3 приложения profile, blog, message. Первое осуществляет отображение и редактирование личной информации, ленту своих новостей, создание новой новости, добавление документов для скачивания другим пользователям, поиск, добавление и удаление других пользователей. Второе отображение новостей для всех пользователей, с возможностью комментирования. И последнее третье, отвечает за обмен сообщениями между пользователями.

Каждое приложение состоит из двух частей:

– Общедоступная часть, которая дает людям возможность управлять своим профилем.

– Административная часть, которая позволит администратору редактировать базу данных сайта.

Эти две части реализованы, следуя шаблону Модель-Представление-Контроллер (Model-View-Controller, MVC). Примем, что MVC определяет способ разработки программного обеспечения, при котором код для определения и доступа к данным (модель, файл models.py) отделен от логики приложения (управление, файл views.py), которая в свою очередь отделена от интерфейса пользователя (представление, файл html) так, что модификация одного из компонентов оказывает минимальное воздействие на остальные.

Основой проекта будут manage.py, __init__.py, settings.py, urls.py, wsgi.py.

– manage.py скрипт, который позволяет вам взаимодействовать с проектом Django.

– __init__.py пустой файл, который указывает Python, что текущий каталог является пакетом Python.

– settings.py настройки/конфигурация проекта.

– urls.py конфигурация URL-ов для вашего проекта Django. Это “содержимое” всех Django-сайтов.

– wsgi.py точки входа для WSGI-совместимый веб-серверов.

Содержимое этих файлов представлено в приложении А.

В данной работе помимо модуля django-registration, будем использовать модуль south, для осуществления миграции базы данных, grapelli, для придания административной части красивого вида, filebrowser, для множественной загрузки файлов.


3 База данных и административная часть

В качестве СУБД выбрана PostgreSQL, в связи с наличием некоторых особенностей в PostgreSQL, которые часто используются – внешние ключи, триггеры и представления. Они позволяют скрывать сложность базы данных от приложения, таким образом избегая создания сложных команд SQL. Подключение к базе данных осуществляется в папке settings (в предыдущей работе все настройки находились в одном файле settings.py).

DATABASE = {

'default': {

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

'NAME': 'diplom',

'USER': 'postgres',

'PASSWORD':'postgres',

'HOST': '127.0.0.1',

'PORT': '5432',

}

}

Эта настройка ведется с учетом того, что в PostgreSQL мы уже создали пустую базу данных с названием diplom.

Рассмотрим модельную часть приложения, отвечающую за главную страницу пользователя.

Класс Profile описывает структуру таблицы profile, которая ссылается на таблицу User, (сгенерированную при подключении приложения django.contrib.auth), с помощью поля user (объект класса ForeignKey, атрибут-указатель которого будет модель User).

user = models.ForeignKey(User, related_name='profile', verbose_name = ('User'), blank = True, null=True)

Так же в этой модели описаны два поля friends и friesnd_requests, которые являются объектами класса ManyToManyField(отношение многие-ко-многим) и ссылаются на свою же модель (“self”), для определения, какие объекты Profile находятся в друзьях и кто хочется стать другом.

friends = models.ManyToManyField("self", blank=True, null=True, symmetrical = False, related_name='friends_targets')

friend_requests = models.ManyToManyField("self", blank=True, null=True, symmetrical = False, related_name='friend_requests_targets' )

Поле party необходимо для администратора, что бы подтверждать, что пользователь является сотрудником фирмы, обычный пользователь видеть его не будет. Если модуль django-registration, обеспечивает проверку на регистрацию существующего человека, то поле party будет рычагом администратора, для добавления в социальную сеть только сотрудников фирмы. Только после того как администратор свяжется с зарегистрированным пользователем и убедится, что тот является участником, он активирует его аккаунт через административную часть, и пользователь сможет полноценно пользоваться сайтом.

party = models.BooleanField(u'Является участником сообщества', blank=True, default = False)

Поле для фотографии пользователя изменено в этой работе на FileBrowserField. Этот класс предоставляет нам возможность загружать сразу несколько файлов, выбирать какого размера они будут и многое другое (рисунок 3).

Рисунок 3 – Административная часть модели Profile

Рисунок 3 – Административная часть модели Profile

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

Для того что бы хранить документы пользователя, которые он будет загружать для скачивания другим пользователям, создаем дополнительную модель FileProfile (рисунок 4).

Рисунок 4 – Административная часть модели FileProfile

Эта модель содержит поле для документа file (FileBrowserField), в которое будет сохраняться файл при добавлении его пользователем. Для того что бы поле загружало конкретно документы необходимо установить параметр ‘format’ строковым аргументом ‘document’. Тогда поле сможет сохранять форматы '.pdf','.doc','.rtf','.txt','.xls','.csv'.

file = FileBrowseField(u"Файл", directory='uploads/files/' , max_length=100, format = 'document', null=True, blank=True)

Поле user(ForeignKey), которое будет автоматически, при сохранении объекта модели, заполняться объектом модели Profile текущего пользователя.

user = models.ForeignKey(Profile, related_name='profile', verbose_name=('User'), blank=True, null=True)

Так же добавим два дополнительных поля title и date соответственно CharField и DateTimeField.

title = models.CharField(u"Заголовок", max_length=64, blank=True, null=True)

date = models.DateTimeField(verbose_name=u'Дата загрузки файла',blank=True, null=True, default = datetime.datetime.now)

После сохранения файла models.py в приложении profile, надо что бы в базе данных сгенерировалась описанные нами модели. В предыдущей работе я использовала стандартную команду django – syncdb, которая может с нуля создать таблицу, но не производить с ней в дальнейшем никаких изменений. Т. е. если я изменяла какие-либо поля мне приходилось удалять всю таблицу, зависимые таблицы, и все их данные для того что бы просто добавить поля. Иногда вручную, в PostgreSQL создавала или редактировала поля, но при добавления поля-связи (ManyToManyField, ForeignKey и т. д.) конечно же возникали трудности. Для того что бы избежать всего этого устанавливаем и подключаем модуль south, который осуществляет редактирование таблиц в базе данных с помощью команд schemamigration и migrate. Если мы первый раз делаем миграцию, то необходимо выполнять команду schemamigration с ключём –initial:

>python manage.py schemamigration profile –initial

После этой команды в приложении создастся папка migrations, в которой сформируется файл c расширением .py, при запуске которого командой migrate, выполнятся питоновские скрипты и произойдут изменения в нашей таблице:

>python manage.py migrate profile

В дальнейшем при редактировании полей в этом приложении будем использовать те же команды, но уже с ключом –auto.

При создании остальных таблиц на основе моделей будем также использовать south.

Теперь перейдем к приложению blog, которое содержит модели Blog, Tags и Comment, описывающие соответствующие таблицы в базе данных. Модель Blog (рисунок 6) ссылается на модель Tags (рисунок 5) с помощью поля tags, которое является экземпляром класса ManyToManyField. Это означает, что каждому объекту модели Blog будет соответствовать множество объектов модели Tags.

tags = models.ManyToManyField(Tags, verbose_name=u'Теги', blank=True)

Рисунок 5 – Административная часть модели Tags

Рисунок 6 – Административная часть модели Blog

Модель Comment (рисунок 7) будет ссылаться на модель Blog с помощью связи ForeignKey.

Рисунок 7 — Административная часть модели Comment

Это необходимо для того что бы определять, какие комментарии относятся к конкретной новости. При создании этих трёх моделей также нам необходимы поля:

Blog: zagol, author – (обьект класса CharField) заголовок новости и имя автора, image – (объект класса FileBrowseField) обложка новости, date_of_publication – (DateTimeField) дата публикации (по умолчанию устанавливается в текущую дату создания), и text – (TextField) текст новости;

Tags: name – (CharField) название тега;

Comment: author_name – (CharField) имя автора комментария, text – (TextField) текст комментария, pub_date – (DateTimeField) дата публикации комментария, admin_comment – (BooleanField) устанавливается в True администратором, если он одобряет комментарий;

Для реализации раздела СООБЩЕНИЯ создаем еще одно приложение messages. Файл models.py для этого приложения будет содержать модели Message и Chat, которые будут позволять обмениваться сообщениями между друзьями социальной сети.

Модель Message содержит два поля sender и recipient (ForeignKey), которые ссылаются на модель User, и определяют, кто из пользователей отправляет сообщение, а кто получает (рисунок 8).

Рисунок 8 – Административная часть модели Message

Модель Chat служит для объединения в один объект всех объектов из модели Message, у которых получатель или отправитель соответствует полям person1 и person2, которые в свою очередь ссылаются на модель User (рисунок 9).

Рисунок 9 – Административная часть модели Сhat

Поле messages – экземпляр класса ManyToManyField и ссылается на модель Message. Т. е. один объект Chat будет ссылаться на несколько объектов модели Message.

Так же эти две модели будут содержать поля date – дата создания сообщения (DateTimeField), title – заголовок сообщения (CharField), message – текст сообщения (TextField), reader – булевское поле для установления, прочитано ли сообщение получателем или нет (BooleanField).

Все модели представлены в приложении Б в разделах соответствующих файлам models.py.


4. Class-Base-View

Весь функционал сайта был переписан, используя Class-Base-View(CBV), способ описания view с помощью классов, в связи с наличием часто используемого функционала. Чтобы не приходилось писать однообразный код, подобные view описаны прямо в коде фреймворка.

В данном проекте в качестве родительских классов используются стандартные классы ListView, DetailView, TemplateView, View, CreateView и MonthArchiveView.

Класс TemplateView позволяет отображать один шаблон, который мы указываем в атрибуте template_name. Что бы изменить передаваемый в запросе словарь с переменными, необходимо переопределить метод get_context_data и в нем добавлять в словарь context все необходимые нам аргументы.

Класс ListView обеспечивает вывод объектов в виде списка. В качестве основных аргументов используются model – для указания, из какой модели мы будем получать объекты, template_name – для явного указания какой в какой шаблон будем обрабатывать. Хотя если явно не указывать этот атрибут, Django “вычислит” его из названия объекта. В данном случае, таким “вычисленным” шаблоном будет "APP/MODEL_list.html" – часть “APP” берется из имени приложения, определяющего модель, а часть “MODEL” – это просто название модели в нижнем регистре.

Класс DetailView позволяет получать один объект, id которого будет соответствовать аргументу pk, который будет передаваться в url. Так же основным аргументом является model, которому мы будем указывать нашу модель, из которой нужно получить объект.

Класс View умеет вызывать свои фунции get(), post() и т.п. в зависимости от типа запроса, передавая request.

Класс CreateView осуществляет создание нового объекта. Основной параметр который нам необходимо указать так же является model. При генерации формы, если нам нужно что бы сохранялись какие-нибудь конкретные поля или наоборот исключить ненужные, используются атрибуты fields и exclude, которым передаются списки полей.

MonthArchiveView – класс, который позволяет фильтровать только те объекты, у которых поле, отвечающее за дату создания, соответствует месяцу и году, которые передаются в url. Для этого используются атрибуты date_field и queryset.


5 Логическая часть приложения и отображение данных на страницах

Теперь приступим к реализации функционала наших страниц.

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

Для этого создадим класс ProfileView, который будет наследоваться от класса CreateView. Но в связи с тем, что на странице будет выполняться множество действий, необходимо поменять поведение view, которые описывают родительский класс. Метод get_context_data будет срабатывать при GET запросе, и выводить две формы (для создания новости и загрузки документа). Так же в каждой view мы будем устанавливать проверку:

if (self.request.user.is_authenticated()) and (Profile.objects.get(pk= self.request.user.id ).party == True) and (not 'pk' in self.kwargs)

Этот фрагмент определят, зарегистрирован ли текущий пользователь, активирован ли он администратором и находится ли на своей странице или на странице другого пользователя.

Рисунок 10 – Главная страница пользователя

Формы для создания новости BlogForm и для загрузки файла FileForm опишем в той же директории в файле forms.py.

Первую форму укажем как стандартный атрибут родительского класса form_class. И при срабатывании POST запроса, эта форма будет обрабатываться стандартными методами CreateView. Что бы не прописывать много лишних полей в форме BlogForm, мы будем использовать класс ModelForm, который укажет что форма будет наследоваться от модели Blog, с помощью атрибута model, и атрибуту exclude укажем какие поля мы не хотим изменять.

class BlogForm(forms.ModelForm):

class Meta:

model = Blog

exclude = ('number','author','date_of_publication', 'image','tags')

thumbnail = forms.FileField(max_length=200, label="Обложка новости", required=False)

Т. к. нам нужно что бы пользователь не видел технические поля (такие как author, date_of_publication, number, поле tags представляет собой ссылку на объекты (ManyToManyField), поле image – FileBrowserField не предоставляет функционал загрузки файла на станице сайта) то их мы будем обрабатывать и заполнять вручную во время проверки на валидность формы.

Что же касается второй формы, FileForm, то мы ее будем просто передавать в словаре context вместе с другими нужными нам переменными, и обработка будет происходить с помощью другого класса UploadView, который будет наследоваться от стандартного класса View, обеспечивающий метод post, который мы переопределим.

class FileForm(forms.ModelForm):

class Meta:

model = FileProfile

exclude = ('user', 'date', 'file')

doc = forms.FileField(max_length=200, label="Файл", required=False)

Хочу заметить, что при загрузке картинки новости или документа для скачивания, в формах использовалось дополнительно поле FileField. Это связано с тем, что функционал поля FielBrowserField не позволяет загружать файл на странице сайта, в отличие от стандартных Django-полей ImageField и FileField, которое описано в форме. Поэтому при выводе на шаблон (файл *.html), мы скрываем поле моделей Blog и FileProfile, а вместо них указываем дополнительное поле FileField. И уже при переопределении метода, мы из POST запроса получаем объект файла, сохраняем его по нужному нам пути и с помощью метода FileObject, который импортируется из библиотеки filebrowser, преобразуем его в объект класса FileBrowserField.

Весь код данных страниц представлен в приложении Б.

Приложение, реализующее раздел БЛОГ, описывается в папке blog нашего проекта. Основная страница этого раздела представляет собой ленту новостей, с возможностью просматривать каждую новость полностью, формой поиска по словам в тексте, заголовке и тегам новости, а также боковое меню, для фильтрации новостей по архивам (рисунок 11).

Рисунок 11 – Главная страница новостей

Функционал главной страницы новостей осуществляется с помощью класса ListView, которому передаем в качестве атрибута model модель Blog, что бы вывести все объекты данной модели.

class BlogList(ListView):

model = Blog

context_object_name = "blog"

def get_context_data(self, **kwargs):

context = super(BlogList, self).get_context_data(**kwargs)

if self.request.user.is_authenticated() and Profile.objects.get(pk=self.request.user.id).party==True:

date_obj = []

for obj in Blog.objects.dates('created', 'month'):

date_obj.append(obj)

context['archives'] = date_obj

context['active_main_menu']='main_blog'

else:

self.template_name = "profile/error.html"

context['ErrorText'] = u"Вы не авторизированны"

return context

Для просмотра каждой новости создаем класс BlogDetail, а в качестве родителя класса будем указывать CreateView, что бы была возможность создавать комментарии. Атрибуту model задаем как объект модели Blog, указывая на основе какой модели, мы будем строить форму, а в атрибуте exclude укажем какие поля, мы не будем отображать на шаблоне.

model = Comment

exclude = ['article', 'author_name', 'pub_date', 'admin_comment']

И теперь, что бы при сохранении объекта наши исключенные поля тоже приобрели нужные нам значения, переопределим метод form_valid:

def form_valid(self, form):

instance = form.save(commit=False)

instance.article = Blog.objects.get(pk=self.kwargs['pk'])

instance.author_name = self.request.user.username

instance.pub_date = datetime.datetime.now()

instance.save()

return redirect(self.get_absolute_url())

def get_absolute_url(self):

return reverse("blog_detail", kwargs={"pk": self.kwargs['pk']})

Для того что бы наши объекты модели Blog фильтровались по датам указанным в боковом меню, используем класс MonthArchiveView. Этот класс обладает атрибутом date_field, принимающего название поле типа DateTimeField в виде строки, по которому будем фильтровать объекты. При этом в url будут предаваться два параметра – month, year, которые соответствуют месяцу и году указанным в ссылке.


ЗАКЛЮЧЕНИЕ

В дипломной работе с помощью Class-Base-View разработано приложение, являющееся корпоративной сетью для организации ККМОО «Молодежная лига развития национальных культур Кубани», сгенерирована база данных в PostgeSQL на основе полей описанных в моделях проекта, c помощью модуля south. Приложение осуществляет обмен сообщениями, поиск , добавление и удаления других пользователей в друзья, новостной блог, с возможностью комментирования каждой статьи и личную страницу пользователя, содержащую личную ленту новостей, список документов для скачивания и контактную информацию пользователя.

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

Планируется дальнейшее развитие проекта – добавление фото- и видео- галереи, а также, с помощью API Яндекс.translate и API Яндекс.Карты, добавить перевод всего сайта и размещения на изображении местности различных графических объектов.

Следовательно, приложение не утратит актуальности и будет в дальнейшем гораздо полезнее.

Весь проект написан на языке Python.


СПИСОК ИСПОЛЬЗУЕМОЙ ЛИТЕРАТУРЫ

1 Django 1.5 documentation [Электронный ресурс] // Django 1.5 documentation. URL: https://docs.djangoproject.com/en/1.5/. (Дата обращения: 1.09.2013)

2 Форсье, Дж. Django. Разработка веб-приложений на Python./ Дж. Форсье, П. Биссекс, У. Чан, – СПб.: Символ-Плюс, 2010. – 456 с.

3 Лутц М. Программирование на Python, том - , 4-е издание/ М. Лутц – СПб.: Символ-Плюс, 2011. – 922с.

4 Бизли, Д. Python. Подробный справочник, 4-е издание/ Д. Бизли – М.: Символ-Плюс, 2010. – 326 с.

5 Object-Relational Mapping! [Электронный ресурс] // ORM. URL: http://ru.wikipedia.org/wiki/ORM. (Дата обращения: 12.03.2012).

6 Django [Электронный ресурс] // Django. URL: http://ru.wikipedia.org/wiki/Django. (Дата обращения: 2.09.2013)

7 Buter-Brod [Электронный ресурс] // Представляем корпоративную сеть asmallworld.net для богатых и знаменитых. URL: http://buter-brot.ru/Moda/prdedstavlyaem-soczialnuyu-set-asmallworldnet-dlya-bogatyx-i-znamenityx.html/. (Дата обращения: 4.04.2014).

8 ASmallWorld. Корпоративная сеть [Электронный ресурс] // URL: https://www.asmallworld.com/. (Дата обращения: 4.30.2014).

9 Adamant [Электронный ресурс] // Оператор системных решений. URL: http://www.adamant.ua/projects/corporate-network/. (Дата обращения: 4.04.2014).


ПРИЛОЖЕНИЕ A

Файл manage.py

#!/usr/bin/env python

from django.core.management import execute_manager

import imp

try:

imp.find_module('settings') # Assumed to be in the same directory.

except ImportError:

import sys

sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)

sys.exit(1)

import settings

if __name__ == "__main__":

execute_manager(settings)


ПРИЛОЖЕНИЕ Б

Папка settings:

Файл __init.py__ (содержит все настройки Django):

# -*- encoding: utf-8 -*-

import os, sys

from django.contrib import messages

from django.utils.translation import ugettext_lazy as _

import os.path

DEBUG = True

PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "../.."))

rel = lambda p: os.path.join(PROJECT_ROOT, p)

TEMPLATE_DEBUG = DEBUG

MANAGERS = ADMINS

EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'

EMAIL_FILE_PATH = os.path.join(PROJECT_ROOT, '_emails')

EMAIL_HOST = 'localhost'

EMAIL_PORT = '8000'

EMAIL_HOST_USER = ''

EMAIL_HOST_PASSWORD = ''

EMAIL_USE_TLS = True

DATABASES = {

'default': {

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

'NAME': 'diplom',

'USER': 'postgres',

'PASSWORD': 'postgres',

'HOST': '127.0.0.1',

'PORT': '5432',

}

}

ALLOWED_HOSTS = []

TIME_ZONE = 'Europe/Moscow'

LANGUAGE_CODE = 'ru-ru'

SITE_ID = 1

USE_I18N = True

USE_L10N = True

USE_TZ = True

LOCALE_PATHS = (os.path.join(PROJECT_ROOT, 'locale'),)

MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'private/media/')

MEDIA_URL = '/media/'

STATIC_ROOT = os.path.join(PROJECT_ROOT, 'public/static/')

STATIC_URL = '/static/'

ADMIN_MEDIA_PREFIX = '/static/admin/'

STATICFILES_DIRS = (

os.path.join(PROJECT_ROOT, 'diplom/static/'),

)

DEFAULT_HOST = 'www.example.com'

STATICFILES_FINDERS = (

'django.contrib.staticfiles.finders.FileSystemFinder',

'django.contrib.staticfiles.finders.AppDirectoriesFinder',

)

SECRET_KEY = '_z(8gb-k+c^y5^1r3b02^km64ve0)bja%soa3@a23d5@*geodf'

TEMPLATE_DEBUG = DEBUG

TEMPLATE_CONTEXT_PROCESSORS = (

'django.core.context_processors.request',

'django.contrib.auth.context_processors.auth',

'django.core.context_processors.debug',

'django.core.context_processors.i18n',

'django.core.context_processors.media',

'django.core.context_processors.static',

'django.core.context_processors.tz',

'django.contrib.messages.context_processors.messages',

)

TEMPLATE_LOADERS = (

'django.template.loaders.filesystem.Loader',

'django.template.loaders.app_directories.Loader',

'django.template.loaders.eggs.Loader',

)

TEMPLATE_DIRS = (

os.path.join(PROJECT_ROOT, 'templates/'),

)

"""Middleware related settings."""

MIDDLEWARE_CLASSES = (

'django.middleware.common.CommonMiddleware',

'django.contrib.sessions.middleware.SessionMiddleware',

'django.middleware.locale.LocaleMiddleware',

'django.middleware.csrf.CsrfViewMiddleware',

'django.contrib.auth.middleware.AuthenticationMiddleware',

'django.contrib.messages.middleware.MessageMiddleware',

'django.middleware.clickjacking.XFrameOptionsMiddleware',

)

AUTHENTICATION_BACKENDS = (

'django.contrib.auth.backends.ModelBa

EMAIL_HOST = 'localhost'

EMAIL_PORT = 1025

EMAIL_HOST_USER = ''

EMAIL_HOST_PASSWORD = ''

EMAIL_USE_TLS = False

DEFAULT_FROM_EMAIL = 'info@google.ru'

LOGGING = {

'version': 1,

'disable_existing_loggers': False,

'filters': {

'require_debug_false': {

'()': 'django.utils.log.RequireDebugFalse'

}

},

'handlers': {

'mail_admins': {

'level': 'ERROR',

'filters': ['require_debug_false'],

'class': 'django.utils.log.AdminEmailHandler'

}

},

'loggers': {

'django.request': {

'handlers': ['mail_admins'],

'level': 'ERROR',

'propagate': True,

},

}

}

AUTH_PROFILE_MODULE = 'profile.Profile'ckend', # this is default

'guardian.backends.ObjectPermissionBackend',

)

ANONYMOUS_USER_ID = -1

ROOT_URLCONF = 'diplom.urls'

MESSAGE_TAGS = {

messages.DEBUG: 'debug',

messages.INFO: 'alert-info',

messages.SUCCESS: 'alert-success',

messages.WARNING: 'alert-warning',

messages.ERROR: 'alert-error',

}

FIXTURE_DIRS = (

os.path.join(PROJECT_ROOT, 'diplom/fixtures'),

)

WSGI_APPLICATION = 'diplom.wsgi.application'

INSTALLED_APPS = (

'django.contrib.auth',

'django.contrib.contenttypes',

'django.contrib.sessions',

'django.contrib.sites',

'django.contrib.messages',

'django.contrib.staticfiles',

'django.contrib.flatpages',

'django.contrib.redirects',

'filebrowser',

'grappelli.dashboard',

'grappelli',

'guardian',

'django.contrib.admin',

'django.contrib.admindocs',

'south',

'registration',

'diplom',

'profile',

'blog',

'messages',

)

from installed_apps.grappelli import *

from installed_apps.logs import *

from installed_apps.filebrowser import *

SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'

DEFAULT_FROM_EMAIL = 'info@google.ru'

LOGGING = {

'version': 1,

'disable_existing_loggers': False,

'filters': {

'require_debug_false': {

'()': 'django.utils.log.RequireDebugFalse'

}

},

'handlers': {

'mail_admins': {

'level': 'ERROR',

'filters': ['require_debug_false'],

'class': 'django.utils.log.AdminEmailHandler'

}

},

'loggers': {

'django.request': {

'handlers': ['mail_admins'],

'level': 'ERROR',

'propagate': True,

},

}

}

AUTH_PROFILE_MODULE = 'profile.Profile'

Файл installed_apps/filebrowser.py (содержит все настройки для Filebrowser):

# -*- encoding: utf-8 -*-

from django.utils.translation import ugettext_lazy as _

FILEBROWSER_DIRECTORY = 'uploads/'

FILEBROWSER_CONVERT_FILENAME = True

FILEBROWSER_NORMALIZE_FILENAME = True

FILEBROWSER_VERSIONS = {

'admin_thumbnail': {'verbose_name': _('Admin Thumbnail'), 'width': 60, 'height': 60, 'opts': 'crop'},

'thumbnail': {'verbose_name': _('Thumbnail (1 col)'), 'width': 60, 'height': 60, 'opts': 'crop'},

'news_logo': {'verbose_name': (u'Логотип новости'), 'width': 100, 'height': 75, 'opts': 'crop'},

'services_thumbnail': {'verbose_name': (u'Миниатюры для услуг'), 'width': 120, 'height': 90, 'opts': 'crop'},

'our_face': {'verbose_name': (u'Фотографии наших сотрудников'), 'width': 216, 'height': 278, 'opts': 'crop'},

'profile_photo': {'verbose_name': (u'Фотография пользователя'), 'width': 205, 'height': 250, 'opts': 'crop'},

'admin_list_blog':{'verbose_name':u'Изображение для списока блогов(655*215)', 'width': 655, 'height': 215, 'opts': 'crop'},

}

FILEBROWSER_ADMIN_VERSIONS = ['thumbnail', 'news_logo', 'services_thumbnail', 'our_face', 'profile_photo',

'admin_list_blog'] #'small', 'medium', 'big', 'large',

FILEBROWSER_ADMIN_THUMBNAIL = 'admin_thumbnail'

FILEBROWSER_MAX_UPLOAD_SIZE = 60485760

FILEBROWSER_IMAGE_MAXBLOCK = 1024*1024

FILEBROWSER_EXTENSIONS = {

'Folder': [''],

'Image': ['.jpg','.jpeg','.gif','.png','.tif','.tiff'],

'Document': ['.pdf','.doc','.rtf','.txt','.xls','.csv'],

'video': ['.mov','.wmv','.mpeg','.mpg','.avi','.rm'],

'audio': ['.mp3','.mp4','.wav','.aiff','.midi','.m4p']

}

FILEBROWSER_SELECT_FORMATS = {

'file': ['Folder','Image','Document','video','audio'],

'image': ['Image'],

'document': ['Document'],

'media': ['video','audio'],

}

Файл diplom/urls.py (содержит все url настроек и сслыки на urls.py других приложений):

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

from django.conf import settings

from django.contrib import admin

from filebrowser.sites import site

from .forms import RegistrationFormProfile

from profile.views import ProfileSettingView, UploadView

import registration

import os

admin.autodiscover()

urlpatterns = patterns('',

(r'^accounts/', include('registration.urls')),

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

(r'^accounts/', include('registration.urls')),

(r'^accounts/profile/$', 'profile.views.profile_return'),

(r'^accounts/edit/profile/$', ProfileSettingView.as_view()),

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

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

url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),

url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

(r'^upload_file/$', UploadView.as_view()),

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

url(r'^message/', include('messages.urls')),

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

)

Приложение PROFILE:

Файл profile/urls.py (содержит все url-ы приложения profile):

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

from views import ProfileView

urlpatterns = patterns('',

url(r'^$', ProfileView.as_view(), name="profile"),

url(r'^friend/(?P<pk>\d+)/$', ProfileView.as_view(), name="profile_friend"),

url(r'^friends/all/$', 'profile.views.search_person'),

url(r'^friends/add/(?P<id>[^/]+)/$', 'profile.views.add_person'),

url(r'^friends/del/(?P<id>[^/]+)/$', 'profile.views.del_person'),

url(r'^friends/accept/(?P<objid>[^/]+)/$', 'profile.views.accept_friend'),

url(r'^friends/reject/(?P<objid>[^/]+)/$', 'profile.views.reject_friend'),

)

Файл profile/models.py (содержит модели Profile и FileProfile приложения profile):

# -*- coding: utf-8 -*-

from django.db import models

from django.contrib.auth.models import User

from diplom.settings import *

from filebrowser.fields import FileBrowseField

from django.core.urlresolvers import reverse

import datetime

class Profile(models.Model):

user = models.ForeignKey(User, related_name='profile', verbose_name=('User'), blank=True, null=True)

thumbnail = FileBrowseField(u"Иконка", max_length=200, directory='uploads/', format='image', null=True, blank=True)

requisites = models.TextField(u'Дополнительные сведения', blank=True)

login = models.CharField(u'Логин',max_length=150,blank=True, null=True)

last_name = models.CharField(u'Фамилия',max_length=150,blank=True)

first_name = models.CharField(u'Имя',max_length=150,blank=True)

midlle_name = models.CharField(u'Отчество',max_length=150,blank=True)

friends = models.ManyToManyField("self", blank=True, null=True, symmetrical = False, related_name='friends_targets')

friend_requests = models.ManyToManyField("self", blank=True, null=True, symmetrical = False, related_name='friend_requests_targets' )

icq = models.CharField(u'ICQ', max_length=150, blank=True)

skype = models.CharField(u'Skype', max_length=150, blank = True)

telephone = models.CharField(u'Телефон', max_length=150, blank = True)

party = models.BooleanField(u'Является участником сообщества', blank=True, default=False)

def __unicode__(self):

return u'%s' % (self.user)

def get_absolute_url(self):

return reverse("profile", kwargs={})

def get_files(self):

return FileProfile.objects.filter(user = self)

class Meta:

verbose_name = u"Пользователь"

verbose_name_plural = u"Пользователи"

class FileProfile(models.Model):

user = models.ForeignKey(Profile, related_name='profile', verbose_name=('User'), blank=True, null=True)

title = models.CharField(u"Заголовок", max_length=64, blank=True, null=True)

date = models.DateTimeField(verbose_name=u'Дата загрузки файла',blank=True, null=True, default = datetime.datetime.now)

file = FileBrowseField(u"Файл", directory='uploads/files/' , max_length=100, format = 'document', null=True, blank=True)

def __unicode__(self):

return u'%s' % (self.user)

class Meta:

verbose_name = u"Файл пользователя"

verbose_name_plural = u"Файлы пользователей"

Файл profile/admins.py (содержит подключение и настройки модели Profile, FileProfile для административной части):

from django.contrib import admin

from models import Profile, FileProfile

class ProfileContentAdmin(admin.TabularInline):

model = FileProfile

fields = ('title','file',)

extra = 1

class FileProfileAdmin(admin.ModelAdmin):

list_display = ('user', 'title', 'file', 'date')

ordering = ('user', 'date')

list_filter = ('user', 'date')

class ProfileAdmin(admin.ModelAdmin):

list_display = ('user', 'last_name', 'first_name', 'midlle_name', 'party')

ordering = ('user',)

list_filter = ('user',)

inlines = [ProfileContentAdmin]

admin.site.register(Profile,ProfileAdmin)

admin.site.register(FileProfile, FileProfileAdmin)

Файл profile/forms.py (содержит модельные формы ProfileForm, BlogForm, FileForm приложения profile):

# -*- encoding: utf-8 -*-

from django import forms

from models import Profile, FileProfile

from blog.models import Blog

class ProfileForm(forms.ModelForm):

class Meta:

model = Profile

exclude = ('user', 'thumbnail', 'login', 'friends', 'friend_requests', 'party')

image = forms.FileField(max_length=200, label="Иконка", required=False)

new_password = forms.CharField(max_length=150, required=False,label='Новый пароль')

confirm_password = forms.CharField(max_length=150, required=False,label='Подтвердить пароль')

class BlogForm(forms.ModelForm):

class Meta:

model = Blog

exclude = ('number','author','date_of_publication', 'image','tags')

thumbnail = forms.FileField(max_length=200, label="Обложка новости", required=False)

class FileForm(forms.ModelForm):

class Meta:

model = FileProfile

exclude = ('user', 'date', 'file')

doc = forms.FileField(max_length=200, label="Файл", required=False)

Файл profile/views.py (содержит View описывающие функционал главной страницы пользователя и страницы поиска других пользователей):

# -*- coding: utf-8 -*-

from django.views.generic import ListView, DetailView, TemplateView, View

from models import Profile

from messages.models import Chat, Message

from django.views.decorators.csrf import csrf_exempt

from django.shortcuts import render_to_response

from django.contrib.auth.models import User

from forms import ProfileForm, BlogForm, FileForm

from django.views.generic.edit import FormView, CreateView, UpdateView

from django.template import RequestContext

from django import forms

from django.db.models import Q

from django.http import HttpResponse, HttpResponseRedirect

import datetime

from django.shortcuts import render_to_response, redirect

from blog.models import Blog, Tags

from django.core.urlresolvers import reverse

from django.core.files.storage import default_storage

from django.core.files.base import ContentFile

from filebrowser.base import FileObject

def profile_return(request):

return render_to_response('profile/return.html', {}, context_instance=RequestContext(request))

class UploadView(View):

def post(self, request, *args, **kwargs):

form = FileForm(request.POST, request.FILES)

if form.is_valid:

instance = form.save(commit=False)

path = default_storage.save('uploads/files/file.pdf', ContentFile(self.request.FILES['doc'].read()))

instance.file = FileObject(path)

instance.user = Profile.objects.get(user = request.user)

instance.save()

return redirect(self.get_absolute_url())

def get_absolute_url(self):

return reverse("profile", kwargs={})

class ProfileView(CreateView):

template_name = "profile/profile.html"

form_class = BlogForm

def create_object_profile(self, pk):

vector = User.objects.get(pk = pk)

object = Profile()

object.user_id = vector.id

object.first_name = vector.first_name

object.last_name = vector.last_name

object.save()

return object

def get_context_data(self, **kwargs):

context = super(ProfileView, self).get_context_data(**kwargs)

if (self.request.user.is_authenticated()) and (Profile.objects.get(pk=self.request.user.id).party==True) and (not 'pk' in self.kwargs):

person_obj = self.request.user

if Profile.objects.filter(pk=person_obj.id).count()==0:

self.create_object_profile(person_obj.id)

person_pk = person_obj.id

elif self.request.user.is_authenticated() and 'pk' in self.kwargs and self.kwargs['pk']:

person_pk = self.kwargs['pk']

if Profile.objects.filter(pk=person_pk).count()==0:

self.create_object_profile(person_pk)

person_obj = User.objects.get(pk = person_pk)

else:

self.template_name = "profile/error.html"

context['ErrorText'] = u"Вы не авторизированны"

context['blog'] = Blog.objects.filter(author=person_obj.username).order_by('-number',)

context['person'] = Profile.objects.get(pk = person_pk)

context['form_file'] = FileForm

return context

def form_valid(self, form):

arr_obj_tags=[]

all_tags = self.request.POST['tag'].split(', ' or ',')

for elem in all_tags:

max_num_tags = Tags.objects.all().order_by('-number')[0]

obj_tag = Tags(number = max_num_tags.number+1, name = elem)

obj_tag.save()

arr_obj_tags.append(obj_tag)

instance = form.save(commit=False)

blogs = Blog.objects.filter(author=self.request.user.username).order_by('-number')

if blogs.count() > 0:

instance.number = blogs[0].number+1

else:

instance.number = 1

instance.author = self.request.user.username

instance.date_of_publication = datetime.datetime.now()

path = default_storage.save('uploads/mar.jpg', ContentFile(self.request.FILES['thumbnail'].read()))

obj_image = FileObject(path).version_generate('admin_list_blog')

instance.image = obj_image

instance.save()

for elem in arr_obj_tags:

instance.tags.add(elem)

return redirect(self.get_absolute_url())

def get_absolute_url(self):

return reverse("profile", kwargs={})

class ProfileSettingView(TemplateView, View):

template_name = "user_profile/user_settings.html"

http_method_names = ['get', 'post']

def post(self, request, *args, **kwargs):

object = Profile.objects.get(user = request.user)

form = ProfileForm(request.POST, request.FILES, instance = object) # A form bound to the POST data

if form.is_valid():

form.save(commit = False)

path = default_storage.save('uploads/mar.jpg', ContentFile(request.FILES['image'].read()))

obj_image = FileObject(path).version_generate('profile_photo')

object.thumbnail = obj_image

object.save()

# Новый пароль и Подверждение пароля

new_password = request.POST['new_password']

confirm_password = request.POST['confirm_password']

# Выбираем обьект User для изменеия пароля

index = User.objects.get(pk = request.user.id)

index.set_password(new_password)

if new_password == '':

mes = 'Поле (новый пароль) пусто:'

else:

if confirm_password == new_password:

mes = 'Пароли совпадают!'

index.save()

else:

mes = 'Пароли не совпадают!'

form.save()

return redirect(reverse("profile", kwargs={}))

def get_context_data(self, **kwargs):

context = super(ProfileSettingView, self).get_context_data(**kwargs)

if self.request.user.is_authenticated() and Profile.objects.get(pk=self.request.user.id).party==True:

object = Profile.objects.get(user = self.request.user)

context['object'] = object

user_id = self.request.user

context['form'] = ProfileForm(instance = object)

if not Profile.objects.filter(pk = user_id.id):

person = Profile()

person.pk = user_id.id

person.user = user_id

person.save()

return context

else:

template_name = "profile/error.html"

context['ErrorText'] = u"Вы не авторизированны"

return context

@csrf_exempt

def search_person(request):

ERROR = None

if request.user.is_authenticated() and Profile.objects.get(pk=request.user.id).party==True:

class ContactForm(forms.Form):

last_name = forms.CharField(max_length=150, required=False)

first_name = forms.CharField(max_length=150, required=False)

user = forms.CharField(max_length=150, required=False)

midlle_name = forms.CharField(max_length=150, required=False)

current_user = request.user.get_profile

if request.method == 'POST':

form = ContactForm(request.POST)

params = []

if form.is_valid():

last_name = form.cleaned_data['last_name']

first_name = form.cleaned_data['first_name']

midlle_name = form.cleaned_data['midlle_name']

user = form.cleaned_data['user']

kargs = {'last_name__icontains':last_name}

params.append(apply(Q, (), kargs))

params.append(Q(first_name__icontains = first_name))

params.append(Q(midlle_name__icontains = midlle_name))

params.append(Q(user__username__icontains = user))

search_result = Profile.objects.filter(*params)

context = {'form': form, 'search_result': search_result, 'User':current_user}

else:

form = ContactForm()

context = {'form':form, 'User':current_user}

return render_to_response('friends/search_person.html', context, context_instance=RequestContext(request))

else:

return render_to_response("friends/error.html", {'ErrorText': u"Вы не авторизированны"})

def add_person(request, id):

obj = Profile.objects.get(user = id)

user = Profile.objects.get(user = request.user.get_profile)

user.friends.add(obj)

obj.friend_requests.add(user)

return HttpResponseRedirect('/profile/friends/all/')

def del_person(request, id):

obj = Profile.objects.get(user = id)

user = Profile.objects.get(user = request.user.get_profile)

user.friends.remove(obj)

return HttpResponseRedirect('/profile/friends/all/')

def accept_friend(request, objid):

obj = Profile.objects.get(user= request.user.get_profile)

obj_friend = Profile.objects.get(user = objid)

obj.friends.add(obj_friend)

obj.friend_requests.remove(obj_friend)

return HttpResponseRedirect('/profile/friends/all/')

def reject_friend(request, objid):

obj = Profile.objects.get(user = request.user.get_profile)

obj_friend = Profile.objects.get(user = objid)

obj.friend_requests.remove(obj_friend)

return HttpResponseRedirect('/profile/friends/all/')

@csrf_exempt

def my_friends(request):

ERROR = None

if request.user.is_authenticated() and Profile.objects.get(pk=request.user.id).party==True:

friends = User.objects.all()

if request.method == 'POST':

pass

context = {'friends': friends}

return render_to_response('friends/choice_friend.html', context, context_instance=RequestContext(request))

else:

# если не залогинен

# хорошо бы сделать из этой проверки декоратор, чтоб всюду её не тоскать за собой

return render_to_response("friends/error.html", {'ErrorText': u"Вы не авторизированны"})

Приложение BLOG:

Файл urls.py для приложения blog:

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

from .views import BlogList, ArticleMonthArchiveView, BlogDetail, FilterTagsView, BlogSearchView

urlpatterns = patterns('',

url(r'^list/$', BlogList.as_view(), name='blog_list'),

url(r'^(?P<year>\d{4})/(?P<month>\d+)/$',

ArticleMonthArchiveView.as_view(month_format='%m'),

name="archive_month_numeric"),

url(r'^detail/(?P<pk>\d+)/$', BlogDetail.as_view(), name='blog_detail'),

url(r'^filter/tag/(?P<pk>\d+)/', FilterTagsView.as_view(),name='filter_tags'),

url(r'^search/$', BlogSearchView.as_view(), name='blog_search'),

)

Файл models.py для приложения blog:

# -*- coding: utf-8 -*-

from django.db import models

from django.contrib.auth.models import User

from filebrowser.fields import FileBrowseField

from model_utils.fields import SplitField

from model_utils.models import TimeStampedModel

import datetime

from django.db.models import permalink

from django.core.urlresolvers import reverse

class Tags(models.Model):

number = models.IntegerField(u'Порядковый номер', blank=True, null=True)

name = models.CharField(u'Название тега', max_length=500)

def __unicode__(self):

return u'%s' % (self.name)

class Meta:

verbose_name = u"Тег"

verbose_name_plural = u"Теги"

class Blog(models.Model):

number = models.IntegerField(u"Порядкоый номер", blank=True, null=True)

zagol = models.CharField(u"Заголовок", max_length=64, blank=True, null=True)

author = models.CharField(u"Автор", max_length=200, blank=True)

image = FileBrowseField(u"Фото", max_length=200, directory='images/blog/', format='image', null=True, blank=True)

date_of_publication = models.DateTimeField(verbose_name=u'Дата публикации новости',blank=True, null=True, default = datetime.datetime.now)

text = SplitField(u'Текст', blank=True)

tags = models.ManyToManyField(Tags, verbose_name=u'Теги', blank=True)

def __unicode__(self):

return u'%s' % (self.zagol,)

class Meta:

verbose_name = u"Блог"

verbose_name_plural = u"Блог"

class Comment(models.Model):

blog=models.ForeignKey(Blog, verbose_name=u'От какого блога', related_name='link_blog', blank=True,null=True)

author_name=models.CharField(u"Автор", max_length=120, blank=True)

text=models.TextField(u'Комментарий',blank=True)

pub_date=models.DateTimeField(u'Дата публикации', default = datetime.datetime.now, blank=True)

admin_comment=models.BooleanField(u'Допущена администратором', default=False, blank=True)

def __unicode__(self):

return self.author_name

def count_comment(self):

return Comment.objects.filter(article=self.article).count()

class Meta:

verbose_name = u"Комментарий"

verbose_name_plural = u"Комментарии"

ordering=[ 'pub_date', ]

Файл admin.py для приложения blog:

# -*- encoding: utf-8 -*-

from django.contrib import admin

from .models import Blog, Comment, Tags

class BlogAdmin(admin.ModelAdmin):

list_display = ('number', 'zagol',)

list_display_links = ('number', 'zagol',)

list_filter = ()

readonly_fields = ()

ordering = ('number',)

date_hierarchy='date_of_publication'

class TagsAdmin(admin.ModelAdmin):

list_display = ('number', 'name',)

list_display_links = ('number', 'name',)

list_filter = ()

readonly_fields = ()

ordering = ('name',)

class CommentAdmin(admin.ModelAdmin):

list_display=('pub_date', 'author_name', )

search_fields=('text', )

list_filter=('author_name', )

date_hierarchy='pub_date'

admin.site.register(Blog, BlogAdmin)

admin.site.register(Tags, TagsAdmin)

admin.site.register(Comment, CommentAdmin)

Файл forms.py для приложения blog:

# -*- coding: utf-8 -*-

from django import forms

from registration.forms import RegistrationFormUniqueEmail

from django.core.mail import send_mail

from .models import Blog

class RegistrationFormProfile(RegistrationFormUniqueEmail):

requisites = forms.CharField(label = 'Работа')

class BlogForm(forms.Form):

name = forms.CharField(max_length=150)

email = forms.EmailField()

message = forms.CharField(widget=forms.Textarea)

def send_email(self, subject, message, from_email, recipient_list=['viktori2000@qip.ru'], fail_silently=False):

return send_mail(subject, message, from_email, recipient_list, fail_silently)

Файл views.py для приложения blog:

# -*- coding: utf-8 -*-

from django.views.generic import ListView, DetailView, TemplateView

from .models import Blog, Tags, Comment

from django.contrib.auth.models import User

from django.views.generic.edit import FormView, CreateView, UpdateView

from django.forms import ModelForm

from django import forms

from django.db.models import Q

from django.contrib.auth.models import User

import datetime

from .forms import BlogForm

from django.views.generic.edit import CreateView

from django.views.generic.dates import MonthArchiveView

from profile.models import Profile

from django.shortcuts import redirect

from django.core.urlresolvers import reverse

class CreateNews(CreateView):

model = Blog

fields = ['number','zagol','author','image','date_of_publication','text','tags']

def get_context_data(self, **kwargs):

if self.request.user.is_authenticated() and Profile.objects.get(pk=self.request.user.id).party==True:

context = super(CreateNews, self).get_context_data(**kwargs)

context['object'] = Profile.objects.get(pk = self.request.user.id)

return context

class BlogList(ListView):

model = Blog

context_object_name = "blog"

def get_context_data(self, **kwargs):

context = super(BlogList, self).get_context_data(**kwargs)

if self.request.user.is_authenticated() and Profile.objects.get(pk=self.request.user.id).party==True:

date_obj = []

for obj in Blog.objects.dates('created', 'month'):

date_obj.append(obj)

context['archives'] = date_obj

context['active_main_menu']='main_blog'

else:

self.template_name = "profile/error.html"

context['ErrorText'] = u"Вы не авторизированны"

return context

class FilterTagsView(DetailView):

model = Blog

template_name = "blog/blog_list.html"

queryset = Blog.objects.all()

def get_context_data(self, **kwargs):

context = super(FilterTagsView, self).get_context_data(**kwargs)

if self.request.user.is_authenticated() and Profile.objects.get(pk=self.request.user.id).party==True:

date_obj = []

for obj in Blog.objects.dates('created', 'month'):

date_obj.append(obj)

object = super(FilterTagsView, self).get_object()

context['blog'] = Blog.objects.filter(tags__pk = object.pk)

context['archives'] = date_obj

context['active_main_menu']='main_blog'

return context

class BlogSearchView(ListView):

template_name = 'blog/blog_list.html'

model = Blog

def get_context_data(self, **kwargs):

context = super(BlogSearchView, self).get_context_data(**kwargs)

if self.request.user.is_authenticated() and Profile.objects.get(pk=self.request.user.id).party==True:

date_obj = []

for obj in Blog.objects.dates('created', 'month'):

date_obj.append(obj)

context['archives'] = date_obj

context['active_main_menu']='main_blog'

search_word = self.request.GET['search_box'].lower()

arr = []

arr.append(Blog.objects.filter(Q(zagol__icontains = search_word)))

context['blog']=Blog.objects.filter(Q(zagol__icontains = search_word)|Q(author__icontains = search_word)|Q(text__icontains = search_word))

return context

class ArticleMonthArchiveView(MonthArchiveView):

queryset = Blog.objects.all()

date_field = "created"

make_object_list = True

allow_future = True

def get_context_data(self, **kwargs):

if self.request.user.is_authenticated() and Profile.objects.get(pk=self.request.user.id).party==True:

context = super(ArticleMonthArchiveView, self).get_context_data(**kwargs)

date_obj = []

for obj in Blog.objects.dates('created', 'month'):

date_obj.append(obj)

context['archives'] = date_obj

context['active_main_menu']='main_blog'

return context

class BlogDetail(CreateView):

template_name = "blog/blog_detail.html"

model = Comment

exclude = ['article', 'author_name', 'pub_date', 'admin_comment']

def get_context_data(self, **kwargs):

if self.request.user.is_authenticated() and Profile.objects.get(pk=self.request.user.id).party==True:

context = super(BlogDetail, self).get_context_data(**kwargs)

date_obj = []

for obj in Blog.objects.dates('created', 'month'):

date_obj.append(obj)

context['blog'] = Blog.objects.get(pk = self.kwargs['pk'])

context['archives'] = date_obj

context['active_main_menu'] = 'main_blog'

context['comments'] = Comment.objects.filter(article = context['blog'], admin_comment=True)

return context

def form_valid(self, form):

instance = form.save(commit=False)

instance.article = Blog.objects.get(pk=self.kwargs['pk'])

instance.author_name = self.request.user.username

instance.pub_date = datetime.datetime.now()

instance.save()

return redirect(self.get_absolute_url())

def get_absolute_url(self):

return reverse("blog_detail", kwargs={"pk": self.kwargs['pk']})

Приложение MESSAGE:

Файл urls.py для приложения message:

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

urlpatterns = patterns('',

url(r'^$', 'messages.views.all_message'),

url(r'^sendmessage/(?P<id>[^/]+)/$', 'messages.views.send_message'),

)

Файл admin.py для приложения message:

from django.contrib import admin

from .models import Message, Chat

class MessageAdmin(admin.ModelAdmin):

list_display = ('recipient', 'sender', 'date', 'title')

ordering = ('recipient', 'sender')

list_filter = ('recipient', 'sender')

admin.site.register(Message,MessageAdmin)

class ChatAdmin(admin.ModelAdmin):

list_display = ('person1', 'person2')

ordering = ('person1', 'person2')

list_filter = ('person1', 'person2')

admin.site.register(Chat,ChatAdmin)

Файл views.py для приложения message:

# -*- coding: utf-8 -*-

from .models import Message, Chat

from profile.models import Profile

from django.views.decorators.csrf import csrf_exempt

from django.template import RequestContext # нужно чтобы передавать реквест в контекст

from django.forms import ModelForm

from django.http import HttpResponse, HttpResponseRedirect

from django import forms

from django.db.models import Q

from django.shortcuts import render_to_response, redirect

from django.contrib.auth.models import User

import datetime

import time

@csrf_exempt

def all_message(request):

ERROR = None

if request.user.is_authenticated() and Profile.objects.get(pk=request.user.id).party==True:

i_am = User.objects.get(pk = request.user.id)

temp4 = Q(person2 = i_am)

temp5 = Q(person1 = i_am)

all_friend = Chat.objects.filter(temp4 | temp5)

i_am = User.objects.get(pk = request.user.id)

messages = Message.objects.filter(recipient = i_am).filter(reader = False).count()

image = all_friend

context = {'all_friend':all_friend, 'messages': messages, 'image':image}

return render_to_response('friends/all_message.html', context, context_instance=RequestContext(request))

else:

return render_to_response("friends/error.html", {'ErrorText': u"Вы не авторизированны"})

@csrf_exempt

def send_message(request, id):

class MessageForm(forms.Form):

title = forms.CharField(max_length=350, required=False)

message = forms.CharField(max_length=350, required=False, widget=forms.Textarea)

friend = User.objects.get(pk = id)

i_am = User.objects.get(pk = request.user.id)

temp1 = Q(recipient = friend) & Q(sender = i_am)

temp2 = Q(recipient = i_am) & Q(sender = friend)

temp3 = temp1 | temp2

temp4 = Q(person2 = i_am) & Q(person1 = friend)

temp5 = Q(person1 = i_am) & Q(person2 = friend)

if len(Chat.objects.filter(temp4 | temp5)) == 0:

chat = Chat()

chat.person1 = i_am

chat.person2 = friend

chat.save()

else:

pass

if request.method == 'POST':

all_message = Message.objects.filter(temp3).order_by('date')

chat_obj = Chat.objects.get(temp4 | temp5)

form = MessageForm(request.POST)

if form.is_valid():

title = form.cleaned_data['title']

message = form.cleaned_data['message']

send_message = Message()

send_message.recipient = friend

send_message.sender = i_am

send_message.date = datetime.datetime.now()

send_message.title = title

send_message.message = message

send_message.reader = False

send_message.save()

chat_obj.messages.add(send_message)

chat_obj.save()

return redirect('/message/sendmessage/'+ str(id) + '/')

else:

all_message = Message.objects.filter(temp3).order_by('date')[0::1]

temp4 = Q(person2 = i_am) & Q(person1 = friend)

temp5 = Q(person1 = i_am) & Q(person2 = friend)

person_type = Chat.objects.filter(temp4 | temp5)

form = MessageForm()

send = Message.objects.filter(temp2)

for elem in send:

if not elem.reader:

elem.reader=True

elem.save()

context = {'form':form, 'friend': friend, 'all_message': all_message}

return render_to_response('friends/send_message.html', context, context_instance=RequestContext(request))


ПРИЛОЖЕНИЕ В

ККМОО «Молодежная лига развития национальных культур Кубани»

350000, г. Краснодар, ул. Красноармейская 53.

ИНН: 2310023918

КПП: 231001001

Счет № 407038108000000000019

Банк: АО «Юг-Инвест банк», г. Краснодар

БИК 040349966

Счет №: 30101810600000000966

Код по ОКОНХ 98400

Код по ОКПО 39744165

Приложение № 1 к договору № ________ от «__» ______ 2012 г.

Техническое задание для создания программной и визуальной части сайта:

1.Разработка дизайна для графической части сайта.

2.Разработка логотипа в векторном формате.

3.Создание программного обеспечения на языке программирования Python, в среде Django.

4.Создание социального раздела для общения между участниками «Клубов интернациональной дружбы».

5.Размещение файлов в сети интернет для отображения текстовой и графической информации в сети интернет, с возможностью вывода информации из базы данных и редактирования содержимого базы данных

6.Создание раздела для вновь созданных и создаваемых «Клубов интернациональной дружбы», в который можно будет добавлять текстовую, графическую и видео информацию, в том числе на английском языке.

Правообладатель __________________

Приобретатель _______________

РАЗРАБОТКА АРХИТЕКТУРЫ ЗАКРЫТОЙ КОРПОРАТИВНОЙ СЕТИ С ИСПОЛЬЗОВАНИЕМ ФРЕЙМВОРКА DJANGO