Django 3 ModelChoiceField остается пустым - PullRequest
3 голосов
/ 29 апреля 2020

У меня есть эта форма с двумя полями. Второе поле должно быть заполнено именами существующих проектов, но при визуализации оно остается пустым и раскрывающийся список не отображается.

class UploadRawForm(forms.ModelForm):
    orig_file = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
    project = forms.ModelChoiceField(queryset=Project.objects.all(), required=True)
    class Meta:
        model = RawFile
        fields = ['orig_file', 'project']

Шаблон:

{% extends 'base.html' %}

{% block title %}File upload{% endblock %}

{% block content %} 
    <h1> {{ name }} </h1>
    <form method="POST" id="upload-form" class="upload-form" enctype="multipart/form-data" novalidate>
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="save btn btn-default">Upload</button>
    </form>

    {% if form.errors %}
        {% for field in form %}
            {% for error in field.errors %}
                <p> {{ error }} </p>
            {% endfor %}
        {% endfor %}
    {% endif %}

{% endblock %}

views.py:

@login_required(login_url='accounts/login')
def upload_raw_view(request):
    '''Upload RAW files. Working for single file uploads'''
    form = UploadRawForm()
    name = 'Upload RAW files.'
    context = {'form': form, 'name': name}
    if request.method == 'POST':
        form = UploadRawForm(request.POST, request.FILES)
        context['form'] = form
        if not form.is_valid():
            return render(request, 'proteomics/upload.html', context=context)
        if form.is_valid():
            files = request.FILES.getlist('orig_file')
            for f in files:
                rawfile = RawFile(orig_file=f)
                rawfile.save()
            return render(request, 'proteomics/upload.html', context)
    return render(request, 'proteomics/upload.html', context)

models.py

class RawFile(models.Model):
    # use the custom storage class fo the FileField
    orig_file = models.FileField(upload_to = media_file_name, 
                                 storage = public_storage, 
                                 max_length = 1000)
    md5sum = models.CharField(max_length = 36, 
                              default = timezone.now, 
                              unique = True)
    created = models.DateField(default=timezone.now)
    project = models.ForeignKey(Project, on_delete=models.CASCADE, null=False)

    def save(self, *args, **kwargs):
        print('Saving new raw file.', self.md5sum)
        if not self.pk:  # file is new
            md5 = hashlib.md5()
            for chunk in self.orig_file.chunks():
                md5.update(chunk)
            self.md5sum = md5.hexdigest()
        if not self.id:
            self.created = timezone.now()
        print('Saving new raw file.', self.md5sum)

        try:
            super(RawFile, self).save(*args, **kwargs) 
        except IntegrityError as e:
            pass

    def __str__(self):
        return basename(self.orig_file.name)

    @property
    def abs_path(self): 
        return f'{PUBLIC_MEDIA_ROOT}/{self.orig_file}'

    @property
    def filename(self):
        return basename(self.abs_path)

    @property
    def path(self):
        return dirname(self.abs_path)

    @property
    def rawtools_status(self):
        path = dirname(self.abs_path)
        if isfile('QcDataTable.csv'):
            return 'Done'
        elif isfile(join(path, 'rawtools.txt')):
            return 'Running'
        return 'New file'

    @property    
    def href(self):
        return os.path.dirname('/'+self.orig_file.name)

    def link(self):
        print(self.href)
        return mark_safe(r'<a href="{}">Output</a>'.format(self.href))

    link.short_description = 'Browse'

enter image description here

Версии

django                    3.0.5            py36h9f0ad1d_1    conda-forge
django-admin-index        1.3.0                    pypi_0    pypi
django-extensions         2.2.9              pyh9f0ad1d_0    conda-forge
django-ordered-model      3.3.0                    pypi_0    pypi
django-plotly-dash        1.3.1                    pypi_0    pypi

Доступные проекты отображаются в HTML код, хотя:

    <form method="POST" id="upload-form" class="upload-form" enctype="multipart/form-data" novalidate>
        <input type="hidden" name="csrfmiddlewaretoken" value="BCns828qAZlisCkj31ITefv5fn3YugsUIZRGsR5wfKnRyL2XTAvDsdWOKX2TSaKQ">
        <p><label for="id_orig_file">Orig file:</label> <input type="file" name="orig_file" multiple required id="id_orig_file"></p>
<p><label for="id_project">Project:</label> <select name="project" required id="id_project">
  <option value="" selected>---------</option>

  <option value="1">COVID</option>

  <option value="2">LSARP</option>

</select></p>
        <button type="submit" class="save btn btn-default">Upload</button>
    </form>

Ответы [ 5 ]

0 голосов
/ 07 мая 2020

Атрибут виджета должен работать. Вот так:

project = forms.ModelChoiceField(
    queryset= Project.objects.all(),
    widget=forms.Select(attrs={'class': 'form-control', 'required': True}), empty_label='')
0 голосов
/ 05 мая 2020

Если вы хотите заполнить форму предыдущими или начальными данными, то при запуске формы в файле views.py вы должны сделать что-то вроде этого:

form = JournalForm(initial={'tank': 123})

Или установить значение в файл forms.py, например:

tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123) 
0 голосов
/ 02 мая 2020

Вам нужно исправить свою форму:

class UploadRawForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['project'].queryset = Project.objects.all()

    class Meta:
        model = RawFile
        fields = ['orig_file', 'project']
        widgets = {
            'orig_file': forms.ClearableFileInput(attrs={'multiple': True}),
        }

Относительно поля orig_file: вы изменяете только его виджет, поэтому вам нужно только добавить запись в диктовку Meta.widgets.

Относительно поля project: нет необходимости полностью переопределять то, что вам уже было дано. Просто измените набор запросов во время инициализации формы. В вашем случае вам может даже не понадобиться изменять набор запросов, поскольку по умолчанию уже установлено значение Project.objects.all(). Таким образом, ваша форма может быть просто:

class UploadRawForm(forms.ModelForm):
    class Meta:
        model = RawFile
        fields = ['orig_file', 'project']
        widgets = {
            'orig_file': forms.ClearableFileInput(attrs={'multiple': True}),
        }
0 голосов
/ 02 мая 2020

Шаблон содержал материализацию. css, из-за чего раскрывающийся список не отображался. Я добавил

  <script>
    $(document).ready(function() {
    $('select').material_select(); 
    });
  </script>

сразу после импорта файла материализации.

0 голосов
/ 01 мая 2020

Зачем использовать ModelForm, если вы переопределяете все сгенерированные поля?

Вот что я бы сделал:

# forms.py
class UploadRawForm(forms.ModelForm):
    orig_file = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

    class Meta:
        model = RawFile
        fields = ['orig_file', 'project']
# views.py
@login_required(login_url='accounts/login')
def upload_raw_view(request):
    '''Upload RAW files. Working for single file uploads'''
    form = UploadRawForm(request.POST or None, request.FILES or None)
    name = 'Upload RAW files.'
    context = {'form': form, 'name': name}
    if request.method == 'POST':
        if form.is_valid():
            files = request.FILES.getlist('orig_file')
            for f in files:
                rawfile = RawFile(orig_file=f)
                rawfile.save()
    return render(request, 'proteomics/upload.html', context)

Ваша модель и шаблон выглядят нормально

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...