2016-08-23 2 views
2

У меня есть модель, описывающая веб-страницу. Поле source_upload представляет собой скриншот веб-страницы.Изначально заполняем FileField в Django-Form

Для добавления объектов сайта в мое приложение, я использую django class-based CreateView. Это работает очень хорошо.

Теперь я пытаюсь добавить полуавтоматический способ добавления сайтов. Вы можете передать URL-адрес в представление, и представление автоматически заполнит форму (и сделает снимок экрана на веб-странице). Пользователь должен иметь возможность просматривать все автоматически извлеченные поля - особенно автоматически созданное изображение скриншота - изменять их и нажать кнопку сохранения, чтобы добавить объект в базу данных, а изображение (если оно было одобрено) в его окончательное местоположение.

Я попытался реализовать это в методе вида get_initial. Это хорошо работает, за исключением скриншота - FileField. Путь I, установленный в initial['source_upload'], не показан в части current: <link> виджета FileInput формы.

Как я могу присвоить файловому полю начальное значение?


models.py

class Site(models.Model): 

    def get_source_upload_path(instance, filename): 
     now = datetime.datetime.now() 
     return "appname/sites/{}/{}/{}/site_{}_{}".format(now.year, now.month, now.day, instance.pk, filename) 

    creationDate = models.DateTimeField(auto_now_add=True) 
    last_modifiedDate = models.DateTimeField(auto_now=True) 
    creator = models.ForeignKey('auth.User', related_name='siteCreated') 
    last_modifier = models.ForeignKey('auth.User', related_name='siteLast_modified') 

    date = models.DateTimeField(default=datetime.date.today)  
    title = models.CharField(max_length=240, blank=True) 
    body = models.TextField(max_length=3000) 

    source_url = models.URLField(blank=True) 
    source_upload = models.FileField(upload_to=get_source_upload_path, blank=True) 

    keywords = models.ManyToManyField("Keyword") 

urls.py

url(r'site/add/$', views.SiteCreate.as_view(), name='site-add'), 
url(r'site/add/(?P<source_url>[A-Za-z0-9\-._~:/\[\]@!$&\'\(\)\*\+,;=?#]+)/$', views.SiteCreate.as_view(), name='site-add-fromurl'), 

forms.py

class SiteForm(ModelForm): 
    class Meta: 
     model = Site 
     fields = ['date', 'title', 'body', 'source_url', 'source_upload', 'keywords'] 
     widgets = { 
      'keywords' : CheckboxSelectMultiple(), 
     } 

views.py

class SiteCreate(LoginRequiredMixin, CreateView): 
    model = Site 
    template_name = 'appname/site_form.html' 
    form_class = SiteForm 
    success_url = reverse_lazy('appname:index') 

    def form_valid(self, form): 
     form.instance.creator = self.request.user 
     form.instance.last_modifier = self.request.user 
     return super(SiteCreate, self).form_valid(form) 

    def get_initial(self): 
     # Get the initial dictionary from the superclass method 
     initial = super(SiteCreate, self).get_initial() 

     try: 
      #get target url from request 
      fullpath = self.request.get_full_path() 
      fullpath = fullpath.split("/") 
      fullpath, querystring = fullpath[3:-1], fullpath[-1] 
      source_domain = fullpath[2] 
      fullpath = "/".join(fullpath) 
      fullpath += querystring 

      source_url = fullpath 

      if (not source_url.startswith("http://") and not source_url.startswith("https://")): 
       print("ERROR: url does not start with http:// or https://") 
       return initial 

      # ... 
      # extract title, date & others with BeautifulSoup 
      # ... 

      #extract screenshot (is there a better way?) 
      from selenium import webdriver 
      driver = webdriver.Firefox() 
      driver.get(source_url) 
      tmpfilename = "{}_{}.png".format(get_valid_filename(source_domain), get_valid_filename(title[:30])) 
      now = datetime.datetime.now() 
      tmpfilepath_rel = "appname/sites/tmp/{}/{}/{}/{}".format(now.year, now.month, now.day, tmpfilename) 
      tmpfilepath = settings.MEDIA_ROOT + tmpfilepath_rel 

      folder=os.path.dirname(tmpfilepath) 
      if not os.path.exists(folder): 
       os.makedirs(folder) 
      driver.save_screenshot(tmpfilepath) 
      driver.quit() 

      initial = initial.copy() 
      initial['source_url'] = source_url 
      initial['title'] = title 
      initial['date'] = soup_date 
      initial['body'] = body 
      initial['source_upload'] = tmpfilepath_rel 
     except KeyError as e: 
      print("no valid source_url found. zeige also ganz normales add/new template") 
     except IndexError as e: 
      print("no valid source_url found. zeige also ganz normales add/new template") 

     return initial 

site_form.html (Используется для создания и просмотра обновлений)

