基于下拉值选择显示Django ModelForm中的链接

问题描述 投票:0回答:1

我使用基于类的通用视图和forms.ModelForm作为form_class属性。如何根据表单的下拉值在ModelForm中显示链接?


我将这个最小的,可重现的例子上传到了GitHub HERE

git clone https://github.com/jaradc/SO939393.git

我想要实现的目标:当选择下拉列表中的项目时,在选择后立即显示下拉列表下方文件的链接。

视觉:

  1. 表格上载了请求
  2. 用户从“模型一”下拉列表中选择一个项目
  3. 一些内部流程: 获取ModelOne sample_input_file位置 将该位置作为链接注入“模型一”字段下面的表单

show link in Django ModelForm


QUICK VIEW(这是整个项目)

如果这太压倒了,你可以忽略它!我提供完整的上下文,以防有人想要查看每个细节。

项目名称:SO939393

应用名称:myapp

SO939393 / urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('myapp.urls'))
]

SO939393 / settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    ...
    'myapp.apps.MyappConfig',
]

的myapp / models.py

from django.db import models

class ModelOne(models.Model):
    name = models.CharField(max_length=100)
    large_pickle_file = models.FileField()
    sample_input_file = models.FileField()

    def __str__(self):
        return self.name

class ModelTwo(models.Model):
    name = models.CharField(max_length=100)
    model_one = models.ForeignKey(ModelOne, on_delete=models.CASCADE)
    upload_file = models.FileField()

    def __str__(self):
        return self.name

MYAPP / urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.HomeView.as_view(), name='home'),
    path('create/', views.Create.as_view(), name='create')
]

MYAPP / forms.py

from django import forms
from .models import ModelTwo

class ModelTwoForm(forms.ModelForm):
    class Meta:
        model = ModelTwo
        fields = ['name', 'model_one', 'upload_file']

MYAPP / views.py

from django.shortcuts import render
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.views.generic.list import ListView
from .forms import ModelTwoForm
from .models import ModelTwo

class HomeView(ListView):
    model = ModelTwo
    template_name = 'myapp/base.html'

class Create(CreateView):
    form_class = ModelTwoForm
    model = ModelTwo
    template_name = 'myapp/create_form.html'
    success_url = '/'

MYAPP /模板/ MYAPP / base.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% block content %}
    <h1><a href="{% url 'create' %}">Create</a> an Item</h1>
    <ul>
        {% for item in object_list %}
            <li>{{ item.name }} - {{ item.model_one.name }}</li>
        {% empty %}
            <li>No items yet.</li>
        {% endfor %}
    </ul>
{% endblock %}
{% block custom_js %}{% endblock %}
</body>
</html>

MYAPP /模板/ MYAPP / create_form.html

{% load static %}
{% block content %}
    <div class="container col-5">
        <form action="" method="POST" enctype="multipart/form-data">
            {% csrf_token %}
            {{ form.as_p }}
            <input type="submit" value="Save" />
        </form>
    </div>
{% endblock %}

{% block custom_js %}<script>{% static 'myapp/custom.js' %}</script>{% endblock %}

MYAPP / admin.py

from django.contrib import admin
from .models import ModelOne, ModelTwo

admin.site.register(ModelOne)
admin.site.register(ModelTwo)

MYAPP /静态/ MYAPP / custom.js

# this file is empty but mentioning just in-case javascript is the way to go here
javascript python jquery django django-forms
1个回答
0
投票

100%的功劳归功于How to Implement Dependent/Chained Dropdown List with Django上的Vitor Freitas博客文章。没有它,我将永远不会学习这种技术,这实际上是我第一次使用AJAX。

如果有人真正遵循这一点,你将不得不创建一个超级用户并迁移以查看它的实际运行情况。

MYAPP / urls.py

为urls.py添加类似ajax的路径

from django.urls import path
from . import views

urlpatterns = [
    path('', views.HomeView.as_view(), name='home'),
    path('create/', views.Create.as_view(), name='create'),
    path('ajax/load-sample-file/', views.load_sample_file, name='ajax_load_sample_file'),
]

MYAPP / forms.py

修改我原来的forms.py,因为我知道我需要插入一个BETWEEN字段链接,所以我需要完全控制字段位置。此外,我期待将来实现Bootstrap,所以我正在添加这些表单类。

from django import forms
from .models import ModelTwo

