Django管理表单 - 如何动态更改选择值

时间:2012-03-29 09:58:15

标签: django django-admin

我有这种情况: 我有模型项目,地区和国家。

class Item(models.Model):
    name = models.CharField(max_length=255)
    alias = models.SlugField(unique=True)
    country = models.OneToOneField(Country, default=0)
    region = models.OneToOneField(Region, default=0, related_name='')

class Region(models.Model):
    name = models.CharField(max_length=100)
    country = models.ForeignKey(Country, default=0) 

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

当我在管理区域中添加项目并选择国家/地区时,我希望仅从所选的Regions中使用Country自动构建区域选择。

我知道如何在javascript中执行此操作,但我不知道它是如何在Django中做到这一点。

3 个答案:

答案 0 :(得分:1)

您需要覆盖管理表单的干净方法:

def clean(self):
    super(CustomItemForm, self).clean() #if necessary
    if 'region' in self._errors:
        """     
        reset the value (something like this i 
        think to set the value b/c it doesnt get set 
        b/c the field fails validation initially)
        """
        region = Region.objects.get(pk=self.data['region'])
        self.initial['region'] = region.id
        self.cleaned_data['region'] = region
        self.region = region

        # remove the error
        del self._errors['region']

    return self.cleaned_data 

答案 1 :(得分:1)

如果你在让django接受你选择的值时遇到麻烦,因为它不认为它应该首先出现在那里,让查询集引用每个可能的值,但是然后覆盖“choices”属性空集。后一部分将避免django构建一个巨大的选项列表,它将被动态javascript覆盖。

我知道这对于管理员屏幕来说并不是一成不变的,但我找到了这个页面,同时希望为非管理员做类似的事情,所以我想我也会在这里回答它。这是我正在使用的:

在views.py中

from django.shortcuts import render_to_response
from django import forms
from django.template import RequestContext
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse
from django.core import serializers
# other imports

class AddRouteForm ( forms.Form ):
    router = forms.ModelChoiceField ( queryset=Router.objects.all() )
    peer = forms.ModelChoiceField ( queryset=Peer.objects.all() )
    peer.choices = []
    # other stuff not relevant

def get_peers ( request ):
    router_id = request.GET['router_id']
    router = Router.objects.get(id=router_id)
    data = serializers.serialize ( "json", router.peer_set.filter(transit_capable=True) )
    return HttpResponse ( data, content_type="text/json" )

def add_route ( request ):
    if request.method == "POST":
        form = AddRouteForm ( request.POST )
        if form.is_valid ():
            # TODO something here
            return HttpResponseRedirect ( reverse ( "staticroute.views.index" ) )
    else:
        form = AddRouteForm ()
    return render_to_response ( "staticroute/add_route.html", locals(), RequestContext(request) )

在html文件中(jQuery也需要加载):

<form method="POST">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Add Route" />
</form>
<script>
    $("#id_router").change ( function () {
        var router_id = $('#id_router').val();

        var items = [];
        items.push ( '<option value="" selected="selected">---------</option>' );
        $("#id_peer").html ( items.join('') );

        if ( router_id != "" ) {
            $.getJSON ( '{% url staticroute.views.get_peers %}', {router_id:router_id}, function(data) {
                $.each ( data, function ( index, val ) {
                    items.push ( '<option value="' + val.pk + '">' + val.fields.description + ' (' + val.fields.address + ')</option>');
                } );
                $("#id_peer").html ( items.join('') );          
            } );
        }

    } ).change();
</script>

答案 2 :(得分:0)

Soory for my delay(我有其他任务)。

我解决了这个问题,而不是提议的库(使用简单的javascript),但存在另一个问题:当我更改国家/地区时 - 选择区域自动更改,但我无法保存新的区域值(当来自同一个国家/地区的另一个区域时 - 没问题),因为错误选择一个有效的选择。这个选择不是可用的选择之一。

模型在第一个问题中是相同的,但模型国家/地区的默认值等于1。

我的第一种方式是通过formfield_key函数更改国家/地区选择,

def formfield_for_foreignkey(self, db_field, request, **kwargs):
    if db_field.name == 'region':
        kwargs["queryset"] = Region.objects.filter(country=self.country)
        return db_field.formfield(**kwargs)

但我不知道是保存对象还是编辑对象。

Here写道 - 最好的方法是改变形式 现在我有代码:

class Item(models.Model):
    country = models.ForeignKey(Country, default=1)
    region = models.ForeignKey(Region, related_name='')


class ItemAdmin(admin.ModelAdmin):
    form = CustomItemForm
    prepopulated_fields = {"alias": ("name",)}
    list_filter = ('country', 'category',)

class CustomItemForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        try:
            country = kwargs['instance'].country
        except KeyError:
            country = 1 
        super(CustomItemForm, self).__init__(*args, **kwargs)
        self.fields['region'].queryset = Region.objects.filter(country=country)