当前位置:  开发笔记 > 编程语言 > 正文

如何仅在django中将外键选择限制为相关对象

如何解决《如何仅在django中将外键选择限制为相关对象》经验,为你挑选了5个好方法。

我有一个类似于以下的双向外国关系

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)

如何将Parent.favoritechild的选择仅限于父母本身的子女?我试过了

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

但这会导致管理界面不列出任何子项.



1> Ber..:

我刚刚在Django文档中遇到了ForeignKey.limit_choices_to.不确定这是如何工作的,但它可能只是正确的事情.

更新: ForeignKey.limit_choices_to允许指定常量,可调用或Q对象,以限制键的允许选择.一个常数显然在这里没用,因为它对所涉及的对象一无所知.

使用可调用(函数或类方法或任何可调用对象)似乎更有希望.但是,如何从HttpRequest对象访问必要信息的问题仍然存在.使用线程本地存储可能是一种解决方案.

2.更新:以下是对我有用的内容:

我创建了一个中间件,如上面的链接所述.它从请求的GET部分中提取一个或多个参数,例如"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,则返回包含所有可能ID的查询非常重要,这样正常的管理页面才能正常工作.

然后将外键字段声明为:

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

问题在于您必须提供信息以通过请求限制选择.我没有看到在这里访问"自我"的方法.


在上面的例子中没有使用实际的线程,它只是使用threadlocals来模拟更广泛的范围.您可以使用存储在Model类或其他任何具有足够宽的范围以便在两个位置访问的值来等效地执行此操作.
@miraculixx我实际上在时间的文档中找到了这个(必须在1.0版本左右).现在我已经回到了未来:)

2> s29..:

"正确"的方法是使用自定义表单.从那里,您可以访问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



3> 小智..:

这种新的"正确"方式,至少在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)

我只是不确定如何获取正在编辑的当前对象.我希望它实际上是在某个地方,但我不确定.



4> 小智..:

这不是django的工作方式.你只会以一种方式创建关系.

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字段中设置了related_name,那么您将其称为.例如:related_name='children'那么你会这样做parent_object.children.all()

阅读文档 http://docs.djangoproject.com/en/dev/topics/db/models/#many-to-one-relationships了解更多信息.



5> wasabigeek..:

如果您只需要Django管理界面中的限制,这可能会有效.我基于另一个论坛的答案 - 虽然它适用于ManyToMany关系,但你应该能够替换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)

推荐阅读
地之南_816
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有