Cer*_*rin 12 python django django-admin
当使用raw_id_fields选项显示时,如何限制Django管理员中ForeignKey字段的显示选项?
当渲染为选择框时,可以很容易地定义自定义ModelForm,以便根据需要选择该字段的queryset值.但是,使用raw_id_fields呈现时,此查询集似乎完全被忽略.它生成一个指向ForeignKey模型的链接,允许您通过弹出窗口从该模型中选择任何记录.您仍然可以通过自定义URL来过滤这些值,但我找不到通过ModelAdmin执行此操作的方法.
我在Django 1.8/Python 3.4项目中使用类似于FSp的方法:
from django.contrib import admin
from django.contrib.admin import widgets
from django.contrib.admin.sites import site
from django import forms
class BlogRawIdWidget(widgets.ForeignKeyRawIdWidget):
def url_parameters(self):
res = super().url_parameters()
res['type__exact'] = 'PROJ'
return res
class ProjectAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['blog'].queryset = Blog.objects.filter(type='PROJ')
self.fields['blog'].widget = BlogRawIdWidget(rel=Project._meta.get_field('blog').remote_field, admin_site=site)
class Meta:
# Django 1.8 convenience:
fields = '__all__'
model = Project
class ProjectAdmin(admin.ModelAdmin):
form = ProjectAdminForm
raw_id_fields = ('blog',)
Run Code Online (Sandbox Code Playgroud)
在django.admin中只选择blog.type =='PROJ'作为外键Project.blog.因为最终用户可能会并且将会选择任何东西,不幸的是.
小智 6
The method below works for me but it is a queryset that affects every admin that needs to use the Customer model. But if you have another Admin, e.g. Invoice that requires a different queryset, you might want to experiment a bit with model proxy.
Model
class Customer(models.Model):
name = models.CharField(max_length=100)
is_active = models.BooleanField()
class Order(models.Model):
cust = models.ForeignKey(Customer)
Run Code Online (Sandbox Code Playgroud)
Admin
class CustomerAdmin(admin.ModelAdmin):
def queryset(self, request):
qs = super(CustomerAdmin, self).queryset(request)
return qs.filter(is_active=1)
class OrderAdmin():
raw_id_fields = ('cust', )
Run Code Online (Sandbox Code Playgroud)
ModelAdmin
对于实际项目,我发现给定的解决方案(自定义查询集)有点过于严格.
我的工作通常如下:
ModelAdmin
(例如子类admin.SimpleListFilter
,请参阅doc)创建我的widget子类,ForeignKeyRawIdWidget
如下所示:
class CustomRawIdWidget(ForeignKeyRawIdWidget):
def url_parameters(self):
"""
activate one or more filters by default
"""
res = super(CustomRawIdWidget, self).url_parameters()
res["<filter_name>__exact"] = "<filter_value>"
return res
Run Code Online (Sandbox Code Playgroud)
请注意,自定义小部件唯一做的是"预选"过滤器,而过滤器又负责"限制"查询集
使用自定义小部件:
class MyForm(forms.ModelForm):
myfield = forms.ModelChoiceField(queryset=MyModel.objects.all(),
...
widget=CustomRawIdWidget(
MyRelationModel._meta.get_field('myfield').rel,
admin.site))
Run Code Online (Sandbox Code Playgroud)此方法的一个弱点是窗口小部件选择的过滤器不会阻止从该模型中选择其他实例.如果需要,我重写该方法ModelAdmin.save_model(...)
(请参阅doc)以检查相关实例是否只是允许的实例.
我发现这种方法有点复杂,但比限制整个查询集要灵活得多ModelAdmin
.
小智 5
如果您需要根据模型实例过滤 raw_id list_view 弹出窗口,您可以使用下面的示例:
1. 编写自定义小部件
class RawIdWidget(widgets.ForeignKeyRawIdWidget):
def url_parameters(self):
res = super(RawIdWidget, self).url_parameters()
object = self.attrs.get('object', None)
if object:
# Filter variants by product_id
res['product_id'] = object.variant.product_id
return res
Run Code Online (Sandbox Code Playgroud)
2. 在表单初始化中传递实例
class ModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ModelForm, self).__init__(*args, **kwargs)
obj = kwargs.get('instance', None)
if obj and obj.pk is not None:
self.fields['variant'].widget = RawIdWidget(
rel=obj._meta.get_field('variant').rel,
admin_site=admin.site,
# Pass the object to attrs
attrs={'object': obj}
)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5193 次 |
最近记录: |