В django, как ограничить выбор иностранного поля на основе другого поля в той же модели?

У меня есть эти модели (я ограничил количество полей только теми, которые вам нужны)

class unit(models.Model):
    name = models.CharField(max_length=200)

class project(models.Model):
    name = models.CharField(max_length=200)

class location(address):
    project = models.ForeignKey(project)

class project_unit(models.Model):
    project = models.ForeignKey(project)         
    unit = models.ForeignKey(unit)

class location_unit(models.Model):
    project = models.ForeignKey(project)    
      #Limit the selection of locations based on which project has been selected
    location = models.ForeignKey(location)
      #The same here for unit. But I have no idea how.
    unit = models.ForeignKey(project_unit)       

Моя голова-новичок просто не может понять, как ограничить два поля, местоположение и блок, в модели location_unit, чтобы отображать только те варианты, которые относятся к выбранному проекту в location_unit. Должен ли я переопределить форму модели и сделать запрос там, или я могу использовать limit_choices_to. В любом случае я не смог выполнить оба

Изменить: просто чтобы уточнить, я хочу, чтобы это произошло в Django Admin. Я также попробовал formfield_for_foreignkey, но все равно не пойду за мной.

ИЗМЕНИТЬ 2:

def formfield_for_foreignkey(self, db_field, request, **kwargs):
    if db_field.name == "unit":
        kwargs["queryset"] = project_unit.objects.filter(project=1)
        return db_field.formfield(**kwargs)
    return super(location_unit_admin, self).formfield_for_foreignkey(db_field, request, **kwargs)

Вышеприведенный фрагмент кода работает. Но, конечно, я не хочу, чтобы проект указывал на 1. Как я могу ссылаться на модели project_id? Я пробовал это:

kwargs["queryset"] = project_unit.objects.filter(project=self.model.project.project_id)

Но это не работает (на самом деле я пробовал много вариаций, да, я новичок в django)

Ответ 2

Ваш formfield_for_foreignkey выглядит так, как будто это может быть хорошим направлением, но вы должны понимать, что ModelAdmin (self) не даст вам конкретного экземпляра. Вы должны получить это из request (возможно, сочетание django.core.urlresolvers.resolve и request.path)


Если вы хотите использовать эту функцию только в админе (а не в валидации модели вообще), вы можете использовать пользовательскую форму с классом администратора модели:

forms.py:

from django import forms

from models import location_unit, location, project_unit

class LocationUnitForm(forms.ModelForm):
    class Meta:
        model = location_unit

    def __init__(self, *args, **kwargs):
        inst = kwargs.get('instance')
        super(LocationUnitForm, self).__init__(*args, **kwargs)
        if inst:
            self.fields['location'].queryset = location.objects.filter(project=inst.project)
            self.fields['unit'].queryset = project_unit.objects.filter(project=inst.project)

admin.py:

from django.contrib import admin

from models import location_unit
from forms import LocationUnitForm

class LocationUnitAdmin(admin.ModelAdmin):
    form = LocationUnitForm

admin.site.register(location_unit, LocationUnitAdmin)

(Просто написал их "на лету" без тестирования, поэтому не гарантируйте, что они будут работать, но они должны быть близки.)