简体   繁体   English

如何使用 formtools 向导从 Django FileSystemStorage 中检索以多步骤形式上传的文件

[英]How to retrieve files from Django FileSystemStorage uploaded in a multisteps form using formtools wizard

I am using Django 3.0 and python 3.8.2 to develop an ads website.我正在使用 Django 3.0 和 python 3.8.2 来开发广告网站。 To add a post, I used Django formtools wizard.要添加帖子,我使用了 Django formtools 向导。 It worked and everything goes nicely.它奏效了,一切顺利。 I could save the multiform data.我可以保存多格式数据。 However, I could not retrieve the files from the FileSystemStorage so I can save them.但是,我无法从 FileSystemStorage 中检索文件,因此我可以保存它们。 Hence, any help to achieve this or suggestion is much appreciated.因此,非常感谢任何有助于实现这一点或建议的帮助。 I want to retrieve uploaded files, save them to the data base and then delete them from the wizard (from the FileSystemStorage).我想检索上传的文件,将它们保存到数据库中,然后从向导(从 FileSystemStorage)中删除它们。 Note: there is no error and everything is working except that the uploaded files are not saved to the data base even though they are available in the FileSystemStorage.注意:没有错误,一切正常,除了上传的文件没有保存到数据库中,即使它们在 FileSystemStorage 中可用。 Thus, I want to retrieve them to be able to save them to the data base.因此,我想检索它们以便能够将它们保存到数据库中。
Here is the view class:这是 class 的视图:

TEMPLATES = {"CommonForm": "towns/salehslist/ads_main_form.html",
         "JobForm": "towns/salehslist/forms/jobPostForm.html",
         }


FORMS = [
        ("CommonForm", CommonForm),
        ("JobForm", JobForm, JobImagesForm), 
        ]

class PostWizard(SessionWizardView):

    # The form wizard itself; will not be called directly by urls.py,
    # but rather wrapped in a function that provide the condition_dictionary
    _condition_dict = {  # a dictionary with key=step, value=callable function that return True to show step and False to not
        "CommonForm": True,  # callable function that says to always show this step
        "JobForm": select_second_step,  # conditional callable for verifying whether to show step two
       
    }

    file_storage = FileSystemStorage(
        location=os.path.join(settings.MEDIA_ROOT, "photos")
)

    def get_template_names(self):
        return [TEMPLATES[self.steps.current]]

    def done(self, form_list, form_dict, **kwargs):

        # form_data = [form.cleaned_data for form in form_list]
        # print(form_data)

        data = {k: v for form in form_list for k, v in form.cleaned_data.items()}
        data["posted_by"] = self.request.user
        instance = Job.objects.create(**data)

        print("YOU ARE HERE")
        print(self.request.FILES.getlist("files"))

        for file in self.request.FILES.getlist("files"):
            print(file)
            img_instance = JobImages.objects.create(job=instance, images=file)

            img_instance.save()

        return HttpResponse("<h1>Post Page </h1>")

Here is the url:这是 url:

url(r'^post/$', PostWizard.as_view(FORMS, condition_dict = PostWizard._condition_dict)),

Here is the html template:这是 html 模板:

    <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    {% load static %}
    {% load crispy_forms_tags %}
    {% load i18n %}
    <script type="text/javascript" src="{%  static 'towns/assets/fontawesome-free-5-12-0-we/js/all.js' %}">
    </script>
    <link rel="stylesheet" type="text/css" href="{% static 'towns/assets/bootstrap-4.4.1/dist/css/bootstrap.min.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'towns/assets/fontawesome-free-5-12-0-we/scc/fontawesome.min.css' %}">
    

    <!-- file uploader font -->
    <link type="text/css" rel="stylesheet" media="all"  href="{% static 'towns/assets/fileuploader-2.2/dist/font/font-fileuploader.css' %}" >

    <link rel="stylesheet" type="text/css" href="{% static 'towns/style/forms/jobPostForm.css' %}">





</head>
<body>



    <div class="container">
        <div class="row h-100">
            <div class="col-lg-6 my-auto">

                    <div class="breadcrumb">
                            <div class="ads-form-title">
                                  Job Post 
                            </div>
                    </div>

                    <form class="" action="" method="POST" enctype="multipart/form-data" novalidate id="jobPost">

                        {% csrf_token %} 
                        {{ wizard.management_form }}
                        {{ wizard.form.media }}
                      
                        <hr>
                            <div class="form-group">
                                
                        
                              <div>
                                  {{ wizard.management_form }}
                                    {% if wizard.form.forms %}
                                        {{ wizard.form.management_form }}
                                        {% for form in wizard.form.forms %}
                                            {{ form|crispy }}
                                        {% endfor %}
                                    {% else %}
                                        {{ wizard.form|crispy }}
                                    {% endif %}
                              </div>

                        
                            </div>
                        <hr>


                        <!-- upload images  -->
                        <!-- file input -->
                        <input type="file" name="files" class="files">

                        



                        
                        <center>
                        <button type="submit" class="btn btn-primary" style="position:relative; width: 33%; height: 100%;"> Submit  </button>
                        </center>
                    </form>


            </div>



        </div>
    </div>



    <script type="text/javascript" src=" {% static 'towns/assets/jquery-3.5.0.min.js' %}">
    </script>
    <script type="text/javascript" src=" {% static 'towns/assets/bootstrap-4.4.1/dist/js/bootstrap.min.js' %}">
    </script>

    <script type="text/javascript" src="{% static 'towns/assets/fileuploader-2.2/dist/jquery.fileuploader.min.js' %}" >
    </script>


    </body>
