具有上游ForeignKey字段的OneToOneField上的Django limit_choices_to

时间:2014-07-14 17:07:00

标签: python django

我正在尝试使用" limit_choices_to" Django OneToOneField中的功能,我想限制选择的上游是另一个ForeignKey。我在管理员中设置的错误是:

invalid literal for int() with base 10: 'Storage Array'

我认为这是因为它正在查看asset_type列中的实际值,它是一个整数外键。我需要能够根据外键的字段值而不是键值本身来限制选择。

基本上我要完成的是让管理区域(和其他表单)只允许您在添加新资产时选择有效的资产类型。例如,如果我要添加"存储阵列"与之关联的上游资产应该只允许为存储阵列的asset_type。

这是我的模特:

from django.db import models
from localflavor.us.us_states import STATE_CHOICES

# Table of brand names of assets
class Brand(models.Model):
    brand = models.CharField(max_length=128, unique=True)

    def __unicode__(self):
        return self.brand

# Table of device types for assets, e.g. "Storage Array"
class Device(models.Model):
    device_type = models.CharField(max_length=128, unique=True)
    device_url_slug = models.SlugField(max_length=70, unique=True)

    class Meta:
        verbose_name = "device type"
        verbose_name_plural = "device types"

    def __unicode__(self):
        return self.device_type

# Table of asset locations
class Location(models.Model):
    site_name = models.CharField(max_length=128, unique=True)
    site_nick = models.CharField(max_length=5, unique=True)
    address_line_one = models.CharField(max_length=256)
    address_line_two = models.CharField(max_length=256, null=True, blank=True)
    address_city = models.CharField(max_length=32)
    address_state = models.CharField(max_length=2, choices=STATE_CHOICES, null=True, blank=True)
    address_zip = models.CharField(max_length=5)

    def __unicode__(self):
        return self.site_name

# Table of Environments, e.g. "Production"
class Environment(models.Model):
    environment = models.CharField(max_length=128, unique=True)

    def __unicode__(self):
        return self.environment

class Credentials(models.Model):
    AUTH_CHOICES = (
        ('SSH', 'Standard SSH'),
        ('SSH-Key', 'SSH with Key-based login'),
        ('HTTP', 'Standard HTTP'),
        ('HTTPS', 'Secure HTTP'),
        ('API', 'API Based'),
        ('SNMP', 'SNMP Based'),
    )

    SNMP_VERSIONS = (
        ('v1', 'SNMP v1'),
        ('v3', 'SNMP v3'),
    )

    auth_method = models.CharField(max_length=32, choices=AUTH_CHOICES)
    auth_username = models.CharField(max_length=32)
    auth_password = models.CharField(max_length=32, null=True, blank=True)
    auth_snmp_version = models.CharField(max_length=2, choices=SNMP_VERSIONS, null=True, blank=True)
    auth_snmp_community = models.CharField(max_length=128, null=True, blank=True)

    class Meta:
        verbose_name = "credentials"
        verbose_name_plural = "credentials"

    def __unicode__(self):
        return self.auth_method

class Asset(models.Model):
    asset_name = models.CharField(max_length=128, unique=True)
    asset_type = models.ForeignKey(Device)
    brand = models.ForeignKey(Brand)
    model = models.CharField(max_length=128)
    serial = models.CharField(max_length=256)
    location = models.ForeignKey(Location)
    environment = models.ForeignKey(Environment)
    datacenter_room = models.CharField(max_length=32, null=True, blank=True)
    grid_location = models.CharField(max_length=32, null=True, blank=True)
    mgmt_address = models.CharField(max_length=128)
    notes = models.TextField(null=True, blank=True)

    def __unicode__(self):
        return self.asset_name

class StorageArray(models.Model):
    OS_NAME_CHOICES = (
        ('Data OnTap', 'NetApp Data OnTap'),
    )

    OS_TYPE_CHOICES = (
        ('7-Mode', 'NetApp 7-Mode'),
        ('cDOT', 'NetApp Clustered'),
    )

    HA_TYPE_CHOICES = (
        ('Standalone', 'Standalone System'),
        ('HA Pair', 'HA Pair'),
        ('Clustered', 'Clustered'),
    )

    asset = models.OneToOneField(Asset, primary_key=True, limit_choices_to={'asset_type': 'Storage Array'})
    os_name = models.CharField(max_length=32, choices=OS_NAME_CHOICES, null=True, blank=True)
    os_version = models.CharField(max_length=16, null=True, blank=True)
    os_type = models.CharField(max_length=16, choices=OS_TYPE_CHOICES, null=True, blank=True)
    array_ha_type = models.CharField(max_length=32, choices=HA_TYPE_CHOICES, null=True, blank=True)
    array_partner = models.CharField(max_length=128, null=True, blank=True)
    credentials = models.ForeignKey(Credentials, null=True, blank=True)

    class Meta:
        verbose_name = "storage array"
        verbose_name_plural = "storage arrays"

    def __unicode__(self):
        return self.asset.asset_name

class SANSwitch(models.Model):
    OS_NAME_CHOICES = (
        ('FabricOS', 'Brocade FabricOS'),
    )

    SWITCH_TYPE_CHOICES = (
        ('Standalone', 'Standalone Switch'),
        ('Director', 'Director'),
        ('Router', 'Multiprotocol Router'),
        ('Blade', 'Blade Chassis IO Module'),
    )

    SWITCH_ROLE_CHOICES = (
        ('Core', 'Core'),
        ('Edge', 'Edge'),
        ('AG', 'Access Gateway'),
    )


    asset = models.OneToOneField(Asset, primary_key=True, limit_choices_to={'asset_type': 'SAN Switch'})
    os_name = models.CharField(max_length=32, choices=OS_NAME_CHOICES, null=True, blank=True)
    os_version = models.CharField(max_length=16, null=True, blank=True)
    switch_type = models.CharField(max_length=32, choices=SWITCH_TYPE_CHOICES, null=True, blank=True)
    switch_role = models.CharField(max_length=32, choices=SWITCH_ROLE_CHOICES, null=True, blank=True)
    credentials = models.ForeignKey(Credentials, null=True, blank=True)

    class Meta:
        verbose_name = "san switch"
        verbose_name_plural = "san switches"

    def __unicode__(self):
        return self.asset.asset_name

1 个答案:

答案 0 :(得分:3)

我自己解决了这个问题!

似乎可以进一步转化为可以使用python / django内置的double underscore notation的关系。

解决我的问题:

asset = models.OneToOneField(Asset, primary_key=True, limit_choices_to={'asset_type': 'Storage Array'})

成为:

asset = models.OneToOneField(Asset, primary_key=True, limit_choices_to={'asset_type__device_type': 'Storage Array'})