Django - объект не имеет атрибута 'object' при инъекции данных POST-формы
Гол
Я пытаюсь внедрить адреса/объекты электронной почты Job Site "Send BCC" в форму в качестве начального значения по умолчанию. Трудность, похоже, заключается в том, как он интерпретирует super().get_context_data(**kwargs)
, и представление каким-то образом пропускает объект(), который он ищет. Я не могу понять, в чем дело, несмотря на проверку на дублирование имен, определение self.object внутри post и get.
GitHub: https://github.com/varlenthegray/wcadmin/blob/dev/communication/views.py#L21
В попытках найти решение возникли следующие переполнения стека:
- У объекта 'CheckoutView' отсутствует атрибут 'object'
- Django: объект не имеет атрибута 'object'
- Django Test: type object has no attribute 'objects'
- Django: AttributeError: "Object has no attribute" .
Ошибка
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'
Вид
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='info@wcwater.com',
to=['info@wcwater.com'],
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)
Модель
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
Форма
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']
Ну, я почти уверен, что это сводится к переходу от form_valid() и form_invalid(). Как только я переместил свой код обратно в этот метод (у меня он работал через этот метод), я решил эту конкретную ошибку. К сожалению, я все еще испытываю трудности с предварительным выбором значений, но, по крайней мере, это больше не мертво.