문제

나는 다음과 비슷한 두 가지 외국 관계가 있습니다.

class Parent(models.Model):
  name = models.CharField(max_length=255)
  favoritechild = models.ForeignKey("Child", blank=True, null=True)

class Child(models.Model):
  name = models.CharField(max_length=255)
  myparent = models.ForeignKey(Parent)

부모님의 선택을 어떻게 부모가있는 어린이에게만 제한합니까? 나는 시도했다

class Parent(models.Model):
  name = models.CharField(max_length=255)
  favoritechild = models.ForeignKey("Child", blank=True, null=True, limit_choices_to = {"myparent": "self"})

그러나 관리자 인터페이스는 어린이를 나열하지 않습니다.

도움이 되었습니까?

해결책

나는 방금 만났다 외국인 .limit_choices_to Django 문서에서. 이것이 어떻게 작동하는지 아직 확실하지 않지만 여기서 옳은 일이 될 수 있습니다.

업데이트: 외국 키 .limit_choices_to는 키에 대한 허용 가능한 선택을 제한하기 위해 상수, 호출 가능 또는 Q 객체를 지정할 수 있습니다. 관련된 물체에 대해 아무것도 모르기 때문에 분명히 여기서는 사용되지 않습니다.

호출 가능 (함수 또는 클래스 방법 또는 호출 가능한 객체)을 사용하는 것이 더 유망한 것 같습니다. 그러나 HTTPrequest 객체에서 필요한 정보에 액세스하는 방법에 대한 문제는 여전히 남아 있습니다. 사용 스레드 로컬 스토리지 해결책 일 수 있습니다.

2. 업데이트 : 다음은 저를 위해 일한 것입니다.

위의 링크에 설명 된대로 미들웨어를 만들었습니다. "Product = 1"과 같은 요청의 파트에서 하나 이상의 인수를 추출 하고이 정보를 스레드 로컬에 저장합니다.

다음으로 모델에는 스레드 로컬 변수를 읽고 ID 목록을 반환하여 외래 키 필드의 선택을 제한하는 클래스 메소드가 있습니다.

@classmethod
def _product_list(cls):
    """
    return a list containing the one product_id contained in the request URL,
    or a query containing all valid product_ids if not id present in URL

    used to limit the choice of foreign key object to those related to the current product
    """
    id = threadlocals.get_current_product()
    if id is not None:
        return [id]
    else:
        return Product.objects.all().values('pk').query

일반적인 관리 페이지가 정상적으로 작동하도록 선택되지 않은 경우 가능한 모든 ID가 포함 된 쿼리를 반환하는 것이 중요합니다.

그런 다음 외국 키 필드가 다음과 같이 선언됩니다.

product = models.ForeignKey(
    Product,
    limit_choices_to={
        id__in=BaseModel._product_list,
    },
)

캐치는 요청을 통해 선택을 제한하기 위해 정보를 제공해야한다는 것입니다. 여기서 "자기"에 액세스하는 방법이 보이지 않습니다.

다른 팁

'올바른'방법은 사용자 정의 양식을 사용하는 것입니다. 거기에서 현재 객체 인 self.instance에 액세스 할 수 있습니다. 예시 --

from django import forms
from django.contrib import admin 
from models import *

class SupplierAdminForm(forms.ModelForm):
    class Meta:
        model = Supplier
        fields = "__all__" # for Django 1.8+


    def __init__(self, *args, **kwargs):
        super(SupplierAdminForm, self).__init__(*args, **kwargs)
        if self.instance:
            self.fields['cat'].queryset = Cat.objects.filter(supplier=self.instance)

class SupplierAdmin(admin.ModelAdmin):
    form = SupplierAdminForm

적어도 Django 1.1이 adminModel.formfield_for_foreignkey (self, db_field, request, ** kwargs)를 재정의하는 이후 로이 작업을 수행하는 새로운 "올바른"방법.

보다 http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#django.contrib.admin.modeladmin.formfield_for_foreignkey

아래 링크를 따르고 싶지 않은 사람들은 위의 질문 모델에 가까운 예제 기능입니다.

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "favoritechild":
            kwargs["queryset"] = Child.objects.filter(myparent=request.object_id)
        return super(MyModelAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)

편집중인 현재 객체를 얻는 방법에 대해서는 잘 모르겠습니다. 나는 그것이 실제로 어딘가에있을 것으로 기대하지만 확실하지 않습니다.

이것은 장고가 작동하는 방식이 아닙니다. 당신은 한 방향으로가는 관계 만 만들 것입니다.

class Parent(models.Model):
  name = models.CharField(max_length=255)

class Child(models.Model):
  name = models.CharField(max_length=255)
  myparent = models.ForeignKey(Parent)

그리고 부모로부터 아이들을 접근하려고한다면parent_object.child_set.all(). MyParent 필드에서 관련 _name을 설정하면 그것이 당신이 그것을 부르는 것입니다. 전: related_name='children', 그러면 당신은 할 것입니다 parent_object.children.all()

읽기 문서 http://docs.djangoproject.com/en/dev/topics/db/models/#many-to-one-relationships 이상.

