我使用基于类的通用视图和forms.ModelForm作为form_class
属性。如何根据表单的下拉值在ModelForm中显示链接?
我将这个最小的,可重现的例子上传到了GitHub HERE。
git clone https://github.com/jaradc/SO939393.git
我想要实现的目标:当选择下拉列表中的项目时,在选择后立即显示下拉列表下方文件的链接。
视觉:
sample_input_file
位置
将该位置作为链接注入“模型一”字段下面的表单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
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 }}
(例如)轻松呈现表单字段。
标注:
uploadForm
data-sample-file-url
的属性,它将指向一个URL{% 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>