{{ widget.initial_text }}: {{ widget.value }}{% if widget.attrs.subject_location_field %} {% endif %}{% if not widget.required %}
+{% endif %}
{{ widget.input_text }}:{% endif %}
@@ -8,5 +8,142 @@
+
+{% if widget.attrs.subject_location_field %}
+
+{% endif %}
diff --git a/docs/ai.rst b/docs/ai.rst
index 9c72f730..81671110 100644
--- a/docs/ai.rst
+++ b/docs/ai.rst
@@ -77,16 +77,60 @@ In this modal you can edit the ``words`` and ``useBulletedList`` parameters and
All default fields and CKEDITOR fields are supported, see AI Hooks section below if you need to support other wysiwyg editors.
+Image Generation
+----------------
+
+Baton provides a new model field and a new image widget which can be used to generate images from text. The image field can be used as a normal image field, but also a new button will appear near it.
+The button will open a modal where you can set some options, describe the image you want and generate the image. You can then preview the image and if you like it you can save it in the
+file field with just one click.::
+
+ from baton.fields import BatonAiImageField
+
+ class MyModel(models.Model):
+ image = BatonAiImageField(verbose_name=_("immagine"), upload_to="news/")
+
+
+There is also another way to add the AI image generation functionality to a normal ImageField if you do not want to use the BatonAiImageField model field:::
+
+
+
+
+Baton also integrates the functionality of `django-subject-imagefield `_, so you can specify a `subject_location` field that will store the percentage coordinated of the subject of the image, and in editing mode a point will appear on the image preview in order to let you change this position::
+
+ from baton.fields import BatonAiImageField
+
+ class MyModel(models.Model):
+ image = BatonAiImageField(verbose_name=_("immagine"), upload_to="news/", subject_location_field='subject_location')
+ subject_location = models.CharField(max_length=7, default="50,50")
+
+You can configure the width of the preview image through the settings ``IMAGE_PREVIEW_WIDTH`` which by default equals ``200``.
+
+Check the ``django-subject-imagefield`` documentation for more details and properties.
+
Image Vision
------------
-In your ``ModelAdmin`` classes you can define which images can be described in order to generate an alt text, look at the following example:::
+There are two ways to activate image vision functionality in Baton, both allow to generate an alt text for the image through the AI.
+
+The first way is to just use the ``BatonAiImageField`` and define the ``alt_field`` attribute (an optionally ``alt_chars``, ``alt_language``)::
+
+ from baton.fields import BatonAiImageField
+
+ class MyModel(models.Model):
+ image = BatonAiImageField(verbose_name=_("immagine"), upload_to="news/", alt_field="image_alt", alt_chars=20, alt_language="en")
+ image_alt = models.CharField(max_length=40, blank=True)
+
+This method will work only when images are inside inlines.
+
+The second method consists in defining in the ``ModelAdmin`` classes which images can be described in order to generate an alt text, look at the following example::
class MyModelAdmin(admin.ModelAdmin):
# ...
baton_vision_fields = {
- "image": [{
- "target": "image_alt",
+ "#id_image": [{ # key must be a selector (useful for inlines)
+ "target": "image_alt", # target should be the name of a field of the same model
"chars": 80,
"language": "en",
}],
@@ -100,25 +144,6 @@ You have to specify the target field name. You can also optionally specify the f
With this configuration, one (the number of targets) button will appear near the ``image`` field, clicking it the calculated image alt text will be inserted in the ``image_alt`` field.
-Image Generation
-----------------
-
-Baton provides a new model field and a new image widget which can be used to generate images from text. The image field can be used as a normal image field, but also a new button will appear near it.
-The button will open a modal where you can set some options, describe the image you want and generate the image. You can then preview the image and if you like it you can save it in the
-file field with just one click.::
-
- from baton.fields import BatonAiImageField
-
- class MyModel(models.Model):
- image = BatonAiImageField(verbose_name=_("immagine"), upload_to="news/")
-
-
-There is also another way to add the AI image generation functionality to a normal ImageField if you do not want to use the BatonAiImageField model field:::
-
-
-
Stats
----------------
diff --git a/docs/conf.py b/docs/conf.py
index 3a466134..7d048714 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -54,8 +54,8 @@
# built documents.
#
# The short X.Y version.
-version = u'4.2.0'
-release = u'4.2.0'
+version = u'4.2.1'
+release = u'4.2.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/configuration.rst b/docs/configuration.rst
index 1f331701..7c0650de 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -38,6 +38,7 @@ This is an example of configuration::
},
'BATON_CLIENT_ID': 'xxxxxxxxxxxxxxxxxxxx',
'BATON_CLIENT_SECRET': 'xxxxxxxxxxxxxxxxxx',
+ 'IMAGE_PREVIEW_WIDTH': 200,
'AI': {
'MODELS': "myapp.foo.bar", # alternative to the below for lines, a function which returns the models dictionary
'IMAGES_MODEL': AIModels.BATON_DALL_E_3,
@@ -242,6 +243,11 @@ You can force the light or dark theme, and the theme toggle disappears from the
**Default**: None
+Image preview width
+-----------------------
+
+The default image width in pixels of the preview shown to set the subject location of the ``BatonAiImageField``. Defaults to ``200``
+
AI
----
diff --git a/docs/customization.rst b/docs/customization.rst
index f0358580..c489cfc4 100644
--- a/docs/customization.rst
+++ b/docs/customization.rst
@@ -9,6 +9,8 @@ You can override all the css variables, just create a `baton/css/root.css` file
You can also create themes directly from the admin site, just surf to `/admin/baton/batontheme/`. There can be only one active theme, if present, the saved content is used instead of the `root.css` file. So just copy the content of that file in the field and change the colors you want. Be aware that the theme content is considered safe and injected into the page as is, so be carefull.
+.. important:: You can find ready to use themes and new ideas at `otto-torino/django-baton-themes `_
+
If you need heavy customization or you need to customize the `primary` and `secondary` colors, you can edit and recompile the JS app which resides in `baton/static/baton/app`.
The Baton js app
@@ -93,6 +95,6 @@ You can also perform live development, in this case:
- start the webpack development server ::
- $ npm run dev
+ $ npm run dev:baton
Now while you make your changes to the js app (css included), webpack will update the bundle automatically, so just refresh the page and you'll see your changes.
diff --git a/setup.py b/setup.py
index 81c3baaf..0121c6f0 100644
--- a/setup.py
+++ b/setup.py
@@ -11,7 +11,7 @@
setup(
name='django-baton',
- version='4.2.0',
+ version='4.2.1',
packages=['baton', 'baton.autodiscover', 'baton.templatetags'],
include_package_data=True,
license='MIT License',
diff --git a/testapp/app/db.sqlite3 b/testapp/app/db.sqlite3
index 4750a515..2a1deaba 100644
Binary files a/testapp/app/db.sqlite3 and b/testapp/app/db.sqlite3 differ
diff --git a/testapp/app/news/admin.py b/testapp/app/news/admin.py
index 7cfb82e0..19c04c09 100644
--- a/testapp/app/news/admin.py
+++ b/testapp/app/news/admin.py
@@ -108,7 +108,7 @@ class NewsAdmin(ImportExportModelAdmin, TranslationAdmin):
}),
('Media', {
- 'fields': ('image', 'image_alt', ),
+ 'fields': ('image', 'image_alt', 'image_subject_location', ),
'classes': ('collapse', ),
}),
('Flags', {
@@ -155,13 +155,13 @@ class NewsAdmin(ImportExportModelAdmin, TranslationAdmin):
# }],
# }
- baton_vision_fields = {
- "image": [{
- "target": "image_alt",
- "chars": 20,
- "language": "en",
- }],
- }
+ # baton_vision_fields = {
+ # "image": [{
+ # "target": "image_alt",
+ # "chars": 20,
+ # "language": "en",
+ # }],
+ # }
def get_category(self, instance):
return mark_safe('%s' % (instance.id, str(instance.category)))
diff --git a/testapp/app/news/migrations/0007_news_image_subject_location_alter_news_image.py b/testapp/app/news/migrations/0007_news_image_subject_location_alter_news_image.py
new file mode 100644
index 00000000..0efc0551
--- /dev/null
+++ b/testapp/app/news/migrations/0007_news_image_subject_location_alter_news_image.py
@@ -0,0 +1,35 @@
+# Generated by Django 5.1.3 on 2024-12-11 09:46
+
+import baton.fields
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("news", "0006_news_image_alt"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="news",
+ name="image_subject_location",
+ field=models.CharField(
+ blank=True,
+ max_length=7,
+ null=True,
+ verbose_name="image subject location",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="news",
+ name="image",
+ field=baton.fields.BatonAiImageField(
+ alt_field="image_alt",
+ blank=True,
+ null=True,
+ subject_location_field="image_subject_location",
+ upload_to="news/img",
+ ),
+ ),
+ ]
diff --git a/testapp/app/news/migrations/0008_activity_image_activity_image_alt_and_more.py b/testapp/app/news/migrations/0008_activity_image_activity_image_alt_and_more.py
new file mode 100644
index 00000000..d46e4c3b
--- /dev/null
+++ b/testapp/app/news/migrations/0008_activity_image_activity_image_alt_and_more.py
@@ -0,0 +1,44 @@
+# Generated by Django 5.1.3 on 2024-12-11 10:48
+
+import baton.fields
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("news", "0007_news_image_subject_location_alter_news_image"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="activity",
+ name="image",
+ field=baton.fields.BatonAiImageField(
+ alt_chars=20,
+ alt_field="image_alt",
+ alt_language="en-us",
+ blank=True,
+ null=True,
+ subject_location_field="image_subject_location",
+ upload_to="activity/img",
+ ),
+ ),
+ migrations.AddField(
+ model_name="activity",
+ name="image_alt",
+ field=models.CharField(
+ blank=True, max_length=50, null=True, verbose_name="image alt"
+ ),
+ ),
+ migrations.AddField(
+ model_name="activity",
+ name="image_subject_location",
+ field=models.CharField(
+ blank=True,
+ max_length=7,
+ null=True,
+ verbose_name="image subject location",
+ ),
+ ),
+ ]
diff --git a/testapp/app/news/models.py b/testapp/app/news/models.py
index e4fd06b8..ba991b5c 100644
--- a/testapp/app/news/models.py
+++ b/testapp/app/news/models.py
@@ -21,6 +21,9 @@ class Activity(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
activity_type = models.CharField(max_length=1, choices=ACTIVITY_TYPES)
date = models.DateTimeField(auto_now_add=True)
+ image = BatonAiImageField(upload_to='activity/img', alt_field='image_alt', subject_location_field='image_subject_location', null=True, blank=True)
+ image_alt = models.CharField('image alt', max_length=50, blank=True, null=True)
+ image_subject_location = models.CharField('image subject location', max_length=7, blank=True, null=True, default='50,50')
# Below the mandatory fields for generic relation
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
@@ -60,8 +63,9 @@ class Status(models.IntegerChoices):
datetime = models.DateTimeField('datetime', blank=True, null=True, help_text='insert date')
title = models.CharField('title', max_length=50, help_text='please insert a cool title')
link = models.URLField('link', blank=True, null=True)
- image = BatonAiImageField(upload_to='news/img', null=True, blank=True)
+ image = BatonAiImageField(upload_to='news/img', alt_field='image_alt', subject_location_field='image_subject_location', null=True, blank=True)
image_alt = models.CharField('image alt', max_length=50, blank=True, null=True)
+ image_subject_location = models.CharField('image subject location', max_length=7, blank=True, null=True, default='50,50')
content = HTMLField(verbose_name='content', help_text='html is supported')
summary = HTMLField('summary', blank=True, null=True)
share = models.BooleanField(default=False)