</html>

When user hit submit button of the form wizard, def post() method is called.当用户点击表单向导的submit按钮时,将调用def post()方法。 def post() will def post()

  1. validate the form and验证表格和
  2. save data and files into session.将数据和文件保存到 session 中。
  3. then if the current page is the last page, it will render_done , which is def done()那么如果当前页是最后一页,就会render_done ,也就是def done()

The reason why your request.files is empty is because, the current request does not have files or data associated with it.您的request.files为空的原因是,当前request没有与之关联的文件或数据。 All your data and files are saved to the session when you hit the submit buttons which are preceding the done() method.当您点击done()方法之前的submit按钮时,您的所有数据和文件都会保存到 session 中。

Since I do not know how your form is structured, I am not sure how to definetely solve your problem.由于我不知道您的表格的结构,我不确定如何明确地解决您的问题。 But something like below should do:但是像下面这样的事情应该做:

# iterate over all forms in the form_list
for form in form_list: 

    # check if current form has files
    if bool(self.get_form_step_files(form)):

         # if yes, do something
         uploadedfiles = form.files
         print(uploadedfiles)
         
         for key, value in uploadedfiles.items():
             jobimage = JobImage(job=?, image=value)
             jobimage.save()

Update wihtout your model, form structure, and template, it is difficult to come out with complete solution.没有你的model、表格结构和模板的更新,很难拿出完整的解决方案。 I am posting a minimum working example.我发布了一个最低限度的工作示例。

1. in models.py 1.在models.py中

class MyPost(models.Model):
    field1 = models.CharField(max_length=50)
    field2 = models.CharField(max_length=50)

class Photo(models.Model):
    mypost = models.ForeignKey(MyPost, on_delete=models.CASCADE)
    photo = models.FileField(blank=True, null=True) 

2. In forms, you will not include photoform, because you are trying to uplaod more than one images. 2. 在 forms 中,您不会包含 photoform,因为您要上传多个图像。

from .models import MyPost, Image
from django import forms

class step_first_form(forms.ModelForm):
    class Meta:
        model = MyPost
        fields = ['field1']

class step_second_form(forms.ModelForm):
    class Meta:
        model = MyPost
        fields = ['field2']
  1. in template, you can keep your first template same as whatever you have.在模板中,您可以使您的第一个模板与您拥有的任何模板相同。 For the second one, say, you will have MyPost's field2 and 2 image inputs, you will change it to:对于第二个,比如说,您将拥有 MyPost 的field2和 2 个图像输入,您将其更改为:
<form action="" method="post" enctype="multipart/form-data">{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
    {{ wizard.form.management_form }}
    {% for form in wizard.form.forms %}
        {{ form }}
    {% endfor %}
{% else %}

 {{wizard.form.field2}}

    <input type="file"  name ="imagefile1"  >
    <input type="file"  name ="imagefile2"  >

{% endif %}
</table>
.......
.....
.....
</form>

  • make sure you include enctype="multipart/form-data" otherwise your files will not be uploaded.确保包含enctype="multipart/form-data"否则您的文件将不会被上传。
  • make sure you have different names for filefield otherwise only one will be saved to your model.确保文件字段的名称不同,否则只会将一个名称保存到 model。

4. in views.py 4.在views.py中

def done(self, form_list, form_dict, **kwargs):
        data = [form.cleaned_data for form in form_list]
        
        # you can print out and inspect this data, and you will know 
        # the below code.
        # you will need to modify data[0]['field1'] etc ...
        print(data)

        mypost = MyPost()
        mypost.field1 = data[0]['field1']
        
        mypost.field2=data[1]['field2']
        mypost.save()

        print('mypost')
        print(mypost)

        # the below part is for saving image files to model

        for form in form_list:
            
            # check which form has files
            if bool(self.get_form_step_files(form)):
                
                uploadedfiles= form.files

                print(form.files)  

                for key, value in uploadedfiles.items():
                    photo = Photo(mypost=mypost,photo=value)
                    photo.save()
            else:
                print('not bool')

        return render ##### whatever template you want to render

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM