首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在django表单中实时过滤数据

在django表单中实时过滤数据
EN

Stack Overflow用户
提问于 2019-10-20 05:59:05
回答 2查看 884关注 0票数 0

严格来说,我有两个问题。第一个问题是forms.py中字段类型的问题。因为我尝试使用外键作为复选框中的值,并且我有一个错误,即"int ()必须是一个字符串、一个类似字节的对象或一个数字,而不是“ModelChoiceField”,我不知道如何处理它。第二个主要问题是在界面中实时过滤数据。我的意思是什么?我有一个用户模型,比如:

代码语言:javascript
运行
复制
# user/models.py:
class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
    country= models.ForeignKey(Country, on_delete=models.SET_NULL, null=True)
    city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True)
    year = models.IntegerField(choices=YEARS, default=1)
    image = models.ImageField(default='default.jpg', upload_to='profile_pics')

在表单中,我只想看到那些位于所选国家/地区的城市。例如,我们有如下记录:

代码语言:javascript
运行
复制
London, United Kingdom;
York, United Kingdom; 
Berlin, Germany;

如果用户选择了德国,他应该只能在城市所在的区域看到柏林。我希望你知道我想要实现什么,并且有人能够帮助我。

代码语言:javascript
运行
复制
# forms.py:

class ProfileUpdateForm(forms.ModelForm):
    country =forms.ModelChoiceField(queryset=Country.objects.all())
    city = forms.ModelChoiceField(queryset=City.objects.filter(country=country))

    class Meta:
        model = Profile
        fields = ['website','country', 'city', 'year', 'image']


# city/models.py

class Country(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


class City(models.Model):
    name = models.CharField(max_length=100)
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    code = models.CharField(max_length=7)

    def __str__(self):
        return self.name

编辑:我认为你需要这段代码:

代码语言:javascript
运行
复制
@login_required
def profile(request):

    if request.method == 'POST':
        u_form = UserUpdateForm(request.POST, instance=request.user)
        p_form = ProfileUpdateForm(request.POST,
                                   request.FILES,
                                   instance=request.user.profile)
        if u_form.is_valid() and p_form.is_valid():
            u_form.save()
            p_form.save()
            messages.success(request, 'Twoje dane zostały uaktualnione!')
    else:
        u_form = UserUpdateForm(instance=request.user)
        p_form = ProfileUpdateForm(instance=request.user.profile)

    context = {
        'u_form': u_form,
        'p_form': p_form,
    }

    return render(request, 'users/profile.html', context)
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-10-20 09:17:25

这很简单,别担心。但是你应该使用基本的Ajax请求,这样你就会学到一些新的东西,快乐!

首先,如果用户还没有选择任何国家,我们应该隐藏表单上的所有城市,或者当用户选择未定义的国家(可能您的国家表中没有城市信息)时,我们应该处理所有错误。因此,将下面这几行添加到表单模型中:

代码语言:javascript
运行
复制
def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['city'].queryset = City.objects.none()

        if 'country' in self.data:
            try:
                country_id = int(self.data.get('country'))
                self.fields['city'].queryset = City.objects.filter(country_id=country_id).order_by('name')
            except (ValueError, TypeError):
                pass  # invalid input from the client; ignore and fallback to empty City queryset
        elif self.instance.pk:
            self.fields['city'].queryset = self.instance.country.city_set.order_by('name')

并增加了新的功能,以获取过滤城市时,用户选择一个国家到您的视图之前的主视图。看起来是这样的:

代码语言:javascript
运行
复制
def load_cities(request):
    country_id = request.GET.get('country')
    cities = City.objects.filter(country_id=country_id).order_by('name')
    return render(request, 'city_dropdown_list_options.html', {'cities': cities})

这个小函数将请求‘国家’字段在您的表单,并发送过滤城市。让我们在您的目录中创建一个新的html文件,如'city_dropdown_list_options.html':

代码语言:javascript
运行
复制
<option value="">---------</option>
{% for city in cities %}
<option value="{{ city.pk }}">{{ city.name }}</option>
{% endfor %}

将新url添加到您的urls.py:

代码语言:javascript
运行
复制
path('ajax/load-cities/', views.load_cities, name='ajax_load_cities')

现在可以在表单中创建一个AJAX请求了。在下面的示例中,我使用的是jQuery,但您可以使用任何JavaScript框架(或仅使用纯JavaScript)来创建异步请求:

代码语言:javascript
运行
复制
{% block content %}

  <h2>Your Form</h2>

  <form method="post" id="ProfileUpdateForm" data-cities-url="{% url 'ajax_load_cities' %}" novalidate>
    {% csrf_token %}
    <table>
      {{ form.as_table }}
    </table>
    <button type="submit">Save</button>
    <a href="{% url 'whatyouwant' %}">Go!</a>
  </form>

  <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
  <script>
    $("#id_country").change(function () {
      var url = $("#ProfileUpdateForm").attr("data-cities-url");  // get the url of the `load_cities` view
      var countryId = $(this).val();  // get the selected country ID from the HTML input

      $.ajax({                       // initialize an AJAX request
        url: url,                    // set the url of the request (= localhost:8000/ajax/load-cities/)
        data: {
          'country': countryId       // add the country id to the GET parameters
        },
        success: function (data) {   // `data` is the return of the `load_cities` view function
          $("#id_city").html(data);  // replace the contents of the city input with the data that came from the server
        }
      });

    });
  </script>

{% endblock %}

太棒了!如果您选择一个国家/地区,您将只看到过滤了国家/地区的城市。这是魔法,对吧?这些我都是从https://www.simpleisbetterthancomplex.com上学到的,你可以用这个标题来搜索:“How to Implement /Chained Dropdown with Django?”祝你好运兄弟!

票数 1
EN

Stack Overflow用户

发布于 2019-10-21 05:13:44

是的,def load_cities函数必须在views.py中创建,就在你的main函数上面。

您的forms.py应该如下所示,您可以删除国家和城市定义,因为您已经在Meta类中定义了您的字段:

代码语言:javascript
运行
复制
class ProfileUpdateForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ['website','country', 'city', 'year', 'image']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['city'].queryset = City.objects.none()

        if 'country' in self.data:
            try:
                country_id = int(self.data.get('country'))
                self.fields['city'].queryset = City.objects.filter(country_id=country_id).order_by('name')
            except (ValueError, TypeError):
                pass
        elif self.instance.pk:
            self.fields['city'].queryset = self.instance.country.city_set.order_by('name')

你能展示你的主要功能,即你的表单的渲染器(在views.py中)吗?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58468359

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档