class ModelTwoForm(forms.ModelForm):
    name = forms.TextInput(attrs={'class': 'form-control'})
    model_name = forms.Select(attrs={'class': 'form-control'})
    upload_file = forms.FileInput(attrs={'class': 'form-control-file'})
    class Meta:
        model = ModelTwo
        fields = ['name', 'model_one', 'upload_file']

MYAPP /模板/ MYAPP / create_form.html

我不需要在模板中使用{{ form.as_p }},而是需要写出每个字段(我在下面使用Bootstrap 4类)。注意:如果使用crispyforms,则不必执行任何操作,并且可以使用{{ form.name|as_crispy_field }}(例如)轻松呈现表单字段。

标注:

  1. 形式的id被命名为uploadForm
  2. form有一个名为data-sample-file-url的属性,它将指向一个URL
  3. 必须包含到CDN或本地文件的jquery链接
  4. 我在myapp的静态位置有一个custom.js文件(如下所述)

{% extends 'myapp/base.html' %}
{% load static %}
{% block content %}
    <div class="container col-5">
        <form action="" method="POST" enctype="multipart/form-data"
              id="uploadForm" data-sample-file-url="{% url 'ajax_load_sample_file' %}">
            {% csrf_token %}
            <div class="form-group">
                <label for="{{ form.name.id_for_label }}">Name:</label>
                {{ form.name }}
            </div>
            <div class="form-group">
                <label for="{{ form.model_one.id_for_label }}">Model one:</label>
                {{ form.model_one }}
            </div>
            <div class="form-group" id="sample-file-placeholder"></div>
            <div class="form-group">
                <label for="{{ form.upload_file.id_for_label }}">Upload file:</label>
                {{ form.upload_file }}
            </div>
            <input type="submit" value="Save"/>
        </form>
    </div>
{% endblock %}

{% block custom_js %}
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script type="text/javascript" src="{% static 'myapp/custom.js' %}"></script>
{% endblock %}

MYAPP /静态/ MYAPP / custom.js

这是javascript和AJAX代码,可以显示依赖于下拉值的链接。我们的想法是生成一个GET请求,我们在基于函数的视图中捕获该请求,并从URL中获取这些URL参数以返回所选下拉对象的示例文件。

$("#id_model_one").change(function () {  // #id_model_one is the ID of the Model one field in the form
    var url = $("#uploadForm").attr("data-sample-file-url");  // get the url of the `load_sample_file` view
    var sampleFileId = $(this).val();  // get the selected model one value (number) from the HTML input
    //alert(sampleFileId)
    //alert(typeof sampleFileId);

    $.ajax({                       // initialize an AJAX request
        url: url,                    // set the url of the request (= localhost:8000/myapp/ajax/load-sample-file/)
        data: {
            'samplefile': sampleFileId       // add the country id to the GET parameters (= /ajax/load-sample-file/?samplefile=1)
        },
        success: function (data) {   // `data` is the return of the `load_sample_file` view function, print it out in alert!
            //alert(data);
            //alert(typeof data);
            $("#sample-file-placeholder").html(data);  // replace the empty div placeholder with the data which is html

        }
    });
});

MYAPP / views.py

load_sample_file视图获取samplefile=#值,我们看起来ID。如果它存在,我们将链接和sample_input_file的名称传递给渲染函数的上下文。

from django.shortcuts import render, HttpResponse
from django.views.generic.edit import CreateView
from django.views.generic.list import ListView
from .forms import ModelTwoForm
from .models import ModelOne, ModelTwo

class HomeView(ListView):
    model = ModelTwo
    template_name = 'myapp/base.html'

class Create(CreateView):
    form_class = ModelTwoForm
    model = ModelTwo
    template_name = 'myapp/create_form.html'
    success_url = '/'

def load_sample_file(request):
    sample_file_id = request.GET.get('samplefile')
    #print(sample_file_id)
    if not sample_file_id:
        return HttpResponse("")
    instance = ModelOne.objects.get(id=sample_file_id)
    context = {
        'link': instance.sample_input_file.path,
        'name': instance.sample_input_file.name,
    }
    return render(request, 'myapp/sample_file_link.html', context)

MYAPP /模板/ MYAPP / sample_file_link.html

这是我们在表单中呈现/填充sample-file-placeholder div的HTML。

<label>Sample File:</label>
<a href="{{ link }}">{{ name }}</a>
© www.soinside.com 2019 - 2024. All rights reserved.