Issue: BlobField cannot be used with uninitialized Proxy
Author: vkrizan
State: closed
Created: 2016-05-11 14:53:51

BlobField determines its binary type on its initialization. BlobField then cannot be used with Proxied database that is not initialized. An `AttributeError` is risen right after module execution/import.

Reproducer:

```
import peewee

class NonWorkingBlobFieldOnProxy(peewee.Model):
    class Meta:
        database = peewee.Proxy()
    myblob = peewee.BlobField()
```

Raises:

```
Traceback (most recent call last):
  File "proxy_example.py", line 3, in <module>
    class NonWorkingBlobFieldOnProxy(peewee.Model):
  File "venv/lib/python2.7/site-packages/peewee.py", line 4479, in __new__
    field.add_to_class(cls, name)
  File "venv/lib/python2.7/site-packages/peewee.py", line 1081, in add_to_class
    self._constructor = model_class._meta.database.get_binary_type()
  File "venv/lib/python2.7/site-packages/peewee.py", line 407, in __getattr__
    raise AttributeError('Cannot use uninitialized Proxy.')
AttributeError: Cannot use uninitialized Proxy.
```

This affects version 2.8.1. In later versions (2.6.X) this problem did not occur.
Commit that introduced this regression: b32e967e


Nice catch and fantastic issue report. I'll work on a solution.


Thank you. I resolved it with lazy imports, right after Proxy initialization.


The proxy should have a way to attach callbacks if I remember correctly, so I just need to move the binary type binding to a hook. I'll fix it regardless, but glad you're not blocked at the moment.


@coleifer I've run into an almost identical issue. Let me know if this should be its own issue.

Name: peewee
Version: 3.14.8 causes this issue with bind_ctx.

If I use bind instead of bind_ctx, this works fine, however I ultimately need bind_ctx to work. 

```python
db=SqliteDatabase(None, pragmas={'journal_mode': 'wal',
                                 'cache_size': -1 * 64000,  # 64MB
                                 'foreign_keys': 1,
                                 'ignore_check_constraints': 0,
                                 'synchronous': 0})
database_proxy=DatabaseProxy()

class SomeModel(Model):
    some_id_field=AutoField()
    image_data=BlobField()
    
    class Meta: 
        database=database_proxy
    
SomeModel()

db_path='test_data/peewee.pb'

with db.bind_ctx([SomeModel]):
    db.init(db_path)
    db.create_tables([SomeModel])
    db.close()
```
Outputs:
```bash
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/tmp/ipykernel_102/1075978240.py in <module>
     22     db.init(db_path)
     23     db.create_tables([SomeModel])
---> 24     db.close()

/opt/conda/lib/python3.9/site-packages/peewee.py in __exit__(self, exc_type, exc_val, exc_tb)
   6291     def __exit__(self, exc_type, exc_val, exc_tb):
   6292         for model, db in zip(self.models, self._orig_database):
-> 6293             model.bind(db, self.bind_refs, self.bind_backrefs,
   6294                        _exclude=set(self.models))
   6295 

/opt/conda/lib/python3.9/site-packages/peewee.py in bind(cls, database, bind_refs, bind_backrefs, _exclude)
   6687     def bind(cls, database, bind_refs=True, bind_backrefs=True, _exclude=None):
   6688         is_different = cls._meta.database is not database
-> 6689         cls._meta.set_database(database)
   6690         if bind_refs or bind_backrefs:
   6691             if _exclude is None:

/opt/conda/lib/python3.9/site-packages/peewee.py in set_database(self, database)
   6124         # Apply any hooks that have been registered.
   6125         for hook in self._db_hooks:
-> 6126             hook(database)
   6127 
   6128     def set_table_name(self, table_name):

/opt/conda/lib/python3.9/site-packages/peewee.py in _db_hook(self, database)
   4761             self._constructor = bytearray
   4762         else:
-> 4763             self._constructor = database.get_binary_type()
   4764 
   4765     def bind(self, model, name, set_attribute=True):

/opt/conda/lib/python3.9/site-packages/peewee.py in __getattr__(self, attr)
    446     def __getattr__(self, attr):
    447         if self.obj is None:
--> 448             raise AttributeError('Cannot use uninitialized Proxy.')
    449         return getattr(self.obj, attr)
    450 
AttributeError: Cannot use uninitialized Proxy.
```
### My opinion:
Seems like on exit, when switching back to the Proxy, it tries getting the binary type.
We could fix this by converting:
```python
# BlobField...
    def _db_hook(self, database):
        if database is None:
            self._constructor = bytearray
        else:
            self._constructor = database.get_binary_type()
```
to
```python
# BlobField...
    def _db_hook(self, database):
        if database is None or isinstance(database, Proxy):
            self._constructor = bytearray
        else:
            self._constructor = database.get_binary_type()
```




@josiahlaivins - see 13e05a3 for fix.