Пример #1
0
class Targeting(VkontakteAdsMixin, VkontakteModel):

    remote_pk_local_field = 'ad'

    ad = models.OneToOneField(Ad, verbose_name=u'Объявление', primary_key=True, related_name='targeting')

    campaign = models.ForeignKey(Campaign, verbose_name=u'Кампания')

    sex = models.PositiveSmallIntegerField(u'Пол', choices=TARGETING_SEX_CHOICES, default=0)
    age_from = models.PositiveSmallIntegerField(u'Возраст с', default=0)
    age_to = models.PositiveSmallIntegerField(u'Возраст до', default=0)
    birthday = models.CommaSeparatedIntegerField(u'День рождения', max_length=100, choices=[(
        '', u'Неважно'), (1, u'Сегодня'), (2, u'Завтра'), (3, u'Сегодня или завтра')], blank=True)

    country = models.PositiveIntegerField(u'Страна', default=0)
    cities = models.CommaSeparatedIntegerField(u'Города', max_length=500, blank=True)
    cities_not = models.CommaSeparatedIntegerField(u'Города исключить', max_length=500, blank=True)
    statuses = models.CommaSeparatedIntegerField(u'Семейное положение', max_length=500, blank=True)

    group_types = models.CommaSeparatedIntegerField(u'Категории групп', max_length=500, blank=True)
    groups = models.CommaSeparatedIntegerField(u'Группы', max_length=500, blank=True)
    religions = models.CommaSeparatedIntegerField(u'Религиозные взгляды', max_length=500, blank=True)
    interests = fields.CommaSeparatedCharField(
        u'Интересы', max_length=500, blank=True, help_text=u'Последовательность слов, разделенных запятой.')
    travellers = models.BooleanField(u'Путешественники', default=False)

    # Расширенная география
    districts = models.CommaSeparatedIntegerField(u'Районы', max_length=500, blank=True)
    stations = models.CommaSeparatedIntegerField(u'Станции метро', max_length=500, blank=True)
    streets = models.CommaSeparatedIntegerField(u'Улицы', max_length=500, blank=True)

    # Образование и работа
    schools = models.CommaSeparatedIntegerField(u'Учебные заведения', max_length=500, blank=True)
    positions = models.CommaSeparatedIntegerField(u'Должности', max_length=500, blank=True)
    school_from = models.PositiveSmallIntegerField(u'Окончание школы после', default=0)
    school_to = models.PositiveSmallIntegerField(u'Окончание школы дое', default=0)
    uni_from = models.PositiveSmallIntegerField(u'Окончание ВУЗа после', default=0)
    uni_to = models.PositiveSmallIntegerField(u'Окончание ВУЗа до', default=0)

    # Дополнительные параметры
    browsers = models.CommaSeparatedIntegerField(u'Браузеры и устройства', max_length=500, blank=True)
    tags = fields.CommaSeparatedCharField(
        u'Ключевые слова', max_length=200, blank=True, help_text=u'Набор строк, разделенных запятой.')

    # not exist in API docs
    approved = models.BooleanField(u'Одобрено', default=False)
    count = models.PositiveIntegerField(null=True, blank=True, help_text=u'')
    operators = models.CommaSeparatedIntegerField(u'Операторы', max_length=500, blank=True, help_text=u'')

    remote = VkontakteManager(
        remote_pk=('ad_id',),
        methods = {'get': 'getAdsTargeting'}
    )

    class Meta:
        verbose_name = u'Таргетинг объявления Вконтакте'
        verbose_name_plural = u'Таргетинг объявления Вконтакте'
Пример #2
0
class Image(VkontakteAdsMixin, VkontakteModel):

    '''
    Model of vkontakte image
    '''

    def _get_upload_to(self, filename=None):
        return 'images/%f.jpg' % time.time()

