Форма администратора Django - как динамически менять значения - PullRequest
3 голосов
/ 29 марта 2012

У меня такая ситуация: У меня есть модели Предмет, Регион и Страна.

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 ]

1 голос
/ 05 апреля 2012

Вам необходимо переопределить чистый метод вашей формы администратора:

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 голос
/ 12 июля 2012

Если у вас возникли проблемы с тем, чтобы 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>
0 голосов
/ 05 апреля 2012

Я решил эту проблему не с предложенными библиотеками (с простым 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)

, но я не знаю, является ли сохранение объектов или редактирование объектов.

Здесь писал - лучший способ - переход через форму итеперь у меня есть код:

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)
...