根据选定的下拉值在Django ModelForm中显示链接

时间:2018-04-17 00:12:55

标签: javascript python jquery django django-forms

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

我将此最小,可重现的示例上传到GitHub HERE

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

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

目视:

  1. 请求中加载的表单
  2. 用户从"模型一"中选择一个项目。下拉
  3. 一些内部流程:
    1. 获取ModelOne sample_input_file位置
    2. 将该位置作为链接注入"模型一"字段
  4. 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
    

1 个答案:

答案 0 :(得分:0)

How to Implement Dependent/Chained Dropdown List with Django上的Vitor Freitas博客文章100%归功于此。没有它,我将永远不会学习这种技术,这实际上是我第一次使用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. 表单具有名为data-sample-file-url的属性,该属性将指向URL
  3. 必须包含指向CDN或本地文件的jquery链接
  4. 我在myapp的静态位置有一个custom.js文件(如下所述)
  5. {% 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>