在Django中复杂的“limit_choices_to”函数

时间:2021-07-26 02:37:13

I have Django database with 2 models: DeviceModel and Device. Let's say, for example, DeviceModel object is "LCD panel" and Device object is "LCD panel №547". So these two tables have ManyToOne relationship.

我有Django数据库,有两个模型:DeviceModel和Device。例如,假设DeviceModel对象“LCD面板”和设备对象是“LCD面板№547”。这两个表有很多对一的关系。

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

class Device(models.Model):
    device_model = models.ForeignKey(DeviceModel)
    serial_number = models.CharField(max_length=255)

Now I need to add some relations between DeviceModel objects. For example "LCD Panel" can be in "Tablet" object or in "Monitor" object. Also another object can be individual, so it doesn't link with other objects.

现在我需要添加一些DeviceModel对象之间的关系。例如,“LCD面板”可以在“Tablet”对象中,也可以在“Monitor”对象中。另外一个对象可以是单独的,所以它不会与其他对象链接。

I decided to do this with ManyToMany relationship, opposed to using serialization with JSON or something like that (btw, which approach is better in what situation??).

我决定使用ManyToMany关系来实现这一点,而不是使用JSON之类的序列化(顺便说一句,在什么情况下哪种方法更好?)

I filled all relationships between device models and know I need to add relationship functional to Device table.

我填充了设备模型之间的所有关系,并知道我需要向设备表添加关系函数。

For that purpose I added "master_dev" foreignkey field pointing to 'self'. It works exactly as I need, but I want to restrict output in django admin panel. It should display only devices, that are connected through device_links. Current code:

为此,我添加了“master_dev”外键字段,指向“self”。它完全按照我的需要工作,但是我想限制django管理面板的输出。它应该只显示通过device_links连接的设备。当前代码:

class DeviceModel(models.Model):
    name = models.CharField(max_length=255)
    device_links = models.ManyToManyField('self')

class Device(models.Model):
    device_model = models.ForeignKey(DeviceModel)
    serial_number = models.CharField(max_length=255)
    master_dev = models.ForeignKey('self', blank=True, null=True)

So, how can I limit output of master_dev field in admin panel? There is a function "limit_choices_to", but I can't get it to work...

那么,如何在管理面板中限制master_dev字段的输出呢?有一个函数“limit_choices_to”,但我不能让它工作…

2 个解决方案

#1


1  

in forms.py:

在forms.py:

def master_dev_chioses():
    chioses = DeviceModel.objects.filter(do your connection filter here - so not all Devicemodels comes to choicefield)


class DeviceForm(forms.ModelForm):
    class Meta:
        model = Device

    def __init__(self, *args, **kwargs):
        super(Device, self).__init__(*args, **kwargs)

        self.fields['master_dev'].choices = master_dev_chioses()

#2


0  

While there is no direct answer to my question about "limit_choices_to" function, I post solution that achieves desired output:

虽然我关于“limit_choices_to”函数的问题没有直接的答案,但我发布的解决方案实现了所需的输出:

from django import forms
from django.contrib import admin
from .models import DeviceModel, Device

class DeviceForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(DeviceForm, self).__init__(*args, **kwargs)
        try:
            linked_device_models = self.instance.device_model.device_links.all()
            linked_devices = Device.objects.filter(device_model__in=linked_device_models)

            required_ids = set(linked_devices.values_list("id", flat=True))

            self.fields['master_dev'].queryset = Device.objects.filter(id__in=required_ids).order_by("device_model__name", "serial_number")         
        except:
            # can't restrict masters output if we don't know device yet
            # admin should edit master_dev field only after creation

            self.fields['master_dev'].queryset = Device.objects.none()


    class Meta:
        model = Device
        fields = ["device_model", "serial_number", "master_dev"]


class DeviceAdmin(admin.ModelAdmin):
    form = DeviceForm

    list_display = ('id', 'device_model', 'serial_number')
    list_display_links = ('id', 'device_model')
    search_fields = ('device_model__name', 'serial_number')
    list_per_page = 50
    list_filter = ('device_model',)

#1


1  

in forms.py:

在forms.py:

def master_dev_chioses():
    chioses = DeviceModel.objects.filter(do your connection filter here - so not all Devicemodels comes to choicefield)


class DeviceForm(forms.ModelForm):
    class Meta:
        model = Device

    def __init__(self, *args, **kwargs):
        super(Device, self).__init__(*args, **kwargs)

        self.fields['master_dev'].choices = master_dev_chioses()

#2


0  

While there is no direct answer to my question about "limit_choices_to" function, I post solution that achieves desired output:

虽然我关于“limit_choices_to”函数的问题没有直接的答案,但我发布的解决方案实现了所需的输出:

from django import forms
from django.contrib import admin
from .models import DeviceModel, Device

class DeviceForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(DeviceForm, self).__init__(*args, **kwargs)
        try:
            linked_device_models = self.instance.device_model.device_links.all()
            linked_devices = Device.objects.filter(device_model__in=linked_device_models)

            required_ids = set(linked_devices.values_list("id", flat=True))

            self.fields['master_dev'].queryset = Device.objects.filter(id__in=required_ids).order_by("device_model__name", "serial_number")         
        except:
            # can't restrict masters output if we don't know device yet
            # admin should edit master_dev field only after creation

            self.fields['master_dev'].queryset = Device.objects.none()


    class Meta:
        model = Device
        fields = ["device_model", "serial_number", "master_dev"]


class DeviceAdmin(admin.ModelAdmin):
    form = DeviceForm

    list_display = ('id', 'device_model', 'serial_number')
    list_display_links = ('id', 'device_model')
    search_fields = ('device_model__name', 'serial_number')
    list_per_page = 50
    list_filter = ('device_model',)