django-lucy-assist 1.0.6__tar.gz → 1.0.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/PKG-INFO +2 -2
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/README.md +1 -1
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/django_lucy_assist.egg-info/PKG-INFO +2 -2
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/django_lucy_assist.egg-info/SOURCES.txt +2 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/__init__.py +1 -1
- django_lucy_assist-1.0.8/lucy_assist/admin.py +71 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/conf.py +8 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/constantes.py +21 -1
- django_lucy_assist-1.0.8/lucy_assist/migrations/0003_configurationlucyassist_crud_views_mapping.py +18 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/models/configuration.py +54 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/services/context_service.py +17 -6
- django_lucy_assist-1.0.8/lucy_assist/services/crud_service.py +1113 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/services/tool_executor_service.py +41 -1
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/services/tools_definition.py +36 -6
- django_lucy_assist-1.0.8/lucy_assist/services/view_discovery_service.py +339 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/static/lucy_assist/css/lucy-assist.css +254 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/pyproject.toml +1 -1
- django_lucy_assist-1.0.6/lucy_assist/admin.py +0 -22
- django_lucy_assist-1.0.6/lucy_assist/services/crud_service.py +0 -440
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/MANIFEST.in +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/django_lucy_assist.egg-info/dependency_links.txt +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/django_lucy_assist.egg-info/requires.txt +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/django_lucy_assist.egg-info/top_level.txt +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/apps.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/context_processors.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/migrations/0001_initial.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/migrations/0002_configurationlucyassist_prompt_complementaire.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/migrations/__init__.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/models/__init__.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/models/base.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/models/conversation.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/models/message.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/models/project_context_cache.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/services/__init__.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/services/bug_notification_service.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/services/claude_service.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/services/gitlab_service.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/services/project_context_service.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/signals.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/static/lucy_assist/image/icon-lucy.png +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/static/lucy_assist/js/lucy-assist.js +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/templates/lucy_assist/chatbot_sidebar.html +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/templates/lucy_assist/partials/documentation_content.html +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/tests/__init__.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/tests/factories/__init__.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/tests/factories/lucy_assist_factories.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/tests/test_lucy_assist.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/urls.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/utils/__init__.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/utils/log_utils.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/utils/message_utils.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/utils/token_utils.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/views/__init__.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/views/api_views.py +0 -0
- {django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-lucy-assist
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.8
|
|
4
4
|
Summary: Assistant IA intelligent Revolucy pour outil métier
|
|
5
5
|
Author-email: Revolucy <hello@revolucy.fr>
|
|
6
6
|
Maintainer-email: Maxence <hello@revolucy.fr>
|
|
@@ -176,7 +176,7 @@ Lucy Assist expose plusieurs endpoints API :
|
|
|
176
176
|
- `POST /lucy-assist/api/conversations/` - Créer une conversation
|
|
177
177
|
- `GET /lucy-assist/api/conversations/<id>/` - Détail d'une conversation
|
|
178
178
|
- `POST /lucy-assist/api/conversations/<id>/messages/` - Ajouter un message
|
|
179
|
-
- `POST /lucy-assist/api/
|
|
179
|
+
- `POST /lucy-assist/api/convers2ations/<id>/completion/` - Générer une réponse (streaming)
|
|
180
180
|
- `GET /lucy-assist/api/tokens/status/` - Statut des tokens
|
|
181
181
|
|
|
182
182
|
## Licence
|
|
@@ -133,7 +133,7 @@ Lucy Assist expose plusieurs endpoints API :
|
|
|
133
133
|
- `POST /lucy-assist/api/conversations/` - Créer une conversation
|
|
134
134
|
- `GET /lucy-assist/api/conversations/<id>/` - Détail d'une conversation
|
|
135
135
|
- `POST /lucy-assist/api/conversations/<id>/messages/` - Ajouter un message
|
|
136
|
-
- `POST /lucy-assist/api/
|
|
136
|
+
- `POST /lucy-assist/api/convers2ations/<id>/completion/` - Générer une réponse (streaming)
|
|
137
137
|
- `GET /lucy-assist/api/tokens/status/` - Statut des tokens
|
|
138
138
|
|
|
139
139
|
## Licence
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-lucy-assist
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.8
|
|
4
4
|
Summary: Assistant IA intelligent Revolucy pour outil métier
|
|
5
5
|
Author-email: Revolucy <hello@revolucy.fr>
|
|
6
6
|
Maintainer-email: Maxence <hello@revolucy.fr>
|
|
@@ -176,7 +176,7 @@ Lucy Assist expose plusieurs endpoints API :
|
|
|
176
176
|
- `POST /lucy-assist/api/conversations/` - Créer une conversation
|
|
177
177
|
- `GET /lucy-assist/api/conversations/<id>/` - Détail d'une conversation
|
|
178
178
|
- `POST /lucy-assist/api/conversations/<id>/messages/` - Ajouter un message
|
|
179
|
-
- `POST /lucy-assist/api/
|
|
179
|
+
- `POST /lucy-assist/api/convers2ations/<id>/completion/` - Générer une réponse (streaming)
|
|
180
180
|
- `GET /lucy-assist/api/tokens/status/` - Statut des tokens
|
|
181
181
|
|
|
182
182
|
## Licence
|
{django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/django_lucy_assist.egg-info/SOURCES.txt
RENAMED
|
@@ -16,6 +16,7 @@ lucy_assist/signals.py
|
|
|
16
16
|
lucy_assist/urls.py
|
|
17
17
|
lucy_assist/migrations/0001_initial.py
|
|
18
18
|
lucy_assist/migrations/0002_configurationlucyassist_prompt_complementaire.py
|
|
19
|
+
lucy_assist/migrations/0003_configurationlucyassist_crud_views_mapping.py
|
|
19
20
|
lucy_assist/migrations/__init__.py
|
|
20
21
|
lucy_assist/models/__init__.py
|
|
21
22
|
lucy_assist/models/base.py
|
|
@@ -32,6 +33,7 @@ lucy_assist/services/gitlab_service.py
|
|
|
32
33
|
lucy_assist/services/project_context_service.py
|
|
33
34
|
lucy_assist/services/tool_executor_service.py
|
|
34
35
|
lucy_assist/services/tools_definition.py
|
|
36
|
+
lucy_assist/services/view_discovery_service.py
|
|
35
37
|
lucy_assist/static/lucy_assist/css/lucy-assist.css
|
|
36
38
|
lucy_assist/static/lucy_assist/image/icon-lucy.png
|
|
37
39
|
lucy_assist/static/lucy_assist/js/lucy-assist.js
|
|
@@ -5,7 +5,7 @@ Un chatbot IA basé sur Claude d'Anthropic, intégrable dans n'importe quelle
|
|
|
5
5
|
application Django pour fournir une assistance contextuelle aux utilisateurs.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
__version__ = '1.0.
|
|
8
|
+
__version__ = '1.0.8'
|
|
9
9
|
__author__ = 'Revolucy'
|
|
10
10
|
|
|
11
11
|
default_app_config = 'lucy_assist.apps.LucyAssistConfig'
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from django.contrib import admin
|
|
2
|
+
|
|
3
|
+
from lucy_assist.models import Conversation, Message, ConfigurationLucyAssist
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BlockMessage(admin.StackedInline):
|
|
7
|
+
model = Message
|
|
8
|
+
extra = 1
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@admin.register(Conversation)
|
|
12
|
+
class ConversationAdmin(admin.ModelAdmin):
|
|
13
|
+
list_display = ('id', 'utilisateur', 'titre', 'created_date', 'is_active')
|
|
14
|
+
list_filter = ('is_active', 'created_date')
|
|
15
|
+
search_fields = ('utilisateur__email', 'titre')
|
|
16
|
+
ordering = ('-created_date',)
|
|
17
|
+
inlines = [BlockMessage]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@admin.register(ConfigurationLucyAssist)
|
|
21
|
+
class ConfigurationLucyAssistAdmin(admin.ModelAdmin):
|
|
22
|
+
list_display = ('id', 'tokens_disponibles', 'prix_par_million_tokens', 'nb_vues_crud', 'updated_date')
|
|
23
|
+
readonly_fields = ('crud_views_mapping_display', 'model_app_mapping_display')
|
|
24
|
+
fieldsets = (
|
|
25
|
+
('Configuration Tokens', {
|
|
26
|
+
'fields': ('tokens_disponibles', 'prix_par_million_tokens', 'actif')
|
|
27
|
+
}),
|
|
28
|
+
('Personnalisation', {
|
|
29
|
+
'fields': ('avatar', 'questions_frequentes', 'prompt_complementaire')
|
|
30
|
+
}),
|
|
31
|
+
('Mapping Automatique (lecture seule)', {
|
|
32
|
+
'fields': ('crud_views_mapping_display', 'model_app_mapping_display'),
|
|
33
|
+
'classes': ('collapse',)
|
|
34
|
+
}),
|
|
35
|
+
)
|
|
36
|
+
actions = ['refresh_crud_views']
|
|
37
|
+
|
|
38
|
+
def nb_vues_crud(self, obj):
|
|
39
|
+
"""Affiche le nombre de modèles avec des vues CRUD découvertes."""
|
|
40
|
+
if obj.crud_views_mapping:
|
|
41
|
+
return len(obj.crud_views_mapping)
|
|
42
|
+
return 0
|
|
43
|
+
nb_vues_crud.short_description = "Modèles CRUD"
|
|
44
|
+
|
|
45
|
+
def crud_views_mapping_display(self, obj):
|
|
46
|
+
"""Affiche le mapping des vues CRUD de manière lisible."""
|
|
47
|
+
import json
|
|
48
|
+
if obj.crud_views_mapping:
|
|
49
|
+
return json.dumps(obj.crud_views_mapping, indent=2, ensure_ascii=False)
|
|
50
|
+
return "Aucune vue découverte. Utilisez l'action 'Rafraîchir les vues CRUD'."
|
|
51
|
+
crud_views_mapping_display.short_description = "Vues CRUD découvertes"
|
|
52
|
+
|
|
53
|
+
def model_app_mapping_display(self, obj):
|
|
54
|
+
"""Affiche le mapping modèle -> app de manière lisible."""
|
|
55
|
+
import json
|
|
56
|
+
if obj.model_app_mapping:
|
|
57
|
+
return json.dumps(obj.model_app_mapping, indent=2, ensure_ascii=False)
|
|
58
|
+
return "Aucun mapping. Sera construit automatiquement."
|
|
59
|
+
model_app_mapping_display.short_description = "Mapping Modèle -> App"
|
|
60
|
+
|
|
61
|
+
@admin.action(description="Rafraîchir les vues CRUD découvertes")
|
|
62
|
+
def refresh_crud_views(self, request, queryset):
|
|
63
|
+
"""Action admin pour rafraîchir le mapping des vues CRUD."""
|
|
64
|
+
for config in queryset:
|
|
65
|
+
mapping = config.refresh_crud_views_mapping()
|
|
66
|
+
nb_models = len(mapping)
|
|
67
|
+
nb_views = sum(len(actions) for actions in mapping.values())
|
|
68
|
+
self.message_user(
|
|
69
|
+
request,
|
|
70
|
+
f"Mapping rafraîchi: {nb_models} modèles, {nb_views} vues découvertes."
|
|
71
|
+
)
|
|
@@ -55,6 +55,14 @@ class LucyAssistSettings:
|
|
|
55
55
|
"Comment modifier mon profil ?",
|
|
56
56
|
"Où trouver la liste des réservations ?",
|
|
57
57
|
],
|
|
58
|
+
|
|
59
|
+
# Chemin vers le module contenant set_current_user pour le ThreadLocal
|
|
60
|
+
# Ex: 'alyse.middleware.middleware' pour le projet Alyse
|
|
61
|
+
'THREAD_LOCAL_MODULE': None,
|
|
62
|
+
|
|
63
|
+
# Attributs de l'utilisateur à copier vers la requête
|
|
64
|
+
# Ex: ['franchise', 'tenant', 'organization']
|
|
65
|
+
'REQUEST_USER_ATTRS': [],
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
def __init__(self):
|
|
@@ -79,7 +79,27 @@ Utilisateur : "Modifie l'adresse du membre 42"
|
|
|
79
79
|
|
|
80
80
|
- Si l'utilisateur demande explicitement "comment faire" ou "explique-moi"
|
|
81
81
|
- Si tu n'as pas assez d'informations (dans ce cas, demande les infos manquantes)
|
|
82
|
-
|
|
82
|
+
|
|
83
|
+
## IMPORTANT - Procédure de suppression
|
|
84
|
+
|
|
85
|
+
Pour TOUTE demande de suppression, tu DOIS suivre cette procédure :
|
|
86
|
+
|
|
87
|
+
1. D'abord, utilise le tool `get_deletion_impact` pour analyser les conséquences
|
|
88
|
+
2. Affiche à l'utilisateur le résultat complet :
|
|
89
|
+
- L'objet qui sera supprimé
|
|
90
|
+
- TOUS les objets supprimés en cascade (avec leur type et nombre)
|
|
91
|
+
- Les champs qui seront mis à NULL
|
|
92
|
+
- Les éventuels blocages (objets protégés)
|
|
93
|
+
3. Demande une confirmation EXPLICITE à l'utilisateur ("Confirmez-vous la suppression ?")
|
|
94
|
+
4. SEULEMENT si l'utilisateur confirme explicitement (oui, ok, confirme, etc.), utilise `delete_object` avec `confirmed: true`
|
|
95
|
+
|
|
96
|
+
Exemple de réponse après get_deletion_impact :
|
|
97
|
+
"Voici les conséquences de la suppression du Client #42 :
|
|
98
|
+
- 5 Réservations seront supprimées en cascade
|
|
99
|
+
- 3 Paiements seront supprimés en cascade
|
|
100
|
+
- 2 Documents auront leur champ 'client' mis à NULL
|
|
101
|
+
|
|
102
|
+
**Confirmez-vous vouloir supprimer ce client et tous les éléments associés ?**"
|
|
83
103
|
|
|
84
104
|
## Contexte de la page actuelle
|
|
85
105
|
{page_context}
|
django_lucy_assist-1.0.8/lucy_assist/migrations/0003_configurationlucyassist_crud_views_mapping.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('lucy_assist', '0002_configurationlucyassist_prompt_complementaire'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='configurationlucyassist',
|
|
15
|
+
name='crud_views_mapping',
|
|
16
|
+
field=models.JSONField(blank=True, default=dict),
|
|
17
|
+
),
|
|
18
|
+
]
|
|
@@ -26,6 +26,17 @@ class ConfigurationLucyAssist(LucyAssistBaseModel):
|
|
|
26
26
|
# Mapping des modèles vers leurs applications Django
|
|
27
27
|
model_app_mapping = models.JSONField(blank=True, default=dict)
|
|
28
28
|
|
|
29
|
+
# Mapping des vues CRUD découvertes automatiquement
|
|
30
|
+
# Structure: {
|
|
31
|
+
# "model_name": {
|
|
32
|
+
# "list": {"url_name": "app:model-list", "url": "/app/model/"},
|
|
33
|
+
# "create": {"url_name": "app:model-formulaire", "url": "/app/model/formulaire/"},
|
|
34
|
+
# "detail": {"url_name": "app:model-detail", "url": "/app/model/detail/<pk>/"},
|
|
35
|
+
# "delete": {"url_name": "app:model-suppression", "url": "/app/model/suppression/<pk>/"}
|
|
36
|
+
# }
|
|
37
|
+
# }
|
|
38
|
+
crud_views_mapping = models.JSONField(blank=True, default=dict)
|
|
39
|
+
|
|
29
40
|
class Meta:
|
|
30
41
|
verbose_name = "Configuration Lucy Assist"
|
|
31
42
|
verbose_name_plural = "Configuration Lucy Assist"
|
|
@@ -51,10 +62,53 @@ class ConfigurationLucyAssist(LucyAssistBaseModel):
|
|
|
51
62
|
def save(self, *args, **kwargs):
|
|
52
63
|
# Forcer l'ID à 1 pour le singleton
|
|
53
64
|
self.pk = 1
|
|
65
|
+
|
|
66
|
+
# Auto-découverte des vues CRUD si le mapping est vide
|
|
67
|
+
if not self.crud_views_mapping:
|
|
68
|
+
self.crud_views_mapping = self._discover_crud_views()
|
|
69
|
+
|
|
54
70
|
super().save(*args, **kwargs)
|
|
55
71
|
# Invalider le cache
|
|
56
72
|
cache.delete('lucy_assist_config')
|
|
57
73
|
|
|
74
|
+
def refresh_crud_views_mapping(self):
|
|
75
|
+
"""
|
|
76
|
+
Force la redécouverte des vues CRUD.
|
|
77
|
+
Utile après l'ajout de nouvelles vues dans le projet.
|
|
78
|
+
"""
|
|
79
|
+
self.crud_views_mapping = self._discover_crud_views()
|
|
80
|
+
self.save(update_fields=['crud_views_mapping'])
|
|
81
|
+
cache.delete('lucy_assist_config')
|
|
82
|
+
return self.crud_views_mapping
|
|
83
|
+
|
|
84
|
+
def _discover_crud_views(self) -> dict:
|
|
85
|
+
"""
|
|
86
|
+
Découvre automatiquement les vues CRUD du projet
|
|
87
|
+
en parcourant les URL patterns.
|
|
88
|
+
"""
|
|
89
|
+
from lucy_assist.services.view_discovery_service import ViewDiscoveryService
|
|
90
|
+
service = ViewDiscoveryService()
|
|
91
|
+
return service.discover_crud_views()
|
|
92
|
+
|
|
93
|
+
def get_crud_view_for_model(self, model_name: str, action: str) -> dict:
|
|
94
|
+
"""
|
|
95
|
+
Retourne les infos de la vue CRUD pour un modèle et une action donnés.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
model_name: Nom du modèle (ex: 'Client', 'Reservation')
|
|
99
|
+
action: Type d'action ('list', 'create', 'detail', 'update', 'delete')
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Dict avec 'url_name', 'url', 'method' ou None si non trouvé
|
|
103
|
+
"""
|
|
104
|
+
if not self.crud_views_mapping:
|
|
105
|
+
self.crud_views_mapping = self._discover_crud_views()
|
|
106
|
+
self.save(update_fields=['crud_views_mapping'])
|
|
107
|
+
|
|
108
|
+
model_lower = model_name.lower()
|
|
109
|
+
model_views = self.crud_views_mapping.get(model_lower, {})
|
|
110
|
+
return model_views.get(action)
|
|
111
|
+
|
|
58
112
|
@property
|
|
59
113
|
def tokens_restants_en_euros(self):
|
|
60
114
|
"""Retourne la valeur en euros des tokens restants."""
|
{django_lucy_assist-1.0.6 → django_lucy_assist-1.0.8}/lucy_assist/services/context_service.py
RENAMED
|
@@ -334,14 +334,17 @@ class ContextService:
|
|
|
334
334
|
try:
|
|
335
335
|
# Trouver les champs texte et date pour la recherche
|
|
336
336
|
search_fields = []
|
|
337
|
-
date_fields = []
|
|
337
|
+
date_fields = [] # DateField (comparaison directe)
|
|
338
|
+
datetime_fields = [] # DateTimeField (utilise __date)
|
|
338
339
|
for field in model._meta.get_fields():
|
|
339
340
|
if hasattr(field, 'get_internal_type'):
|
|
340
341
|
field_type = field.get_internal_type()
|
|
341
342
|
if field_type in ['CharField', 'TextField']:
|
|
342
343
|
search_fields.append(field.name)
|
|
343
|
-
elif field_type
|
|
344
|
+
elif field_type == 'DateField':
|
|
344
345
|
date_fields.append(field.name)
|
|
346
|
+
elif field_type == 'DateTimeField':
|
|
347
|
+
datetime_fields.append(field.name)
|
|
345
348
|
|
|
346
349
|
# Construire la requête
|
|
347
350
|
from django.db.models import Q
|
|
@@ -349,13 +352,21 @@ class ContextService:
|
|
|
349
352
|
has_criteria = False
|
|
350
353
|
|
|
351
354
|
# Si on a une date, chercher dans les champs date
|
|
352
|
-
if search_date and date_fields:
|
|
355
|
+
if search_date and (date_fields or datetime_fields):
|
|
353
356
|
date_q = Q()
|
|
357
|
+
search_date_only = search_date.date()
|
|
358
|
+
|
|
359
|
+
# DateField: comparaison directe
|
|
354
360
|
for field_name in date_fields:
|
|
355
|
-
date_q |= Q(**{
|
|
361
|
+
date_q |= Q(**{field_name: search_date_only})
|
|
362
|
+
|
|
363
|
+
# DateTimeField: utiliser __date
|
|
364
|
+
for field_name in datetime_fields:
|
|
365
|
+
date_q |= Q(**{f'{field_name}__date': search_date_only})
|
|
366
|
+
|
|
356
367
|
q_objects = date_q
|
|
357
368
|
has_criteria = True
|
|
358
|
-
LogUtils.info(f"[search_objects] {model.__name__}: recherche date dans {date_fields}")
|
|
369
|
+
LogUtils.info(f"[search_objects] {model.__name__}: recherche date dans DateField={date_fields}, DateTimeField={datetime_fields}")
|
|
359
370
|
|
|
360
371
|
# Si on a du texte, chercher dans les champs texte
|
|
361
372
|
if text_query.strip() and search_fields:
|
|
@@ -382,7 +393,7 @@ class ContextService:
|
|
|
382
393
|
|
|
383
394
|
# Si pas de critère de recherche valide, skip
|
|
384
395
|
if not has_criteria:
|
|
385
|
-
if not search_fields and not date_fields:
|
|
396
|
+
if not search_fields and not date_fields and not datetime_fields:
|
|
386
397
|
LogUtils.info(f"[search_objects] {model.__name__}: aucun champ recherchable")
|
|
387
398
|
continue
|
|
388
399
|
|