我有这种情况: 我有模型项目,地区和国家。
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中做到这一点。
答案 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)