# Django Admin Style Linker
[](https://badge.fury.io/py/django-admin-style-linker)
A simple Django admin mixin to link a CSS editor field ([MonacoEditor](https://github.com/john-psina/django-admin-monaco-editor)) with an HTML editor field ([TinyMCE](https://github.com/jazzband/django-tinymce)) for a live preview. When a user types CSS, it's instantly applied to the content in the HTML editor's iframe.
## Features
- Easy to integrate with any `ModelAdmin`.
- Works with separate CSS and HTML fields.
- Optional support for [django-modeltranslation](https://github.com/deschler/django-modeltranslation).
## Installation
```bash
pip install django-admin-style-linker
```
Add `admin_style_linker` to your `INSTALLED_APPS` in `settings.py` and configure TinyMCE:
```python
INSTALLED_APPS = [
# ...
'django_monaco_editor',
'tinymce',
'admin_style_linker',
# ...
]
# Important
# You need to add this setup to your TinyMCE settings for django-admin-style-linker to work properly.
TINYMCE_DEFAULT_CONFIG = {
"setup": """function (editor) {
const event = new CustomEvent('tinyMceAllEditorsInit', { detail: [editor] });
document.dispatchEvent(event);
}""",
# other TinyMCE settings
}
```
## Usage
In your `admin.py`, inherit from `LinkStyleAdminMixin` and configure the `link_styles` attribute.
`link_styles` is a list of dictionaries, where each dictionary specifies one style field and one or more HTML fields it should apply to.
**Example:**
```python
from django.contrib import admin
from .models import MyModel
from admin_style_linker import LinkStyleAdminMixin
@admin.register(MyModel)
class MyModelAdmin(LinkStyleAdminMixin, admin.ModelAdmin):
# ... other admin settings
link_styles = [
{
'styles_field': 'custom_css', # The name of the field with CSS
'html_fields': ['content_html', 'another_html_field'], # A list of fields with HTML
},
]
```

## Django Modeltranslation Support
The mixin automatically detects if `django-modeltranslation` is installed and intelligently handles translated fields. You don't need any special configuration—just use the **base field names** in your `link_styles` setup, and the mixin will figure out the rest.
Here are a few common scenarios:
---
### Scenario 1: Both Style and HTML Fields are Translatable (Most common)
When both the CSS field and the HTML field(s) are registered for translation, the mixin will link fields of the same language together.
**`translation.py`:**
```python
from modeltranslation.translator import register, TranslationOptions
from .models import MyModel
@register(MyModel)
class MyModelTranslationOptions(TranslationOptions):
fields = ('styles', 'content')
```
**`admin.py`:**
```python
@admin.register(MyModel)
class MyModelAdmin(LinkStyleAdminMixin, admin.ModelAdmin):
link_styles = [
{
'styles_field': 'styles', # Base name
'html_fields': ['content'], # Base name
},
]
```
**Result:**
The mixin will automatically create the following links:
* `styles_en` will apply to `content_en`.
* `styles_uk` will apply to `content_uk`.
* ...and so on for all your `LANGUAGES`.
---
### Scenario 2: Non-Translatable Styles for Translatable HTML
Use one common CSS field to style all language versions of your HTML content.
**`translation.py`:**
```python
@register(MyModel)
class MyModelTranslationOptions(TranslationOptions):
fields = ('content',) # Only 'content' is translatable
```
**`admin.py`:**
```python
@admin.register(MyModel)
class MyModelAdmin(LinkStyleAdminMixin, admin.ModelAdmin):
link_styles = [
{
'styles_field': 'global_styles', # Not a translatable field
'html_fields': ['content'], # Translatable field
},
]
```
**Result:**
The `global_styles` field will apply to **all** language versions of the `content` field:
* `global_styles` → `content_en`
* `global_styles` → `content_uk`
---
### Scenario 3: Translatable Styles for a Non-Translatable HTML Field
If your style field is translatable but the HTML field is not, the mixin will link the non-translatable field only to the style field of the **default language** (`settings.LANGUAGE_CODE`).
**`translation.py`:**
```python
@register(MyModel)
class MyModelTranslationOptions(TranslationOptions):
fields = ('styles',) # Only 'styles' is translatable
```
**`admin.py`:**
```python
@admin.register(MyModel)
class MyModelAdmin(LinkStyleAdminMixin, admin.ModelAdmin):
link_styles = [
{
'styles_field': 'styles', # Translatable field
'html_fields': ['footer_html'], # NOT a translatable field
},
]
```
**Result:**
Assuming your default language is English (`en`):
* `styles_en` will apply to `footer_html`.
* Other style versions (`styles_uk`, etc.) will not be linked to `footer_html`.
---
## How it Works
The mixin injects `data-*` attributes into the widgets of the specified fields during form rendering. A JavaScript file then listens for changes in the `data-style-source-for` field and injects its content as a `<style>` tag into the `<iframe>` of the corresponding `data-style-target-of` editor.
Raw data
{
"_id": null,
"home_page": null,
"name": "django-admin-style-linker",
"maintainer": null,
"docs_url": null,
"requires_python": "<4,>=3.11",
"maintainer_email": null,
"keywords": "django, admin, css, preview, tinymce, monaco",
"author": null,
"author_email": "Leonid Yesypov <leonidyesipov@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/e3/48/0a2e395dd6600f7196f0177aebc88ac7e683b4d91b2f31b50ba6fc503a42/django_admin_style_linker-1.0.3.tar.gz",
"platform": null,
"description": " # Django Admin Style Linker\n\n[](https://badge.fury.io/py/django-admin-style-linker)\n\nA simple Django admin mixin to link a CSS editor field ([MonacoEditor](https://github.com/john-psina/django-admin-monaco-editor)) with an HTML editor field ([TinyMCE](https://github.com/jazzband/django-tinymce)) for a live preview. When a user types CSS, it's instantly applied to the content in the HTML editor's iframe.\n\n## Features\n- Easy to integrate with any `ModelAdmin`.\n- Works with separate CSS and HTML fields.\n- Optional support for [django-modeltranslation](https://github.com/deschler/django-modeltranslation).\n\n## Installation\n\n```bash\npip install django-admin-style-linker\n```\n\nAdd `admin_style_linker` to your `INSTALLED_APPS` in `settings.py` and configure TinyMCE:\n\n```python\nINSTALLED_APPS = [\n # ...\n 'django_monaco_editor',\n 'tinymce',\n 'admin_style_linker',\n # ...\n]\n\n# Important\n# You need to add this setup to your TinyMCE settings for django-admin-style-linker to work properly.\nTINYMCE_DEFAULT_CONFIG = {\n \"setup\": \"\"\"function (editor) {\n const event = new CustomEvent('tinyMceAllEditorsInit', { detail: [editor] });\n document.dispatchEvent(event);\n }\"\"\",\n\n # other TinyMCE settings\n}\n```\n\n## Usage\n\nIn your `admin.py`, inherit from `LinkStyleAdminMixin` and configure the `link_styles` attribute.\n\n`link_styles` is a list of dictionaries, where each dictionary specifies one style field and one or more HTML fields it should apply to.\n\n**Example:**\n\n```python\nfrom django.contrib import admin\nfrom .models import MyModel\nfrom admin_style_linker import LinkStyleAdminMixin\n\n@admin.register(MyModel)\nclass MyModelAdmin(LinkStyleAdminMixin, admin.ModelAdmin):\n # ... other admin settings\n\n link_styles = [\n {\n 'styles_field': 'custom_css', # The name of the field with CSS\n 'html_fields': ['content_html', 'another_html_field'], # A list of fields with HTML\n },\n ]\n```\n\n\n\n## Django Modeltranslation Support\n\nThe mixin automatically detects if `django-modeltranslation` is installed and intelligently handles translated fields. You don't need any special configuration\u2014just use the **base field names** in your `link_styles` setup, and the mixin will figure out the rest.\n\nHere are a few common scenarios:\n\n---\n\n### Scenario 1: Both Style and HTML Fields are Translatable (Most common)\n\nWhen both the CSS field and the HTML field(s) are registered for translation, the mixin will link fields of the same language together.\n\n**`translation.py`:**\n```python\nfrom modeltranslation.translator import register, TranslationOptions\nfrom .models import MyModel\n\n@register(MyModel)\nclass MyModelTranslationOptions(TranslationOptions):\n fields = ('styles', 'content')\n```\n\n**`admin.py`:**\n```python\n@admin.register(MyModel)\nclass MyModelAdmin(LinkStyleAdminMixin, admin.ModelAdmin):\n link_styles = [\n {\n 'styles_field': 'styles', # Base name\n 'html_fields': ['content'], # Base name\n },\n ]\n```\n\n**Result:**\nThe mixin will automatically create the following links:\n* `styles_en` will apply to `content_en`.\n* `styles_uk` will apply to `content_uk`.\n* ...and so on for all your `LANGUAGES`.\n\n---\n\n### Scenario 2: Non-Translatable Styles for Translatable HTML\n\nUse one common CSS field to style all language versions of your HTML content.\n\n**`translation.py`:**\n```python\n@register(MyModel)\nclass MyModelTranslationOptions(TranslationOptions):\n fields = ('content',) # Only 'content' is translatable\n```\n\n**`admin.py`:**\n```python\n@admin.register(MyModel)\nclass MyModelAdmin(LinkStyleAdminMixin, admin.ModelAdmin):\n link_styles = [\n {\n 'styles_field': 'global_styles', # Not a translatable field\n 'html_fields': ['content'], # Translatable field\n },\n ]\n```\n\n**Result:**\nThe `global_styles` field will apply to **all** language versions of the `content` field:\n* `global_styles` \u2192 `content_en`\n* `global_styles` \u2192 `content_uk`\n\n---\n\n### Scenario 3: Translatable Styles for a Non-Translatable HTML Field\n\nIf your style field is translatable but the HTML field is not, the mixin will link the non-translatable field only to the style field of the **default language** (`settings.LANGUAGE_CODE`).\n\n**`translation.py`:**\n```python\n@register(MyModel)\nclass MyModelTranslationOptions(TranslationOptions):\n fields = ('styles',) # Only 'styles' is translatable\n```\n\n**`admin.py`:**\n```python\n@admin.register(MyModel)\nclass MyModelAdmin(LinkStyleAdminMixin, admin.ModelAdmin):\n link_styles = [\n {\n 'styles_field': 'styles', # Translatable field\n 'html_fields': ['footer_html'], # NOT a translatable field\n },\n ]\n```\n\n**Result:**\nAssuming your default language is English (`en`):\n* `styles_en` will apply to `footer_html`.\n* Other style versions (`styles_uk`, etc.) will not be linked to `footer_html`.\n\n---\n\n## How it Works\nThe mixin injects `data-*` attributes into the widgets of the specified fields during form rendering. A JavaScript file then listens for changes in the `data-style-source-for` field and injects its content as a `<style>` tag into the `<iframe>` of the corresponding `data-style-target-of` editor.\n",
"bugtrack_url": null,
"license": null,
"summary": "A Django admin mixin to link MonacoEditor CSS and TinyMCE HTML fields for a live preview.",
"version": "1.0.3",
"project_urls": {
"Bug Tracker": "https://github.com/john-psina/django-admin-style-linker/issues",
"Documentation": "https://github.com/john-psina/django-admin-style-linker",
"Homepage": "https://github.com/john-psina/django-admin-style-linker",
"Repository": "https://github.com/john-psina/django-admin-style-linker"
},
"split_keywords": [
"django",
" admin",
" css",
" preview",
" tinymce",
" monaco"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "3dfeb8e8aa70e85684dc96f00e72cc08705e8bd1078f29f5e1d972bcbd40d9a4",
"md5": "65a6718457131f085d20a9bcc8af5ab7",
"sha256": "d92e34bdfd227b9be20872ef9b7eb9c2db35f3e93fdce1e805215c7f63fb24ed"
},
"downloads": -1,
"filename": "django_admin_style_linker-1.0.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "65a6718457131f085d20a9bcc8af5ab7",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4,>=3.11",
"size": 9078,
"upload_time": "2025-10-30T15:38:30",
"upload_time_iso_8601": "2025-10-30T15:38:30.584018Z",
"url": "https://files.pythonhosted.org/packages/3d/fe/b8e8aa70e85684dc96f00e72cc08705e8bd1078f29f5e1d972bcbd40d9a4/django_admin_style_linker-1.0.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "e3480a2e395dd6600f7196f0177aebc88ac7e683b4d91b2f31b50ba6fc503a42",
"md5": "1e25b0b3cd20afcfef93b188a5747c02",
"sha256": "6e6e47453846823ed847657fe22854bebc871e60b29da70ce9c5d35cc8bcab79"
},
"downloads": -1,
"filename": "django_admin_style_linker-1.0.3.tar.gz",
"has_sig": false,
"md5_digest": "1e25b0b3cd20afcfef93b188a5747c02",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4,>=3.11",
"size": 10689,
"upload_time": "2025-10-30T15:38:31",
"upload_time_iso_8601": "2025-10-30T15:38:31.940397Z",
"url": "https://files.pythonhosted.org/packages/e3/48/0a2e395dd6600f7196f0177aebc88ac7e683b4d91b2f31b50ba6fc503a42/django_admin_style_linker-1.0.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-30 15:38:31",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "john-psina",
"github_project": "django-admin-style-linker",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "django",
"specs": [
[
">=",
"5.0"
]
]
},
{
"name": "django-admin-monaco-editor",
"specs": [
[
">=",
"1.1.5"
]
]
},
{
"name": "django-tinymce",
"specs": [
[
">=",
"4.0.0"
]
]
}
],
"lcname": "django-admin-style-linker"
}