1

Goal

I'm trying to inject the "Send BCC" Job Site email addresses/objects into the form as the initial default value. The difficulty seems to be how it's interpreting super().get_context_data(**kwargs) and the view somehow is missing the object() it's looking for. I can't seem to figure out what's wrong, despite checking for duplicate names, defining self.object inside of post and get.

GitHub: https://github.com/varlenthegray/wcadmin/blob/dev/communication/views.py#L21

Referenced the following StackOverflows in attempts to find the solution:

Error

Environment:


Request Method: POST
Request URL: http://localhost:3003/email/compose_email

Django Version: 4.0.6
Python Version: 3.8.10
Installed Applications:
['customer',
 'equipment',
 'service',
 'supplier',
 'users',
 'qb',
 'communication',
 'main',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.humanize',
 'dateutil',
 'widget_tweaks',
 'intuitlib',
 'quickbooks',
 'rest_framework',
 'rest_framework_datatables',
 'markdownify']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "/home/wcadev/public_html/lib/python/Django-4.0.6-py3.8.egg/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/home/wcadev/public_html/lib/python/Django-4.0.6-py3.8.egg/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/wcadev/public_html/lib/python/Django-4.0.6-py3.8.egg/django/views/generic/base.py", line 84, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/wcadev/public_html/lib/python/Django-4.0.6-py3.8.egg/django/contrib/auth/mixins.py", line 73, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/home/wcadev/public_html/lib/python/Django-4.0.6-py3.8.egg/django/views/generic/base.py", line 119, in dispatch
    return handler(request, *args, **kwargs)
  File "/home/wcadev/public_html/wcadmin/communication/views.py", line 92, in post
    response = super().form_invalid(form)
  File "/home/wcadev/public_html/lib/python/Django-4.0.6-py3.8.egg/django/views/generic/edit.py", line 69, in form_invalid
    return self.render_to_response(self.get_context_data(form=form))
  File "/home/wcadev/public_html/wcadmin/communication/views.py", line 28, in get_context_data
    context = super().get_context_data(**kwargs)
  File "/home/wcadev/public_html/lib/python/Django-4.0.6-py3.8.egg/django/views/generic/edit.py", line 75, in get_context_data
    return super().get_context_data(**kwargs)
  File "/home/wcadev/public_html/lib/python/Django-4.0.6-py3.8.egg/django/views/generic/detail.py", line 95, in get_context_data
    if self.object:

Exception Type: AttributeError at /email/compose_email
Exception Value: 'EmailHomepage' object has no attribute 'object'

View

class EmailHomepage(LoginRequiredMixin, generic.CreateView):
    model = EmailHistory
    template_name = 'communication/compose_email.html'
    form_class = CreateEmail
    success_url = '?sent=true'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['customers'] = JobSite.objects.filter(active=True).exclude(email=None)
        context['existing_templates'] = EmailTemplates.objects.all()
        return context

    def post(self, request, *args, **kwargs):
        data = request.POST.get('data')

        if data:
            # fancy footwork to get POST data and represent it as an array, then get objects from the array
            raw_job_site_ids = simplejson.loads(request.POST['data'])['body']
            job_site_ids = []

            # this has to be done, it's a 3D array initially with 1 array, [0] didn't work
            for js_id in raw_job_site_ids:
                job_site_ids.append(js_id[0])

            job_sites = JobSite.objects.filter(pk__in=job_site_ids)

            form = CreateEmail(request.POST, initial={'send_bcc': job_sites})
        else:
            form = CreateEmail(request.POST)

        if form.is_valid():
            form_save = form.save(commit=False)
            form_save.user = self.request.user
            draft = self.request.GET.get('draft')

            if draft:
                form_save.status = 'draft'
            else:
                form_save.status = 'sent'

                send_cc = []
                send_bcc = []

                for customer in form.cleaned_data.get('send_cc'):
                    send_cc.append(customer.email)

                for customer in form.cleaned_data.get('send_bcc'):
                    send_bcc.append(customer.email)

                message = EmailMultiAlternatives(
                    subject=form.cleaned_data.get('subject'),
                    body=form.cleaned_data.get('message'),
                    from_email='[email protected]',
                    to=['[email protected]'],
                    bcc=send_bcc,
                    cc=send_cc,
                )

                message.attach_alternative(markdown.markdown(form.cleaned_data.get('message')), 'text/html')

                message.send(fail_silently=False)

            form.save()

            if not draft:
                return super().form_valid(form)
            else:
                return HttpResponseRedirect('?save_draft=true')
        else:
            logger.warning('Email Form Invalid.')

            response = super().form_invalid(form)

            if self.request.accepts('text/html'):
                return response
            else:
                return JsonResponse(form.errors, status=400)

Model

class EmailHistory(models.Model):
    send_bcc = models.ManyToManyField(Customer, blank=True, related_name='send_bcc')
    send_cc = models.ManyToManyField(Customer, blank=True, related_name='send_cc')
    subject = models.CharField(max_length=200)
    message = models.TextField()
    template_used = models.ForeignKey(EmailTemplates, on_delete=models.CASCADE, blank=True, null=True)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, editable=False)
    status = models.CharField(max_length=50)
    timestamp = models.DateTimeField(auto_now_add=True, editable=False)

    class Meta:
        ordering = ['-timestamp']

    @property
    def bcc_as_comma(self):
        all_bcc = ''

        for customer in self.send_bcc.all():
            all_bcc += customer.email

            if self.send_bcc.count() > 1:
                all_bcc += ', '

        if self.send_bcc.count() > 1:
            return all_bcc[:-2]
        else:
            return all_bcc

    @property
    def cc_as_comma(self):
        all_cc = ''

        for customer in self.send_cc.all():
            all_cc += customer.email

            if self.send_cc.count() > 1:
                all_cc += ', '

        if self.send_bcc.count() > 1:
            return all_cc[:-2]
        else:
            return all_cc

Form

class CreateEmail(forms.ModelForm):
    send_bcc = SendField(queryset=Customer.objects.all().exclude(email=None)
                         .order_by('first_name', 'last_name', 'company', 'email'), required=False)
    send_cc = SendField(queryset=User.objects.all().exclude(email='')
                        .order_by('first_name', 'last_name', 'username'), required=False)
    template_used = forms.ModelChoiceField(queryset=EmailTemplates.objects.all(), required=False)

    class Meta:
        model = EmailHistory
        fields = ['send_bcc', 'send_cc', 'subject', 'message', 'template_used']
1
  • Does this work? context = super(EmailHomepage, self).get_context_data(**kwargs) Commented Jul 24, 2022 at 1:34

1 Answer 1

0

Well, I'm pretty sure it boils down to moving from form_valid() and form_invalid(). Once I moved my code back to that method (I had it working through that method) I've resolved this specific error. Unfortunately, I'm still having a hard time pre-selecting values, but at least it's not dead anymore.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.