{% extends "appname/base.html" %} 
{% load staticfiles %} 
{% block header %} 
    <link rel="stylesheet" type="text/css" href="{% static 'appname/model_forms.css' %}" /> 
{% endblock %} 
{% block body %} 
     <form enctype="multipart/form-data" action="" method="post">{% csrf_token %} 

      <div class="fieldWrapper"> 
       <div class="error">{{ form.date.errors }}</div> 
       <div class="label">{{ form.date.label_tag }}</div> 
       <div class="field">{{ form.date }}<br />{{ form.date.help_text }}</div> 
       <div class="floatclear"></div> 
      </div> 
      <div class="fieldWrapper"> 
       <div class="error">{{ form.title.errors }}</div> 
       <div class="label">{{ form.title.label_tag }}</div> 
       <div class="field">{{ form.title }}<br />{{ form.title.help_text }}</div> 
       <div class="floatclear"></div> 
      </div> 
      <div class="fieldWrapper"> 
       <div class="error">{{ form.body.errors }}</div> 
       <div class="label">{{ form.body.label_tag }}</div> 
       <div class="field">{{ form.body }}<br />{{ form.body.help_text }}</div> 
       <div class="floatclear"></div> 
      </div> 
      <div class="fieldWrapper"> 
       <div class="error">{{ form.source_url.errors }}</div> 
       <div class="label">{{ form.source_url.label_tag }}</div> 
       <div class="field">{{ form.source_url }}<br />{{ form.source_url.help_text }}</div> 
       <div class="floatclear"></div> 
      </div> 
      <div class="fieldWrapper"> 
       <div class="error">{{ form.source_upload.errors }}</div> 
       <div class="label">{{ form.source_upload.label_tag }}</div> 
       <div class="field">{{ form.source_upload }}<br />{{ form.source_upload.help_text }}</div> 
       <div class="floatclear"></div> 
      </div> 
      <div class="fieldWrapper"> 
       <div class="error">{{ form.keywords.errors }}</div> 
       <div class="label">{{ form.keywords.label_tag }}</div> 

       <div class="field"> 
        <ul class="checkbox-grid"> 
         {% for kw in form.keywords %} 
          <li> 
           {{ kw.tag }} 
           <label for="{{ kw.id_for_label }}"> 
            {{ kw.choice_label }} 
           </label> 
          </li> 
         {% endfor %} 
        </ul> 
        <div class="checkbox_help_text"><br />{{ form.keywords.help_text }}</div> 
       </div> 
       <div class="floatclear"></div> 
      </div> 
      <input type="submit" value="Save" /> 
     </form> 
     <div id="ObjectHistory"> 
      {% if site.pk %} 
       <p>Created by: {{ site.creator }}</p> 
       <p>Created on: {{ site.creationDate }}</p> 
       <p>Last modified by: {{ site.last_modifier }}</p> 
       <p>Last modified on: {{ site.last_modifiedDate }}</p> 
       <p>Now: {% now "Y-m-d H:i:s" %} <a href="{% url 'appname:site-delete' site.pk %}"><button>delete</button></a></p> 
      {% else %} 
       <p>This is a new Site!</p> 
       <p>Now: {% now "Y-m-d H:i:s" %}</p> 
      {% endif %} 
     </div> 
{% endblock %} 
+1

Я думаю, что вы не можете, потому что это было бы огромным риск безопасности. Представьте себе поле файла с начальным значением '/ etc/shadow' и скрытым. Это позволит вам «украсть» любой файл из пользовательской системы. Я не знаю, как это работает с javascript. Я думаю, что браузеры игнорируют начальные значения в поле файла (из html part) – Dawid

+0

Я не хочу устанавливать начальное значение для «Файл для загрузки». Виджет (default-django-) выглядит примерно так: '' Текущий файл: <файл-url-on-the-server>. Вы можете заменить его на ".И я хочу установить начальное значение только для части ''. Не для локального файла пользователь (может или не должен) загружать. – Graslandpinguin

ответ

1

Это происходит потому, что значение FileField, используемый в вашей форме, это не просто путь к файлу - это пример FieldFile (см. https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.fields.files.FieldFile).

Я не уверен, что вы можете создать экземпляр FieldFile напрямую, но по крайней мере вы можете сделать это, создав экземпляр модели (вам не нужно ее сохранять).

В views.py:

tmp_site = Site(source_upload=tmpfilepath_rel) 
initial['source_upload'] = tmp_site.source_upload 

В качестве альтернативы вы можете вручную добавить ссылку на файл при рендеринге HTML:

<div class="currently"><a href="{{ form.source_upload.value }}">{{ form.source_upload.value }}</a></div> 
+0

Я не хочу устанавливать начальное значение для «Файл для загрузки», но для части «Текущий загруженный этот файл» в FileInput-Widget. Виджет выглядит примерно так: '' Текущий файл: <файл-url-on-the-server>. Вы можете заменить его на ". И я хочу установить начальное значение только для части ''. Не для локального файла пользователь (может или не должен) загружать. Моя формулировка вопроса была немного неясной – Graslandpinguin

+0

Можете ли вы добавить шаблон html к вопросу? – skoll

+0

Я добавил шаблон 'site_form.html' к вопросу. – Graslandpinguin

Смежные вопросы