|
| 1 | +--- |
| 2 | + |
| 3 | +# Model Converters |
| 4 | + |
| 5 | +Model Converters are special classes used to convert SQLAlchemy model properties into web interface form fields. They allow you to customize how backend SQLAlchemy models are represented in the admin interface, providing flexibility in handling different data types and validation rules. |
| 6 | + |
| 7 | +This page will guide you through the basics of using and customizing Model Converters. For advanced usage, refer to the [API Reference](./api_reference/model_converter.md). |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## Overview |
| 12 | + |
| 13 | +The `ModelConverter` class is the base class for converting SQLAlchemy model properties into form fields. It provides default conversions for common SQLAlchemy types (e.g., `String`, `Integer`, `JSON`) and allows you to customize or extend these conversions. |
| 14 | + |
| 15 | +### Base Model Converter |
| 16 | + |
| 17 | +The base `ModelConverter` class looks like this: |
| 18 | + |
| 19 | +```python |
| 20 | +class ModelConverter(ModelConverterBase): |
| 21 | + @staticmethod |
| 22 | + def _string_common(prop: ColumnProperty) -> list[Validator]: |
| 23 | + li = [] |
| 24 | + column: Column = prop.columns[0] |
| 25 | + if isinstance(column.type.length, int) and column.type.length: |
| 26 | + li.append(validators.Length(max=column.type.length)) |
| 27 | + return li |
| 28 | + |
| 29 | + @converts("String", "CHAR") # includes Unicode |
| 30 | + def conv_string( |
| 31 | + self, model: type, prop: ColumnProperty, kwargs: dict[str, Any] |
| 32 | + ) -> UnboundField: |
| 33 | + extra_validators = self._string_common(prop) |
| 34 | + kwargs.setdefault("validators", []) |
| 35 | + kwargs["validators"].extend(extra_validators) |
| 36 | + return StringField(**kwargs) |
| 37 | + |
| 38 | + @converts("Text", "LargeBinary", "Binary") # includes UnicodeText |
| 39 | + def conv_text( |
| 40 | + self, model: type, prop: ColumnProperty, kwargs: dict[str, Any] |
| 41 | + ) -> UnboundField: |
| 42 | + kwargs.setdefault("validators", []) |
| 43 | + extra_validators = self._string_common(prop) |
| 44 | + kwargs["validators"].extend(extra_validators) |
| 45 | + return TextAreaField(**kwargs) |
| 46 | +``` |
| 47 | + |
| 48 | +This class includes methods like `conv_string` and `conv_text` to handle specific SQLAlchemy types. You can extend this class to add custom behavior or override existing conversions. |
| 49 | + |
| 50 | +--- |
| 51 | + |
| 52 | +## Customizing Model Converters |
| 53 | + |
| 54 | +You can inherit from `ModelConverter` to create your own converter and customize how specific SQLAlchemy types are handled. For example, you can define a custom converter for `JSON` fields: |
| 55 | + |
| 56 | +```python |
| 57 | +from typing import Any |
| 58 | +import json |
| 59 | +from wtforms import JSONField |
| 60 | +from sqladmin import ModelConverter |
| 61 | + |
| 62 | + |
| 63 | +class CustomJSONField(JSONField): |
| 64 | + def _value(self) -> str: |
| 65 | + if self.raw_data: |
| 66 | + return self.raw_data[0] |
| 67 | + elif self.data: |
| 68 | + return str(json.dumps(self.data, ensure_ascii=False)) |
| 69 | + else: |
| 70 | + return "" |
| 71 | + |
| 72 | + |
| 73 | +class CustomModelConverter(ModelConverter): |
| 74 | + @converts("JSON", "JSONB") |
| 75 | + def conv_json(self, model: type, prop: ColumnProperty, kwargs: dict[str, Any]) -> UnboundField: |
| 76 | + return CustomJSONField(**kwargs) |
| 77 | +``` |
| 78 | + |
| 79 | +In this example: |
| 80 | +- `CustomJSONField` is a custom field that formats JSON data for display. |
| 81 | +- `CustomModelConverter` overrides the `conv_json` method to use `CustomJSONField` for `JSON` and `JSONB` SQLAlchemy types. |
| 82 | + |
| 83 | +--- |
| 84 | + |
| 85 | +## Using Custom Model Converters in Admin Views |
| 86 | + |
| 87 | +To use your custom model converter in the admin interface, specify it in your `ModelView` class: |
| 88 | + |
| 89 | +```python |
| 90 | +from sqladmin import ModelView |
| 91 | + |
| 92 | + |
| 93 | +class BaseAdmin(ModelView): |
| 94 | + form_converter: ClassVar[Type[CustomModelConverter]] = CustomModelConverter |
| 95 | +``` |
| 96 | + |
| 97 | +This ensures that all form fields in the admin interface are generated using your custom converter. |
| 98 | + |
| 99 | +--- |
| 100 | + |
| 101 | +## Example: Full Workflow |
| 102 | + |
| 103 | +Here’s a complete example of defining a SQLAlchemy model, creating a custom model converter, and using it in the admin interface: |
| 104 | + |
| 105 | +### Step 1: Define SQLAlchemy Models |
| 106 | + |
| 107 | +```python |
| 108 | +from sqlalchemy import Column, Integer, String, JSON, create_engine |
| 109 | +from sqlalchemy.orm import declarative_base |
| 110 | + |
| 111 | + |
| 112 | +Base = declarative_base() |
| 113 | +engine = create_engine("sqlite:///example.db", connect_args={"check_same_thread": False}) |
| 114 | + |
| 115 | + |
| 116 | +class User(Base): |
| 117 | + __tablename__ = "users" |
| 118 | + |
| 119 | + id = Column(Integer, primary_key=True) |
| 120 | + name = Column(String) |
| 121 | + preferences = Column(JSON) |
| 122 | + |
| 123 | + |
| 124 | +Base.metadata.create_all(engine) # Create tables |
| 125 | +``` |
| 126 | + |
| 127 | +### Step 2: Create Custom Model Converter |
| 128 | + |
| 129 | +```python |
| 130 | +from sqladmin import ModelConverter |
| 131 | +from wtforms import JSONField |
| 132 | +import json |
| 133 | + |
| 134 | + |
| 135 | +class CustomJSONField(JSONField): |
| 136 | + def _value(self) -> str: |
| 137 | + if self.raw_data: |
| 138 | + return self.raw_data[0] |
| 139 | + elif self.data: |
| 140 | + return str(json.dumps(self.data, ensure_ascii=False)) |
| 141 | + else: |
| 142 | + return "" |
| 143 | + |
| 144 | + |
| 145 | +class CustomModelConverter(ModelConverter): |
| 146 | + @converts("JSON", "JSONB") |
| 147 | + def conv_json(self, model: type, prop: ColumnProperty, kwargs: dict[str, Any]) -> UnboundField: |
| 148 | + return CustomJSONField(**kwargs) |
| 149 | +``` |
| 150 | + |
| 151 | +### Step 3: Use Custom Converter in Admin Interface |
| 152 | + |
| 153 | +```python |
| 154 | +from sqladmin import ModelView |
| 155 | + |
| 156 | + |
| 157 | +class UserAdmin(BaseAdmin): |
| 158 | + form_converter = CustomModelConverter |
| 159 | +``` |
0 commit comments