Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create trivial customized field types in Django models?

I'm trying to make some types in Django that map to standard Django types. The custom model field documentation goes into complicated cases; I just want to store a basic Django type from a class with a bunch of handy methods.

For example, if I were storing playing cards, I want something like:

class Card(object):
    """ A playing card.  """
    def as_number(self):
        """ returns a number from 1 (Ace of Clubs) and 52 (King of Spades)."""
        return self.number + self.suit_rank() * 13
    def __unicode(self): ...
    def is_highest(self, other_cards, trump=None):...
    def __init__(self, number, suit):  ...
     ...

I want my models to have something like:

class my_game(models.Model):
    ante = models.IntegerField()
    bonus_card = Card()   # Really stored as an models.IntegerField()
    ....

I'm expecting the answer will look like inheriting from the correct type, adding some specially named get/store fields for card, and renaming init(). Does anyone have sample code or better documentation?

like image 207
Charles Merriam Avatar asked Dec 17 '25 16:12

Charles Merriam


1 Answers

I'd do this with a subclass of Django's PositiveIntegerField:

from django.db import models

class Card(object):
    """The ``Card`` class you described."""
    ...

class CardField(models.PositiveIntegerField):
    __metaclass__ = models.SubfieldBase

    def get_db_prep_value(self, value):
        """Return the ``int`` equivalent of ``value``."""
        if value is None: return None
        try:
            int_value = value.as_number()
        except AttributeError:
            int_value = int(value)
        return int_value

    def to_python(self, value):
        """Return the ``Card`` equivalent of ``value``."""
        if value is None or isinstance(value, Card):
            return value
        return Card(int(value))

The get_db_prep_value method is responsible for converting value into something suitable for interacting with the database, in this case either an int or None.

The to_python method does the reverse, converting value into a Card. Just like before, you'll need to handle the possibility of None as a value. Using the SubfieldBase ensures that to_python is called every time a value is assigned to the field.

like image 129
jpwatts Avatar answered Dec 20 '25 09:12

jpwatts



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!