Issue: Proxy for Metadata's `schema` field?
Author: rmoretto
State: closed
Created: 2019-11-21 18:26:21

Hello,

I'm trying to replicate the `DatabaseProxy` behavior but with the `Model._meta.schema` property. I need to define the name of the schema with the `DatabaseProxy` initialization, but I'm failing miserably.

I basically have a factory for base models that go basically like:
```python
# util.py
import peewee

def base_model_factory(model_database):
    class BaseModel(peewee.Model):
        class Meta:
            database = model_database

    return BaseModel
```

The models definitions:
```python
# models.py
import peewee

db_proxy = peewee.DatabaseProxy()
BaseModel = base_model_factory(db_proxy)

def initialize_database(database, schema):
    db_proxy.initialize(database)
    BaseModel._meta.schema = schema

class MyModel(BaseModel):
    id = peewee.AutoField()
```

And the usage:
```python
# app.py
import util
import models
import peewee

def main():
    db = peewee.PostgresqlDatabase("my_db")
    schema = "my_schema"
    models.initialize_database(db, schema)
    
    print(models.MyModel._meta.schema)  # None
```

When I import the `utils` module the `MyModel` is defined with no schema, so the line `BaseModel._meta.schema = schema` has basically no effect, as the `MyModel` was already defined. 

I could on the `initialize_database` add a line with the `MyModel._meta.schema = schema` but I would need to do that for all my models, and some of those models are divided into multiple modules, which I believe could bring some problems(?).

Is there any way of doing this initialization in a less stupid way? Or should I just bite the bullet and define explicitly the schema for all my models in the `initialize_database` function?

Thank in advance.







Well, I think you could probably get rid of your `get_base_model()` function, as it seems redundant given that you're already using a proxy for your database. That doesn't address the issue, but in your example it's really not doing anything but adding an unnecessary layer of misdirection.

Now to the crux of the issue: certain model metadata attributes *are* inheritable ([see table in [documentation](http://docs.peewee-orm.com/en/latest/peewee/models.html#model-options-and-table-metadata)). However, model metadata is set at class-creation time and after that, the attributes on one model instance are not connected to the "parent" metadata.

So what you would need to do is apply the schema across all your models. For a more advanced usage, you can specify a custom model metadata implementation -- and then use the built-in `SubclassAwareMetadata` -- which tracks subclasses. You could then override the `schema` setter to propagate to all subclasses. This is a fairly advanced usage, though, but it is do-able.

```python

class SchemaPropagateMetadata(SubclassAwareMetadata):
    @property
    def schema(self):
        return self._schema
    @schema.setter
    def schema(self, value):
        # self.models is essentially a singleton shared by all models
        # that use this metadata class.
        for model in self.models:
            model._meta._schema = value

class BaseModel(Model):
    class Meta:
         database = db
         model_metadata_class = SchemaPropagateMetadata

# Now settings SomeModel._meta.schema will propagate the changes
# to every model that inherits from BaseModel.
```

Thank you very much, it worked like a charm!