U SW@sdZddlTddlmZddlmZddlmZddlmZddlmZe Z iZ Gdd d eZGd d d eeeZd d Z Gddde ZGddde ZGddde ZdS)a Provide a "Generic ForeignKey", similar to Django. A "GFK" is composed of two columns: an object ID and an object type identifier. The object types are collected in a global registry (all_models), so all you need to do is subclass ``gfk.Model`` and your model will be added to the registry. Example: class Tag(Model): tag = CharField() object_type = CharField(null=True) object_id = IntegerField(null=True) object = GFKField('object_type', 'object_id') class Blog(Model): tags = ReverseGFK(Tag, 'object_type', 'object_id') class Photo(Model): tags = ReverseGFK(Tag, 'object_type', 'object_id') tag.object -> a blog or photo blog.tags -> select query of tags for ``blog`` instance Blog.tags -> select query of all tags for Blog instances )*) BaseModel)Model) SelectQuery) UpdateQuery)with_metaclasscseZdZfddZZS)rcs,tt|||||}|dkr(t||S)N)Z_metaclass_helper_r)superr__new__ all_modelsadd)clsnamebasesZattrs __class__/gfk.pyr 's zBaseModel.__new__)__name__ __module__ __qualname__r __classcell__rrrrr&src@s eZdZdS)rN)rrrrrrrr-srcCs4|tkr*tD]}|jj|kr |t|<q*q t|SN) table_cacher _metadb_tableget)tbl_namemodelrrr get_model0s  rc@s@eZdZdZddZeddZeddZdd Zd d Z d S) BoundGFKField model_class gfk_fieldcCs||_||_dSrr )selfr!r"rrr__init__;szBoundGFKField.__init__cCsB|jjj}t|jj|jjf}|D]\}}|t|s"dSq"dSNTF)r!rindexessetr"model_type_fieldmodel_id_field)r#r&fieldsZindexed_columnsZ is_uniquerrrunique?s   zBoundGFKField.uniquecCs>|jjj}t|tr:t|jj|jjf}|t|j s:dSdSr%) r!r primary_key isinstanceZ CompositeKeyr'r"r(r) field_names)r#Zpkr*rrrr,Is  zBoundGFKField.primary_keycCs<|jj}|j|jj}|j|jj}||jjk||k@Sr)r!rr*r"r(r)r _get_pk_value)r#othermeta type_fieldid_fieldrrr__eq__Ss  zBoundGFKField.__eq__cCs@t|}|jj|jj}|jj|jj}||jjk||k@Sr)typerr*r"r(r)rr/)r#r0Z other_clsr2r3rrr__ne__[s  zBoundGFKField.__ne__N) rrr __slots__r$propertyr+r,r4r6rrrrr8s  rc@s0eZdZd ddZddZd dd Zd d ZdS)GFKField object_type object_idcCs$||_||_d|j|jf|_dS)N.)r(r)joinatt_name)r#r(r)rrrr$eszGFKField.__init__cCsh|j}||jrd||jrd||j}t|}|s@td|||jj ||jk}|SdS)Nz-Model for table "%s" not found in GFK lookup.) _datarr(r)rAttributeErrorselectwhererr,)r#instancedatarr!Zqueryrrrget_objks zGFKField.get_objNcCsB|r8|j|jkr*||}|r*||j|j<|j|jSt||Sr)r> _obj_cacherErr)r#rC instance_typeZrel_objrrr__get__ws   zGFKField.__get__cCs0||j|j<|jj|j|j<||j|j<dSr)rFr>rrr?r(r/r))r#rCvaluerrr__set__s zGFKField.__set__)r:r;)N)rrrr$rErHrJrrrrr9ds   r9c@s(eZdZd ddZd ddZdd ZdS) ReverseGFKr:r;cCs&||_|jj||_|jj||_dSr)r!rr*r(r))r#rr(r)rrrr$szReverseGFK.__init__NcCsJ|r,|j|j|jjk|j|k@S|j|j|jjkSdSr)r!rArBr(rrr)r/)r#rCrGrrrrHs     zReverseGFK.__get__cs|jj}|}t|trL|jjkrLtjj|j|i |j  nVt t fdd|r|D],}t|jj|t|jj||qfn td|dS)Ncs t|jSr)r-r!)ir#rrz$ReverseGFK.__set__..z&ReverseGFK field unable to handle "%s")rrr/r-rr!rr(r)rBZ_whereZexecuteallmapsetattrr Zsave ValueError)r#rCrIZmtvZmivobjrrMrrJs&    zReverseGFK.__set__)r:r;)N)rrrr$rHrJrrrrrKs   rKN)__doc__ZpeeweerZ _BaseModelrZ_Modelrrrr'r rrobjectrr9rKrrrrs     ,"