
Доброго времени суток, Хабр!
Недавно разрабатывала сайт на python/django и нужна была возможность использования API Вконтакте. А именно:
• Постинг статей с сайта на страницу во Вконтакте, а также в выбранные группы (в которых состоял администратор);
• Возможность прикрепления документов и картинок к записям;
• Получение списка групп и записей с помощью обновляющегося скрипта и загрузка всего этого в админку django.
Собственно, для администратора управление этим функционалом осуществляется через админку.
Расскажу по шагам реализацию этого функционала.
На первом этапе администратору нужно создать своё приложение во «Вконтакте», а также получить токен для работы с API. Для получения токена я использую модуль VKAppAuth (ссылка на GitHub, там же пример использования модуля).
Настройки для получения сохраняю в отдельном файле и подключаю его в models.py. В models.py добавляю поля для «Вконтакте» в модель статьи:
photo_vk = models.ImageField(upload_to=photo_vk_path, verbose_name=u'Прикрепить фото для Вконтакте', max_length = 1000, blank=True) file_vk = models.FileField(upload_to=files_vk_path, verbose_name=u'Прикрепить документ для Вконтакте', max_length = 1000, blank=True) wall_user_vk = models.BooleanField(verbose_name=u'Отправить на стену пользователя Вконтакте', default=False) group_vk = models.ManyToManyField(Vk_groups, verbose_name=u'Отправить в следующие группы Вконтакте', blank=True) group_stat = models.BooleanField(verbose_name=u'Публиковать запись от имени группы', default=False)
Поле group_vk отображает все группы «Вконтакте» из таблицы Vk_groups. Код класса Vk_groups в models.py:
class Vk_groups(models.Model): title = models.CharField(max_length=1000, verbose_name=u'Название группы') gid = models.CharField(max_length=1000, verbose_name=u'ID группы') is_closed = models.BooleanField(verbose_name=u'Закрытая группа', default=False) is_admin = models.BooleanField(verbose_name=u'Пользователь является администратором', default=False) def __str__(self): return self.title.encode('utf8') class Meta: verbose_name = "Группа Вконтакте" verbose_name_plural = "Группы Вконтакте"
Также создана модель для записей «Вконтакте». Они будут загружаться с помощью автоматически обновляемого на сервере скрипта, таким образом, в админке будут актуальные ��аписи со страницы администратора и из групп, в которых он состоит.
Поля модели:
class Vk_posts(models.Model): group = models.CharField(max_length=1000, verbose_name=u'Страница/группа', blank=True) text = HTMLField(verbose_name=u'Текст записи', blank=True) date = models.DateTimeField(verbose_name=u'Дата публикации', blank=True)
Для модели статьи я переопределила метод save(), чтобы при сохранении какой-либо статьи происходило обращение к API Вконтакте и производилась отправка записи во «Вконтакте», если поставлены соответствующие галочки.
def save(self, *args, **kwargs): use_vk(self) model = super(Page, self).save(*args, **kwargs)
Перед сохранением вызывается функция use_vk, в которой происходит обращение к API.
#пути для фото и документов photo_vk_path = 'photo_vk' files_vk_path = 'files_vk' def use_vk(self): #составление записи msg = self.title + '\n' + self.text msg = re.sub('<.*?>','',msg) #флаг для определения, нужно ли отправлять запись post_vk = 0 #получение списка групп groups = [g for g in self.group_vk.all()] if len(groups) or self.wall_user_vk: post_vk = 1 if post_vk: attachments = [] #для прикрепления фото if self.photo_vk: server = vk.photos.getWallUploadServer(uid = my_id) path = MEDIA_ROOT + photo_vk_path + '/' + re.split('/', self.photo_vk.url)[-1] r = requests.post(server['upload_url'], files={'photo': open(path,"rb")}) params = {'server': r.json()['server'], 'photo': r.json()['photo'], 'hash': r.json()['hash']} wallphoto = vk.photos.saveWallPhoto(**params) attachments.append(wallphoto[0]['id']) #для прикрепления документа if self.file_vk: server = vk.docs.getWallUploadServer() path = MEDIA_ROOT + files_vk_path + '/' + re.split('/', self.file_vk.url)[-1] r = requests.post(server['upload_url'], files={'file': open(path,"rb")}) params = {'file': r.json()['file']} doc = vk.docs.save(**params) attachments.append('doc' + str(my_id) + '_' + str(doc[0]['did'])) params = {'attachments': ','.join(attachments), 'message': msg} #для отправки записи на стену администратора if self.wall_user_vk: params['owner_id'] = my_id vk.wall.post(**params) #для отправки записи в выбранные группы if len(groups): if self.group_stat: params['from_group'] = 1 for g in groups: params['owner_id'] = g.gid vk.wall.post(**params)
Нужно отметить, что загрузчик для фото и документов выдавал некорректный путь к файлам в папках по вызову его метода url (не исключаю, что это именно у меня), поэтому я сама составляла путь до картинок и документов (переменная path).
Подробнее об этапах загрузки фото или документа к записи:
a) Отправка запроса на получение адреса сервера Вконтакте, куда можно загрузить фото или документ;
b) Получение адреса сервера Вконтакте;
c) Формирование post-запроса по адресу сервера с загрузкой на него документа или фото;
d) При успешной загрузке получение ответа с идентификатором загруженного документа или фото;
e) Формирование списка атрибутов для размещения записи во Вконтакте, в числе которых идентификатор фото или документа.
После прикрепления фото/документа используется завершающий метод API vk.wall.post(**params), отправляющий запись на стену администратора/группы запись.
Для получения списка групп и сохранения новых записей из групп и со стены администратора используется скрипт, который автоматически обновляется на сервере в заданное время. Данный скрипт получает настройки django, импортирует к себе необходимые модели и файл получения токена, а затем через API получает группы администратора, записи со стены/из групп и обновляет таблицы базы данных:
import sys import time sys.path = ['C:/site/umc/'] + sys.path from django.core.management import setup_environ import settings setup_environ(settings) from www.models import Vk_groups, Vk_posts from umc.vk_response import * count_posts = 15 def get_posts(owner_id, g_name): """Функция получения записей со стены администратора и групп и добавление новых записей в таблицу Vk_posts""" params = {'owner_id': owner_id, 'count': count_posts} answer = vk.wall.get(**params) for i in range(count_posts): params = { 'group': g_name, 'text': answer[i+1]['text'], 'date': time.strftime("%Y-%m-%d %H:%M:%S+06:00", time.localtime(answer[i+1]['date'])) } try: Vk_posts.objects.get_or_create(**params) except: params['text'] = u'Невозможно отобразить текст статьи' Vk_posts.objects.get_or_create(**params) #добавление новых групп в таблицу Vk_groups params = {'owner_id': my_id, 'extended': 1, 'filter': 'events, groups, admin'} answer = vk.groups.get(**params) for i in range(answer[0]): Vk_groups.objects.get_or_create(title = answer[i+1]['name'], gid = '-' + str(answer[i+1]['gid']), is_admin = answer[i+1]['is_admin'], is_closed = answer[i+1]['is_closed']) #добавление новых записей из групп в таблицу Vk_posts groups = Vk_groups.objects.all() for g in groups: get_posts(g.gid, g.title) #добавление новых записей со стены пользователя в таблицу Vk_posts user = vk.users.get(uid = my_id) get_posts(my_id, user[0]['first_name']+ ' ' + user[0]['last_name'])
Собственно, теперь можно попробовать отправить записи из админки на стену или любую группу (если права доступа позволяют размещать записи на стене группы), и проверить работу.
Надеюсь, статья была полезной.
Ссылка на проект: github.com/julia-bikova/DjangoVkPosting
Всем приятной работы с Django!