#    ad = models.OneToOneField(Ad, related_name='image')
    ad = models.OneToOneField(Ad, verbose_name=u'Объявление', primary_key=True, related_name='image')

    hash = models.CharField(
        max_length=50, blank=True, help_text=u'Значение, полученное в результате загрузки фотографии на сервер')
    photo_hash = models.CharField(
        max_length=50, blank=True, help_text=u'Значение, полученное в результате загрузки фотографии на сервер')
    photo = models.CharField(
        max_length=200, blank=True, help_text=u'Значение, полученное в результате загрузки фотографии на сервер')
    server = models.PositiveIntegerField(
        blank=True, null=True, help_text=u'Значение, полученное в результате загрузки фотографии на сервер')
    size = models.CharField(max_length=1, blank=True)
    aid = models.PositiveIntegerField(null=True, blank=True)
    width = models.PositiveIntegerField(null=True, blank=True)
    height = models.PositiveIntegerField(null=True, blank=True)

    file = models.ImageField(u'Картинка', upload_to=_get_upload_to, blank=True)

    # not in API
    post_url = models.CharField(max_length=200, blank=True, help_text=u'Адрес загрузки картинки на сервер')

    remote = VkontakteManager(methods={'get_post_url': 'getUploadURL'})

    class Meta:
        verbose_name = u'Картинка объявления Вконтакте'
        verbose_name_plural = u'Картинка объявления Вконтакте'

    def get_post_url(self):
        self.post_url = Image.remote.api_call(method='get_post_url', cost_type=self.ad.cost_type)
        return self.post_url

    def upload(self):
        if self.file:
            # save file to disk
            if not self.file._committed:
                self.file.field.pre_save(self, True)
            url = self.post_url or self.get_post_url()
            files = {
                'file': (self.file.name.split('/')[-1], open(os.path.join(settings.MEDIA_ROOT, self.file.name), 'rb'))}

            response = requests.post(url, files=files)
            response = json.loads(response.content)
            if 'errcode' in response:
                raise VkontakteContentError("Error with code %d while uploading image %s" %
                                            (response['errcode'], self.file))
            self.parse(response)
Пример #3
0
class Budget(VkontakteAdsModel):

    account = models.ForeignKey(
        Account, primary_key=True, help_text=u'Номер рекламного кабинета, бюджет которого запрашивается.')
    budget = models.DecimalField(
        max_digits=10, decimal_places=2, help_text=u'Оставшийся бюджет в указанном рекламном кабинете.')

    remote = VkontakteManager(remote_pk=('account',), methods={'get': 'getBudget'})

    class Meta:
        verbose_name = u'Бюджет личного кабинета Вконтакте'
        verbose_name_plural = u'Бюджеты личных кабинетов Вконтакте'
Пример #4
0
class Client(VkontakteAdsIDContentModel):

    fields_required_for_update = ['client_id']

    account = models.ForeignKey(Account, verbose_name=u'Аккаунт', related_name='clients',
                                help_text=u'Номер рекламного кабинета, в котором должны создаваться кампании.')

    name = models.CharField(u'Название', max_length=60)
    day_limit = models.IntegerField(u'Дневной лимит', null=True, help_text=u'Целое число рублей.')
    all_limit = models.IntegerField(u'Общий лимит', null=True, help_text=u'Целое число рублей.')

    statistics = generic.GenericRelation('Statistic', verbose_name=u'Статистика')

    objects = VkontakteCRUDManager()
    remote = VkontakteManager(
        remote_pk=('remote_id',),
        methods = {
        'get': 'getClients',
        'create': 'createClients',
        'update': 'updateClients',
        'delete': 'deleteClients',
    })

    class Meta:
        verbose_name = u'Рекламный клиент Вконтакте'
        verbose_name_plural = u'Рекламные клиенты Вконтакте'

    def __str__(self):
        return self.name

    def fields_for_update(self):
        fields = self.fields_for_create()
        fields.update(client_id=self.remote_id)
        return fields

    def fields_for_create(self):
        fields = dict(name=self.name)
        if self.day_limit:
            fields.update(day_limit=self.day_limit)
        if self.all_limit:
            fields.update(all_limit=self.all_limit)
        return fields

    def fetch_campaigns(self, ids=None):
        '''
        Get all campaigns of account
        '''
        return super(Client, self).fetch_campaigns(account=self.account, client=self, ids=ids)
Пример #5
0
class Account(VkontakteAdsIDModel):

    remote_pk_field = 'account_id'

    name = models.CharField(u'Название', blank=True, max_length=100)

    account_status = models.BooleanField(default=False, help_text=u'Cтатус рекламного кабинета. активен / неактивен.')
    access_role = models.CharField(
        choices=ACCOUNT_ACCESS_ROLE_CHOICES, max_length=10, help_text=u'права пользователя в рекламном кабинете.')

    remote = VkontakteManager(remote_pk=('remote_id',), methods={
        'get': 'getAccounts'
    })

    statistics = generic.GenericRelation('Statistic', verbose_name=u'Статистика')

    class Meta:
        verbose_name = u'Рекламный кабинет Вконтакте'
        verbose_name_plural = u'Рекламные кабинеты Вконтакте'

    def __str__(self):
        return self.name or 'Account #%s' % self.remote_id

    def _substitute(self, old_instance):
        super(Account, self)._substitute(old_instance)
        self.name = old_instance.name

    def fetch_clients(self):
        '''
        Get all clients of account
        '''
        try:
            instances = Client.remote.get(account_id=self.remote_id)
        except VKError, e:
            if e.code == 100:
                return []
            else:
                raise e
        instances_saved = []

        for instance in instances:
            instance.account = self
            instance.fetched = datetime.now()
            instance._commit_remote = False
            instances_saved += [Client.remote.get_or_create_from_instance(instance)]

        return instances_saved