Django Admin 인터페이스에 제한이 필요한 경우 이것이 작동 할 수 있습니다. 나는 그것을 기반으로한다 이 답변 다른 포럼에서 - 많은 사람들의 관계를위한 것이지만 교체 할 수 있어야합니다. formfield_for_foreignkey 작동하기 위해. ~ 안에 admin.py:

class ParentAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        self.instance = obj
        return super(ParentAdmin, self).get_form(request, obj=obj, **kwargs)

    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        if db_field.name == 'favoritechild' and self.instance:       
            kwargs['queryset'] = Child.objects.filter(myparent=self.instance.pk)
        return super(ChildAdmin, self).formfield_for_foreignkey(db_field, request=request, **kwargs)

모델 인스턴스를 작성/편집 할 때 관리자 인터페이스에서 사용 가능한 선택을 제한 하시겠습니까?

이를 수행하는 한 가지 방법은 모델의 검증입니다. 이렇게하면 외국 필드가 올바른 선택이 아닌 경우 관리자 인터페이스에서 오류를 제기 할 수 있습니다.

물론 에릭의 대답은 정확합니다. 여기에서 자녀에서 부모로의 외국 열쇠 하나만 필요합니다.

@ber : 이와 비슷한 모델에 검증을 추가했습니다.

class Parent(models.Model):
  name = models.CharField(max_length=255)
  favoritechild = models.ForeignKey("Child", blank=True, null=True)
  def save(self, force_insert=False, force_update=False):
    if self.favoritechild is not None and self.favoritechild.myparent.id != self.id:
      raise Exception("You must select one of your own children as your favorite")
    super(Parent, self).save(force_insert, force_update)

내가 원하는 방식으로 정확하게 작동하지만,이 검증으로 인해 선택 후 유효성을 검사하기보다는 관리자 인터페이스의 드롭 다운에서 선택을 제한 할 수 있다면 정말 좋을 것입니다.

나는 비슷한 일을하려고 노력하고 있습니다. 모든 사람들이 '당신은 외국의 열쇠 만 있어야한다'고 말하는 것처럼 보인다.

Limit_choices_to = { "myparent": "self"} 당신이하고 싶지 않은 것은 부끄러운 일입니다. 깨끗하고 단순했을 것입니다. 불행히도 '자기'는 평가되지 않고 일반 문자열로 겪습니다.

나는 아마도 내가 할 수 있다고 생각했다 :

class MyModel(models.Model):
    def _get_self_pk(self):
        return self.pk
    favourite = models.ForeignKey(limit_choices_to={'myparent__pk':_get_self_pk})

그러나 기능이 자체 arg를 통과하지 않기 때문에 오류가 발생합니다.

유일한 방법은이 모델을 사용하는 모든 형식에 논리를 넣는 것 같습니다 (즉, 쿼리 세트를 Formfield의 선택에 전달합니다). 쉽게 수행되지만 모델 수준에서이를 갖는 것이 더 건조합니다. 모델의 저장 방법을 무시하는 것은 잘못된 선택이 통과되는 것을 방지하는 좋은 방법으로 보입니다.

업데이트
다른 방법으로 나중에 답변을 참조하십시오 https://stackoverflow.com/a/3753916/202168

대안적인 접근법은 부모 모델의 필드로서 'favouritechild'FK를 갖지 않는 것입니다.

대신 아이에게 IS_FAVOURITE 부울 필드를 가질 수 있습니다.

이것은 도움이 될 수 있습니다 :https://github.com/anentropic/django-excluctionbooleanfield

그렇게하면 자녀가 자신이 속한 부모가 가장 좋아하는 것으로 만들 수 있도록하는 모든 문제를 회피 할 수 있습니다.

보기 코드는 약간 다르지만 필터링 로직은 간단합니다.

관리자에서는 IS_FAVOURITE Checkbox (부모당 몇 명의 자녀 만있는 경우)에 노출 된 아동 모델에 대한 인라인을 가질 수도 있습니다. 그렇지 않으면 관리자는 자녀의 측면에서 수행해야합니다.

from django.contrib import admin
from sopin.menus.models import Restaurant, DishType

class ObjInline(admin.TabularInline):
    def __init__(self, parent_model, admin_site, obj=None):
        self.obj = obj
        super(ObjInline, self).__init__(parent_model, admin_site)

class ObjAdmin(admin.ModelAdmin):

    def get_inline_instances(self, request, obj=None):
        inline_instances = []
        for inline_class in self.inlines:
            inline = inline_class(self.model, self.admin_site, obj)
            if request:
                if not (inline.has_add_permission(request) or
                        inline.has_change_permission(request, obj) or
                        inline.has_delete_permission(request, obj)):
                    continue
                if not inline.has_add_permission(request):
                    inline.max_num = 0
            inline_instances.append(inline)

        return inline_instances



class DishTypeInline(ObjInline):
    model = DishType

    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        field = super(DishTypeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
        if db_field.name == 'dishtype':
            if self.obj is not None:
                field.queryset = field.queryset.filter(restaurant__exact = self.obj)  
            else:
                field.queryset = field.queryset.none()

        return field

class RestaurantAdmin(ObjAdmin):
    inlines = [
        DishTypeInline
    ]
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top