# -*- coding: utf-8 -*- import xlrd from collections import namedtuple import re from django import forms from django.core.urlresolvers import reverse from django.utils import translation from django.utils.translation import ugettext_lazy as _ from ckeditor.widgets import CKEditorWidget from sorl.thumbnail.admin.current import AdminImageWidget from haystack.query import SearchQuerySet from emencia.django.newsletter.models import ( Attachment, Contact, ContactSettings, MailingList, Newsletter, NewsletterRecommend, ) from theme.models import Theme from city.models import City from country.models import Area, Country from exposition.models import Exposition from conference.models import Conference class ContactSettingsForm(forms.ModelForm): city = forms.CharField(label=_(u'Город'), widget=forms.HiddenInput() ,required=False) periodic = forms.ChoiceField(choices=ContactSettings.PERIODIC_CHOICES, label=_(u'Периодичность отправки')) first_name = forms.CharField(label=_('first name')) subscriber = forms.BooleanField(label=_('subscriber'), required=False) valid = forms.BooleanField(label=_('valid email'), required=False) tester = forms.BooleanField(label=_('contact tester'), required=False) country = forms.MultipleChoiceField(choices=[(c.id,c.name) for c in list(set(Country.objects.language().all()))], required=False) area = forms.MultipleChoiceField(choices=[(a.id, a.name) for a in list(set(Area.objects.language().all()))], required=False) def __init__(self, *args, **kwargs): super(ContactSettingsForm, self).__init__(*args, **kwargs) instance = getattr(self, 'instance', None) if instance: lang = translation.get_language() self.fields['city'].widget.attrs['data-init-text'] = [(item.id, item.name) for item in list(instance.city.filter(translations__language_code=lang))] class Meta: model = ContactSettings fields = ('periodic', 'exponent_practicum', 'organiser_practicum', 'theme', 'area', 'country', 'city', ) def save(self, commit=True): contactsettings = super(ContactSettingsForm, self).save(commit=False) old_save_m2m = self.save_m2m if commit: contactsettings.save() contact = contactsettings.contact contact.first_name = self.cleaned_data['first_name'] contact.subscriber = self.cleaned_data['subscriber'] contact.valid = self.cleaned_data['valid'] contact.tester = self.cleaned_data['tester'] contact.save() return contactsettings def clean_periodic(self): return int(self.cleaned_data['periodic']) def clean_city(self): cities = self.cleaned_data.get('city') if cities: res = [] for id in cities.split(','): try: res.append(int(id)) except ValueError: continue return City.objects.filter(id__in=res) else: return City.objects.none() class MailingListForm(forms.ModelForm): theme_choices = [(item.id, item.name) for item in Theme.objects.language().all()] excel_file = forms.FileField(label=_(u'Импортировать подписчиков'), required=False) add_from_themes = forms.MultipleChoiceField(label=_(u'Добавить подписчиков по тематикам'), required=False, choices=theme_choices) theme_for_filter = forms.MultipleChoiceField(label=_(u'Тематики'), required=False, choices=theme_choices) class Meta: model = MailingList fields = ('name', 'description', 'theme_for_filter') def save(self, commit=True): ml = super(MailingListForm, self).save(commit=True) # data = self.cleaned_data # f = data['excel_file'] # if f: # # contact_list = list(Contact.objects.all()) # book = xlrd.open_workbook(file_contents=f.read()) # sheet = book.sheet_by_index(0) # excel_emails = {sheet.row_values(row_number)[0]: sheet.row_values(row_number)[1] for row_number in range(1, sheet.nrows)} # valid_contacts = [] # # for contact in contact_list: # # if contact.email in excel_emails: # # valid_contacts.append(contact) # for email, first_name in excel_emails.iteritems(): # valid_contacts.append(Contact.objects.create( # email=email, first_name=first_name, # valid=True, activated=True)) # ml.subscribers = valid_contacts # ml.save() return ml def get_contact_list(self, qs): headers_map = namedtuple("Headers", ['email', 'first_name', 'exponent_practicum', 'organiser_practicum', 'geo', 'country', 'city', 'theme', 'time1', 'time2']) excel_file = self.cleaned_data['excel_file'] contact_items = dict(qs.values_list('email', 'pk')) ids = set(contact_items.values()) if excel_file: book = xlrd.open_workbook(file_contents=excel_file.read()) sheet = book.sheet_by_index(0) countries = {} cities = {} themes = {} field_models = { 'country': {'model': Country, 'cached': {}}, 'city': {'model': City, 'cached': {}}, 'theme': {'model': Theme, 'cached': {}} } for i in range(1, sheet.nrows): item = headers_map(*sheet.row(i)) # email = sheet.row_values(i)[0] # first_name = sheet.row_values(i)[1] # exponent_practicum = sheet.row_values(i)[2] # organiser_practicum = sheet.row_values(i)[3] # if email not in contact_items: c, created = Contact.objects.get_or_create(email=item.email.value.strip()) c.first_name = item.first_name.value.strip() or c.first_name c.activated = True c.save() ids.add(c.pk) contactsettings, _created = ContactSettings.objects.get_or_create(contact_id=c.pk) contactsettings.exponent_practicum = item.exponent_practicum.value contactsettings.organiser_practicum = item.organiser_practicum.value for field, data in field_models.iteritems(): # model = data['model'] # cached = data['cached'] cell = getattr(item, field) values = cell.value.split(';') names_to_fetch = [] pks = set() # print(cell) # print(field) # for x in values: # print(x) # import pdb; pdb.set_trace() for val in values: val_stripped = val.strip() _pk = data['cached'].get(val_stripped, None) if _pk is None: names_to_fetch.append(val_stripped) else: pks.add(_pk) # print(names_to_fetch) # print(data['model']) if names_to_fetch: # _pks = dict([(x.name_ru, x.pk) for x in SearchQuerySet().models(data['model']).filter(name__in=values)]) sqs = SearchQuerySet().models(data['model']).filter(name_ru__in=values).load_all() _pks = dict([(x.object.name, x.pk) for x in sqs]) # print(_pks) data['cached'].update(_pks) pks.update(_pks.values()) # print(data['cached']) if pks: _field = getattr(contactsettings, field) _field.add(*pks) # print(pks) contactsettings.save() # p = re.compile(r'([^\(pk=\d+\)]*\(pk=(?P\d+)\))') # p.finditer(): # ... if self.cleaned_data['add_from_themes']: ct_from_themes = Contact.objects\ .filter( contactsettings__theme__in=self.cleaned_data['add_from_themes'] ).distinct().values_list('pk', flat=True) ids.update(ct_from_themes) return ids class NewsletterForm(forms.ModelForm): test_contacts = forms.ModelMultipleChoiceField(label=_(u'Тестовые контакты'), required=False, queryset=Contact.objects.filter(tester=True)) content = forms.CharField(label=_('content'), widget=CKEditorWidget(config_name='newsletters'), required=False) content2 = forms.CharField(label=_('Content B'), widget=CKEditorWidget(config_name='newsletters'), required=False) class Meta: model = Newsletter fields = ('preheader', 'title', 'content', 'ab_testing', 'ab_first_stage', 'preheader2', 'title2', 'content2', 'mailing_list', 'theme_for_filter', 'test_contacts', 'header_sender', 'header_reply', 'status', 'sending_date', 'slug') widgets = { 'ab_first_stage': forms.widgets.TextInput(attrs={'type':'number', 'min': 5, 'max': 100}), } def __init__(self, *args, **kwargs): super(NewsletterForm, self).__init__(*args, **kwargs) # добавляем поле для возможности указания варианта финальной рассылки (А-В тестирование) if self.instance and self.instance.pk and self.instance.ab_testing and self.instance.ab_final_stage: self._meta.fields = ( 'preheader', 'title', 'content', 'ab_testing', 'ab_first_stage', 'preheader2', 'title2', 'content2', 'mailing_list', 'theme_for_filter', 'test_contacts', 'header_sender', 'header_reply', 'ab_final_choice', 'status', 'sending_date', 'slug') field = forms.ChoiceField( label=_(u'Вариант в финальную рассылку'), choices=Newsletter.AB_FINAL_CHOICE, initial=self.instance.ab_final_choice or Newsletter.A) self.fields.insert(self.fields.keyOrder.index('status'), 'ab_final_choice', field) if self.instance and self.instance.mailing_list_id: self.fields['theme_for_filter'].queryset = self.instance.mailing_list.theme_for_filter.all() self.initial['ab_first_stage'] = self.initial.get('ab_first_stage') or 10 class NewsletterDailyForm(forms.ModelForm): test_contacts = forms.ModelMultipleChoiceField(label=_(u'Тестовые контакты'), required=False, queryset=Contact.objects.filter(tester=True)) class Meta: model = Newsletter fields = ( 'preheader', 'title', 'test_contacts', 'banner', 'banner_url', 'header_sender', 'header_reply', 'status', 'sending_date', 'slug') widgets = { 'banner': AdminImageWidget, } class AttachmentForm(forms.ModelForm): class Meta: model = Attachment fields = ('title', 'file_attachment') class NewsletterRecommendForm(forms.ModelForm): rx = re.compile(r'^(?Pc|e)(?P\d+)$') verbose = _(u'Создание/Редактирование рекомендации') # exposition = forms.IntegerField(label=_(u'Выставка'), widget=forms.HiddenInput(), required=False) event_models = {'c': Conference, 'e': Exposition} event = forms.CharField(label=_(u'Событие'), widget=forms.Select()) class Meta: model = NewsletterRecommend fields = ('theme', 'fr', 'to') def __init__(self, *args, **kwargs): super(NewsletterRecommendForm, self).__init__(*args, **kwargs) # import pdb; pdb.set_trace() if self.instance and self.instance.pk: event = self.instance.event() id = event.__class__.__name__.lower()[:1] + str(event.pk) option = u''.format(id=id, label=event.name) self.fields['event'].widget.render_options = lambda choices, value: option self.initial['event'] = id self.fields['event'].widget.attrs.update({ 'data-ajax-url': reverse('admin_events_search'), 'select2': 'true', }) def clean_event(self): event = self.cleaned_data.get('event') match = self.rx.match(event) if not match: raise forms.ValidationError(_(u'Введены неверные данные')) model = self.event_models.get(match.group('type')) self.event_model = model event_id = match.group('pk') try: event = model.objects.get(pk=event_id) except model.DoesNotExist: raise forms.ValidationError(_(u'Такого события не существует')) return event def save(self, commit=True): obj = super(NewsletterRecommendForm, self).save(commit=False) if self.cleaned_data['event']: if self.event_model == Exposition: obj.exposition = self.cleaned_data['event'] else: obj.conference = self.cleaned_data['event'] if commit: obj.save() if not obj.pk: obj.save() obj.theme = self.cleaned_data['theme'] return obj class NewsletterFilterForm(forms.Form): """ Форма для фильтра рассылок по дате """ model = Newsletter start_date = forms.DateField( label=_(u'Начальная дата отправки'), required=False ) end_date = forms.DateField( label=_(u'Конечная дата отправки'), required=False ) def filter(self): """ Фильтр данных """ qs = self.model.objects.all() if self.cleaned_data.get('start_date'): qs = qs.filter(sending_date__gte=self.cleaned_data['start_date']) if self.cleaned_data.get('end_date'): qs = qs.filter(sending_date__lte=self.cleaned_data['end_date']) return qs