Ilja Leiko
Ilja Leiko

Reputation: 668

FileField not working in Django

I am trying to create FileField in my forms and without saving file locally, add the file(as an attachment) to email and send it. Email part of code works fine, but when i add FileField it shows me error "'str' object has no attribute 'get'" and i am struggling to figure out what is the problem.

view:

def print(request):
    if request.method == 'POST':
        form = PrintForm(data=request.POST, request = request)
        #print(request.FILES)

        if form.is_valid():
            contact_name = request.POST.get('contact_name', '')
            contact_email = request.POST.get('contact_email', '')
            form_content = request.POST.get('content', '')
            supervisor = form.cleaned_data['supervisor']
            template = get_template('threeD/email/contact_template_for_printing.txt')
            context = Context({
                'contact_name': contact_name,
                'supervisor': supervisor,
                'contact_email': contact_email,
                'form_content': form_content,
            })
            content = template.render(context)
            subject = "New message"

            try:
                email = EmailMessage(
                    subject,
                    content,
                    contact_email,
                    [supervisor],
                    headers={'Reply-To': contact_email}
                )
                if request.FILES:
                    #uploaded_file = request.POST.get('file')

                    uploaded_file = request.FILES['stl_file']  # file is the name value which you have provided in form for file field
                    email.attach('uploaded_file.name, uploaded_file.read(), uploaded_file.content_type')
                email.send()
            except:
                return "Attachment error"

            messages.success(request, "Thank you for your message.")
            return redirect('/index/print/')

    else:
        form = PrintForm(request=request)

    context_dict = {}
    context_dict['printers'] = Printer.objects.all()
    context_dict['form'] = form
    return render(request, 'threeD/print.html', context_dict)

form:

class PrintForm(forms.Form):
    contact_name = forms.CharField(required=True)
    contact_email = forms.EmailField(required=True)
    supervisor = forms.ChoiceField(
        choices=[(str(sup.email), str(sup.name)) for sup in Supervisors.objects.all()]
    )
    stl_file = forms.FileField(required=False)
    stl_file.help_text = "Upload your file as .STL format. If you have more than one file, " \
                     "make a .zip and upload them all at once"
    content = forms.CharField(
        required=True,
        widget=forms.Textarea
    )

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop("request")
        super(PrintForm, self).__init__(*args, **kwargs)
        self.fields['contact_name'].label = "Your name:"
        self.fields['stl_file'].label = "Choose your design file:"

here is HTML code snippet, where i call for the form:

<div class="panel-body">
  <form role="form" action="" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {% load bootstrap %}
    {{ form|bootstrap }}          
    <div class="text-center">
      <button type="submit" class="btn btn-primary">
        <span class="glyphicon glyphicon-send"></span>
        Send a message
      </button>
    </div>
  </form>
</div>

Environment:

Request Method: POST
Request URL: http://localhost:8000/index/print/

Django Version: 1.9
Python Version: 3.4.3

Installed Applications:
['admin_tools',
 'admin_tools.theming',
 'admin_tools.menu',
 'admin_tools.dashboard',
 'threeD.apps.ThreedConfig',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'bootstrapform',
 'django.contrib.sites',
 'allauth',
 'allauth.account',
 'allauth.socialaccount',
 'allauth.socialaccount.providers.facebook']

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.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']

And that's the error i'm getting:

Traceback:

File "C:\Python34\lib\site-packages\django-1.9-py3.4.egg\django\core\handlers\base.py" in get_response
  235.                 response = middleware_method(request, response)

File "C:\Python34\lib\site-packages\django-1.9-py3.4.egg\django\middleware\clickjacking.py" in process_response
  31.         if response.get('X-Frame-Options') is not None:

Exception Type: AttributeError at /index/print/
Exception Value: 'str' object has no attribute 'get'

After removing try-except case from views, i m getting following traceback: Traceback:

File "C:\Python34\lib\site-packages\django-1.9-py3.4.egg\django\core\handlers\base.py" in get_response
  149.                     response = self.process_exception_by_middleware(e, request)

File "C:\Python34\lib\site-packages\django-1.9-py3.4.egg\django\core\handlers\base.py" in get_response
  147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "E:\Python\Facility\threeD\views.py" in print
  145.                 email.attach('uploaded_file.name, uploaded_file.read(), uploaded_file.content_type')

File "C:\Python34\lib\site-packages\django-1.9-py3.4.egg\django\core\mail\message.py" in attach
  307.             assert content is not None

Exception Type: AssertionError at /index/print/
Exception Value: 

Any help would be very much appreciated. Thanks!

Upvotes: 1

Views: 1732

Answers (2)

davidejones
davidejones

Reputation: 1949

It looks like the clickjacking middleware is blowing up because the response its reading is a string when it should be something else.

Looking at your code this line might be the culprit return "Attachment error"

try changing it to

return HttpResponse('Attachment error')

you can import HttpResponse like this from django.http import HttpResponse

Upvotes: 1

Rohan
Rohan

Reputation: 53386

You should not use request.POST and request.FILES to populate the model/DB. You should use data from form.

So for the file field you should do

uploaded_file = form.cleaned_data['stl_file'] 

Also, don't do, use data from form.cleaned_data

contact_name = request.POST.get('contact_name', '')

Rather use

contact_name = form.cleaned_data.get('contact_name', '')

Upvotes: 0

Related Questions