2012-12-29 17 views
8

Sono abbastanza nuovo per Python e Django, e totalmente nuovo su Stack Overflow, quindi spero di non infrangere alcuna regola qui e rispettando il formato della domanda.Campi del modello personalizzato di Django: to_python() non chiamato

Sto affrontando un problema nel tentativo di implementare un campo modello personalizzato con Django (Python 3.3.0, Django 1.5a1), e non ho trovato argomenti simili, in realtà sono piuttosto bloccato su questo ...

Quindi c'è un giocatore, ha una mano (di carta). La mano eredita da CardContainer, che è fondamentalmente un elenco di carte con alcune funzioni di aiuto (nascoste qui). Ecco il codice corrispondente:

from django.db import models 


class Card: 
    def __init__(self, id): 
     self.id = id 


class CardContainer: 
    def __init__(self, cards=None): 
     if cards is None: 
      cards = [] 
     self.cards = cards 


class Hand(CardContainer): 
    def __init__(self, cards=None): 
     super(Hand, self).__init__(cards) 


class CardContainerField(models.CommaSeparatedIntegerField): 
    __metaclass__ = models.SubfieldBase 

    def __init__(self, cls, *args, **kwargs): 
     if not issubclass(cls, CardContainer): 
      raise TypeError('{} is not a subclass of CardContainer'.format(cls)) 

     self.cls = cls 
     kwargs['max_length'] = 10 
     super(CardContainerField, self).__init__(*args, **kwargs) 

    def to_python(self, value): 
     if not value: 
      return self.cls() 

     if isinstance(value, self.cls): 
      return value 

     if isinstance(value, list): 
      return self.cls([i if isinstance(i, Card) else Card(i) for i in value]) 

     # String: '1,2,3,...' 
     return self.cls([Card(int(i)) for i in value.split(',')]) 

    def get_prep_value(self, value): 
     if value is None: 
      return '' 

     return ','.join([str(card.id) for card in value.cards]) 


class Player(models.Model): 
    hand = CardContainerField(Hand) 

Ma quando ho un giocatore, consente di dire, in questo modo: (! O anche un'istanza CardContainer a tutti) Player.objects.get(id=3).hand, invece di ottenere un'istanza Hand, sto solo diventando una stringa separata da virgola di interi come "1,2,3", che va bene nel database (è il formato che mi piacerebbe vedere nel database) ...

Mi sembra che to_python non viene chiamato, quindi i dati restituiti sono il valore grezzo, quindi la stringa. Quando ho cercato questo tipo di problemi, la gente ha perso il __metaclass__ = models.SubfieldBase ... Speravo di aver perso anche quello, ma, ehi, sarebbe stato troppo semplice! Mi sono perso qualcosa di banale, o sbaglio per tutto? : D

Grazie mille !!

risposta

10

In python 3 la variabile globale modulo __metaclass__ non è più supportata. È necessario utilizzare:

class CardContainerField(models.CommaSeparatedIntegerField, metaclass=models.SubfieldBase): 
    ... 
+0

Wow, grazie, ho completamente non sapevo che !! Penso che il risultato silenzioso che crea sia piuttosto fastidioso, e ho presentato un [ticket] (https://code.djangoproject.com/ticket/19539) per la documentazione (come Django supporta Python 3, penso che il documento dovrebbe menzionare quella). – astorije

0

per Django 1.10 e l'ultima

class CardContainerField(models.CommaSeparatedIntegerField): 
    def from_db_value(self,value, expression, connection, context): 
     ....... 
Problemi correlati