Question

Is it possible to add a variable to Django Model Field.choices?

I lose functionality when I have to add it statically.

IP_CHOICES = (
    ('192.168.1.0', '192.168.1.0'),
)

ip_address = models.IPAddressField(choices=IP_CHOICES, unique=True, blank=True)

I use a Python IP Interpreter called IPy, to calculate the correct IP block.

ip = IP(self.network + slash)

for rangeip in enumerate(ip[2:-1]):

    IP_CHOICES = (
        ("%s" %rangeip, "%s" %rangeip)
    )

Is this possible? If so, please help. Been trying to hack it for the past week and got no where. Any help is appreciated.

Please view Model Class.

#IP Block Class
class IP_block(models.Model):

    network = models.IPAddressField(unique=True)
    slash = models.ForeignKey(Subnet, verbose_name='CIDR')
    subnet = models.CharField(max_length=64, blank=True)
    gateway_ip = models.CharField(max_length=64, blank=True)
    broadcast_ip = models.CharField(max_length=64, blank=True)
    ip_range = models.TextField(blank=True, verbose_name='Available IP Range')
    dslam = models.ManyToManyField(Dslam, verbose_name='Dslam', blank=True)

    #ip block and range save function


    def save(self, *args, **kwargs):

        slash = unicode(self.slash)

        broadcast = IP(self.network + slash).broadcast()
        subnet = IP(self.network+slash).strNetmask()

        self.broadcast_ip = broadcast
        self.subnet = subnet

        ip = IP(self.network + slash)

        for gateway in ip[1]:
            self.gateway_ip = gateway

        #rangeip for loop

        ip = IP(self.network + slash)


        if self.ip_range:
            print 'no override'

        else:

            for rangeip in ip[2:-1]:
                self.ip_range += "%s\n" %rangeip

                IP_CHOICE = "(%s" %rangeip + ", %s)," %rangeip

                #ip_list select 

                ip_list = models.CharField(choices=IP_CHOICE, max_length=128, blank=True)

        super(IP_block, self).save(*args, **kwargs)


    class Meta:
        verbose_name_plural = 'IP Blocks'

    def __unicode__(self):
        return self.network         
Was it helpful?

Solution

You have many fairly basic errors here. For example, in your suggested syntax:

for rangeip in enumerate(whatever):
    IP_CHOICES = (do_something)

It should be obvious to you that you are simply overwriting IP_CHOICES each time through the loop. At the end of the loop, it will simply have the value of the last iteration, which isn't by itself in a suitable format for choices.

You have this same pattern a number of times. Please think about what it is actually doing.

But there's an even worse error in your save function, where you have this line:

ip_list = models.CharField(choices=IP_CHOICE, max_length=128, blank=True)

I have absolutely no idea what you think that is doing. You can't define a field in the middle of a save method. You can set a field's value, but you can't suddenly define a new field (again, please think about it: how would that work with the database? And remember fields are class-level attributes: all instances of that model need to have the same field selection).

It's almost impossible to understand what you are actually trying to do. I think you are trying to provide a choice of IP addresses for one field in the model (ip_list), once the user has set the range in another field (ip_range). (It would have been useful if you'd stated that explicitly up front.)

The place to do this is in the form, not in the model. Setting choices on a model field is really just a shortcut to setting them on forms automatically created from that model, but if you need to do something dynamic you need to define the form yourself and put the logic there. I guess it would be something like this:

class IPBlockForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(IPForm, self).__init__(*args, **kwargs)
        if self.instance and self.instance.ip_range:
            ip_list_choices = get_ip_list_from_wherever(self.instance_ip_range)
            self.fields['ip_list'] = forms.ChoiceField(choices=ip_list_choices)

    class Meta:
        model = IP_block

But naturally you need to fix the other logic errors in your save method, which I mention above, first.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top