Пример #6
0
class Layout(VkontakteAdsMixin, VkontakteModel):

    remote_pk_local_field = 'ad'

    ad = models.OneToOneField(Ad, verbose_name=u'Объявление', primary_key=True, related_name='layout')

    campaign = models.ForeignKey(Campaign, verbose_name=u'Кампания', help_text=u'Кампания объявления.')
    # change max_length=50, because found string with len=27
    title = fields.CharRangeLengthField(
        u'Заголовок', min_length=3, max_length=50, help_text=u'Заголовок объявления - строка длиной от 3 до 25 символов')
    # change max_length=100, because found string with len=65
    description = fields.CharRangeLengthField(
        u'Описание', min_length=3, max_length=100, help_text=u'Описание объявления - строка длиной от 3 до 60 символов - обязательно при выборе типа "оплата за переходы"')
    link_url = models.URLField(
        u'Ссылка', max_length=500, help_text=u'Ссылка на рекламируемый объект в формате http://yoursite.com или ВКонтакте API. Если в ссылке содержатся строки "{ad_id}" или "{campaign_id}", то они заменяются соответственно на ID объявления и ID кампании в момент перехода пользователя по такой ссылке.')
    link_domain = models.CharField(
        u'Домен', blank=True, max_length=50, help_text=u'Домен рекламируемого объекта в формате yoursite.com')

    # not exist in API docs
    preview_link = models.CharField(u'Превью', blank=True, max_length=200)

    # preview content
    preview = models.TextField()

    remote = VkontakteManager(
        remote_pk=('ad_id',),
        methods = {'get': 'getAdsLayout'}
    )

    class Meta:
        verbose_name = u'Контент объявления Вконтакте'
        verbose_name_plural = u'Контент объявления Вконтакте'

    def save(self, *args, **kwargs):
        self.set_preview()
        super(Layout, self).save(*args, **kwargs)

    def set_preview(self):
        if self.preview_link:
            response = requests.get(self.preview_link)
            # decode, becouse otherwise test would crash
            self.preview = response.content.decode('windows-1251', 'ignore')
Пример #7
0
class AdAbstract(VkontakteAdsIDContentModel):

    '''
    Abstract model of vkontakte ads with all fields for some special needs
    '''
    account = models.ForeignKey(Account, verbose_name=u'Аккаунт', related_name='ads',
                                help_text=u'Номер рекламного кабинета, в котором создается объявление.')
    campaign = ChainedForeignKey(Campaign, verbose_name=u'Кампания', chained_field="account", chained_model_field="account",
                                 show_all=False, auto_choose=True, related_name='ads', help_text=u'Кампания, в которой будет создаваться объявление.')

    # max_lengh=100 потому что иногда рекламы созданные через интерфейс ВК имеют названия длиннее
    name = fields.CharRangeLengthField(u'Название', min_length=3, max_length=100,
                                       help_text=u'Название объявления (для использования в рекламном кабинете) - строка длиной от 3 до 60 символов.')
    all_limit = models.PositiveIntegerField(u'Общий лимит', null=True, help_text=u'Целое число рублей.')
    cost_type = models.PositiveSmallIntegerField(u'Тип оплаты', choices=(
        (0, u'оплата за переходы'), (1, u'оплата за показы')), help_text=u'Флаг, описывающий тип оплаты')
    cpc = fields.IntegerRangeField(u'Цена за переход', min_value=50, null=True, blank=True,
                                   help_text=u'Если оплата за переходы, цена за переход в копейках, минимум 50 коп.')
    cpm = models.PositiveIntegerField(
        u'Цена за показы', null=True, blank=True, help_text=u'Если оплата за показы, цена за 1000 показов в копейках')
    status = models.BooleanField(u'Статус', default=False, help_text=u'Статус рекламного объявления: остановлено / запущено.')
    disclaimer = models.BooleanField(
        u'Противопоказания', default=False, help_text=u'Укажите, если имеются противопоказания (только для рекламы медицинских товаров и услуг).')

    # not exist in API docs
    approved = models.BooleanField(u'Одобрено', default=False)

    statistics = generic.GenericRelation('Statistic', verbose_name=u'Статистика')

    objects = VkontakteCRUDManager()
    remote = VkontakteManager(
        remote_pk=('remote_id',),
        methods = {
        'get': 'getAds',
        'create': 'createAds',
        'update': 'updateAds',
        'delete': 'deleteAds',
    })

    class Meta:
        abstract = True
