【问题标题】:Display Link Within Django ModelForm Based On Dropdown Value Selected根据选择的下拉值在 Django ModelForm 中显示链接
【发布时间】:2018-04-17 00:12:54
【问题描述】:

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


我将这个最小的、可重现的示例上传到 GitHub HERE

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

我正在尝试实现 stront>:选择从下拉列表的项目时,在选择后立即显示到下拉下拉下拉下降下方的文件。

视觉上:

  1. 根据请求加载表单
  2. 用户从“Model one”下拉菜单中选择一个项目
  3. 一些内部进程:
    1. 获取 ModelOne sample_input_file 位置
    2. 将该位置作为链接注入到“Model one”字段下方的表单中


快速查看(这是整个项目)

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

项目名称: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/templates/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/templates/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/static/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】:

    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,因为我知道我需要在字段之间插入一个链接,因此我需要完全控制字段位置。 此外,我期待 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/templates/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/static/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/templates/myapp/sample_file_link.html

    这是我们正在渲染/填充到表单中sample-file-placeholder div 中的 HTML。

    <label>Sample File:</label>
    <a href="{{ link }}">{{ name }}</a>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-01
      • 1970-01-01
      • 2018-01-19
      • 1970-01-01
      • 2015-03-08
      • 1970-01-01
      • 2018-04-08
      • 2017-11-05
      相关资源
      最近更新 更多