2013-10-02 12 views
8

Sto usando factory_boy per creare fixture di prova. Ho due semplici fabbriche, supportate dai modelli SQLAlchemy (semplificato di seguito).Evitare duplicati con factory_boy factory

Mi piacerebbe essere in grado di chiamare AddressFactory.create() più volte, e farlo creare un Country se non esiste già, altrimenti voglio riutilizzare il record esistente.

class CountryFactory(factory.Factory): 
    FACTORY_FOR = Country 

    cc = "US" 
    name = "United States" 


class AddressFactory(factory.Factory): 
    FACTORY_FOR = Address 

    name = "Joe User" 
    city = "Seven Mile Beach" 
    country = factory.SubFactory(CountryFactory, cc="KY", name="Cayman Islands") 

La mia domanda è: come posso configurare queste fabbriche in modo che factory_boy non tenta di creare un nuovo Paese ogni volta che si crea un indirizzo?

+0

Hai un'occhiata a [factory.alchemy] (https://github.com/rbarrois/factory_boy/blob/master/factory /alchemy.py)? – javex

+0

Non sai a cosa ti riferisci in quel collegamento; non c'è niente in quel file specifico che sembra utile. Ho esaminato i documenti per factory_boy e lo SQLAlchemy factory in particolare, ma non ho visto nulla sul riutilizzo dei record. Fondamentalmente cercando una funzionalità di tipo "trova o crea". –

+0

Dopo una ricerca più approfondita, la risposta breve è che non puoi farlo. C'è il supporto per [get-or-create con i modelli Django] (https://factoryboy.readthedocs.org/en/latest/orms.html#factory.django.DjangoModelFactory.FACTORY_DJANGO_GET_OR_CREATE), ma non SQLAlchemy. Sto lasciando questa domanda aperta perché spero di aggiungere il supporto SQLAlchemy per questo uno di questi giorni se nessuno mi picchia. –

risposta

4

Nell'ultimo fabbrica-boy == 2.3.1 è possibile aggiungere FACTORY_DJANGO_GET_OR_CREATE

class CountryFactory(factory.django.DjangoModelFactory): 
    FACTORY_FOR = 'appname.Country' 
    FACTORY_DJANGO_GET_OR_CREATE = ('cc',) 

    cc = "US" 
    name = "United States" 

Supponendo campo cc è l'identificatore univoco.

+0

Come ho accennato nella mia domanda e nel commento di follow-up di cui sopra, sto usando SQLAlchemy. So che questo esiste per Django, ma questo non mi aiuta. La funzionalità che sto cercando non esiste nel factory boy e non ho ancora avuto il tempo di aggiungerla da sola. –

2

Mentre hai ragione che non c'è get_or_create funzione per le fabbriche SQLAlchemy basati, se esistono già gli oggetti che si desidera utilizzare come chiave esterna, si può scorrere attraverso di loro:

http://factoryboy.readthedocs.org/en/latest/recipes.html#choosing-from-a-populated-table

Così immaginabilmente potresti hackerare una soluzione nella tua fabbrica usando un attributo lazy che controlla prima se l'oggetto esiste nel db, e se così usa questo metodo per iterare attraverso di loro, ma se l'oggetto non esiste, chiama un SubFactory per creare prima l'oggetto.

+0

Questa è sicuramente una soluzione hacky, molto meglio se hai inviato un PR aggiungendo l'abilità get_or_create per SQLAlchemy ;-) –

0

Un'altra soluzione hacky consiste nel sovrascrivere il metodo create della fabbrica in modo che l'oggetto venga ricercato effettuando una query e memorizzando nella cache i risultati.

Questo semplice esempio non fa alcun filtro sulla **kwargs però:

class StaticFactory(SQLAlchemyModelFactory):       

    counter = 0              
    cache = []              
    model = None              

    @classmethod              
    def create(cls, **kwargs):          
     if not cls.cache:           
      cls.cache = your_session.query(cls.model).all()  
     instance = cls.cache[cls.counter]       
     cls.counter = (cls.counter + 1) % len(cls.cache)    
     return instance            
Problemi correlati