Пример #8
0
class Campaign(VkontakteAdsIDContentModel):

    account = models.ForeignKey(Account, verbose_name=u'Аккаунт', related_name='campaigns',
                                help_text=u'Номер рекламного кабинета, в котором должны создаваться кампании.')
    client = ChainedForeignKey(Client, verbose_name=u'Клиент', chained_field="account", chained_model_field="account", show_all=False, auto_choose=True,
                               related_name='campaigns', null=True, blank=True, help_text=u'Только для рекламных агентств. id клиента, в рекламном кабинете которого будет создаваться кампания.')

    name = fields.CharRangeLengthField(
        u'Название', min_length=3, max_length=60, help_text=u'Название рекламной кампании - строка длиной от 3 до 60 символов.')
    day_limit = models.IntegerField(u'Дневной лимит', null=True, help_text=u'Целое число рублей.')
    all_limit = models.IntegerField(u'Общий лимит', null=True, help_text=u'Целое число рублей.')
    start_time = models.DateTimeField(
        u'Время запуска', null=True, blank=True, help_text=u'Время запуска кампании в unixtime формате.')
    stop_time = models.DateTimeField(
        u'Время остановки', null=True, blank=True, help_text=u'Время остановки кампании в unixtime формате.')
    status = models.BooleanField(u'Статус', default=False, help_text=u'Статус рекламной кампании: остановлена / запущена.')

    statistics = generic.GenericRelation('Statistic', verbose_name=u'Статистика')

    objects = VkontakteCRUDManager()
    remote = VkontakteManager(
        remote_pk=('remote_id',),
        methods = {
        'get': 'getCampaigns',
        'create': 'createCampaigns',
        'update': 'updateCampaigns',
        'delete': 'deleteCampaigns',
    })

    class Meta:
        verbose_name = u'Рекламная кампания Вконтакте'
        verbose_name_plural = u'Рекламные кампании Вконтакте'

    def _substitute(self, old_instance):
        super(Campaign, self)._substitute(old_instance)
        self.account = old_instance.account
        self.client = old_instance.client

    @property
    def refresh_kwargs(self):
        kwargs = super(Campaign, self).retresh_kwargs
        kwargs['account_id'] = self.account.remote_id
        kwargs['campaign_ids'] = [self.remote_id]
        if self.client:
            kwargs['client_id'] = self.client.remote_id

        return kwargs

    def check_remote_existance(self, *args, **kwargs):
        existance = super(Campaign, self).check_remote_existance(**kwargs)
        if not existance:
            for ad in self.ads.all():
                ad.archived = True
                ad.save(commit_remote=False)
        return existance

    fields_required_for_update = ['campaign_id']

    def fields_for_update(self):
        '''
        TODO: add dropping start_time, stop_time http://vk.com/developers.php?oid=-1&p=ads.updateCampaigns
        '''
        fields = self.fields_for_create()
        if 'client_id' in fields:
            fields.pop('client_id')
        fields.update(campaign_id=self.remote_id)
        return fields

    def fields_for_create(self):
        fields = dict(name=self.name, status=int(self.status))
        if self.client:
            fields.update(client_id=self.client.remote_id)
        if self.day_limit:
            fields.update(day_limit=self.day_limit)
        if self.all_limit:
            fields.update(all_limit=self.all_limit)
        if self.start_time:
            fields.update(start_time=int(time.mktime(self.start_time.timetuple())))
        if self.stop_time:
            fields.update(stop_time=int(time.mktime(self.stop_time.timetuple())))
        return fields

    def parse(self, response):
        # Convert status=2 to flag archived
        if response['status'] == 2:
            response['status'] = 0
            self.archived = True
        super(Campaign, self).parse(response)

    def fetch_ads(self, ids=None):
        '''
        Get all ads of campaign
        '''
        return super(Campaign, self).fetch_ads(model=Ad, ids=ids)

    def fetch_ads_targeting(self, ids=None):
        '''
        Get all ad targetings of campaign
        '''
        return super(Campaign, self).fetch_ads(model=Targeting, ids=ids)

    def fetch_ads_layout(self, ids=None):
        '''
        Get all ad layouts of campaign
        '''
        return super(Campaign, self).fetch_ads(model=Layout, ids=ids)