Migration au nouveau système de catégories

This commit is contained in:
Jean-Marie Favreau 2024-11-01 23:46:37 +01:00
parent 597ada73da
commit e129abee6f
17 changed files with 251 additions and 5 deletions

View File

@ -0,0 +1,208 @@
# Generated by Django 4.2.9 on 2024-11-01 14:22
from django.db import migrations
import os.path
class SimpleCat:
def __init__(self=None,
name=None, color=None,
pictogram=None, position=None,
transfered_to=None,
transtag=None):
self.name = name
self.color = color
self.pictogram = pictogram
self.position = position
self.transfered_to = transfered_to
self.transfered_to_object = {}
self.transtag = transtag
def get_transfered_category(self, e):
# we check if the given event has a corresponding tag (except empty string)
if not e is None:
for t, c in self.transfered_to.items():
if t != "" and t in e.tags:
return c
return self.transfered_to[""] if "" in self.transfered_to else None
def get_transfered_to_object(self, apps, e=None):
if self.transfered_to is None:
return None, None
Category = apps.get_model("agenda_culturel", "Category")
if isinstance(self.transfered_to, dict):
cname = self.get_transfered_category(e)
else:
cname = self.transfered_to
if not cname in self.transfered_to_object.keys():
self.transfered_to_object[cname] = Category.objects.filter(name=cname).first()
return self.transfered_to_object[cname], self.transtag
def get_pictogram_file(self):
from django.core.files import File
f = open(os.path.dirname(__file__) + "/images/" + self.pictogram, "rb")
return File(name=self.pictogram, file=f)
# Color selection
# https://colorkit.co/color-palette-generator/4cae4f-ff9900-2094f3-9b27b0-ffec3d-ff5724-795649-4051b5-009485/
# #4cae4f, #ff9900, #2094f3, #9b27b0, #ffec3d, #ff5724, #795649, #4051b5, #009485
preserved = {
"Nature": {
"old": SimpleCat("Nature", color="#27AEEF", pictogram="leaf.svg", position=8),
"new": SimpleCat("Nature", color="#4cae4f", pictogram="leaf.svg", position=8)
},
"Cinéma": {
"old": SimpleCat("Cinéma", color="#EDE15B", pictogram="theater.svg", position=5),
"new": SimpleCat("Cinéma", color="#ff9900", pictogram="theater.svg", position=4),
},
"Sans catégorie": {
"old": SimpleCat("Sans catégorie", color="#AAAAAA", pictogram="calendar.svg", position=100),
"new": SimpleCat("Sans catégorie", color="#AAAAAA", pictogram="calendar.svg", position=100),
}
}
old_cats = [
SimpleCat("Conférence", "#87BC45", "school-outline.svg", 7, "Rencontres & Débats", "conférence"),
SimpleCat("Exposition", "#BDCF32", "warehouse.svg", 6, "Visites & Expositions", "exposition"),
SimpleCat("Arts du spectacle", "#EDBF33", "track-light.svg", 4, "Spectacles"),
SimpleCat("Danse", "#EF9B20", "dance-ballroom.svg", 3, "Spectacles", "danse"),
SimpleCat("Concert", "#F46A9B", "account-music-outline.svg", 2, "Fêtes & Concerts", "concert"),
SimpleCat("Théâtre", "#EA5545", "drama-masks.svg", 1, "Spectacles", "théâtre")
]
new_cats = [
SimpleCat("Fêtes & Concerts", "#ff5724", "party-popper.svg", 1, {"concert": "Concert", "": "Sans catégorie"}),
SimpleCat("Spectacles", "#edbf33", "track-light.svg", 2, {"théâtre": "Théâtre", "danse": "Danse", "": "Arts du spectacle"}),
SimpleCat("Rencontres & Débats", "#9b27b0", "workshop.svg", 3, {"conférence": "Conférence", "": "Sans catégorie"}),
SimpleCat("Animations & Ateliers", "#4051b5", "tools.svg", 5, "Sans catégorie"),
SimpleCat("Rendez-vous locaux", "#2094f3", "ferris-wheel.svg", 6, "Sans catégorie"),
SimpleCat("Visites & Expositions", "#795649", "compass-outline.svg", 7, {"exposition": "Exposition", "": "Sans catégorie"}),
]
def create_categories(apps, catlist):
Category = apps.get_model("agenda_culturel", "Category")
cats = [Category(name=c.name, color=c.color, position=c.position, pictogram=c.get_pictogram_file()) for c in catlist]
Category.objects.bulk_create(cats)
def delete_categories(apps, catlist):
Category = apps.get_model("agenda_culturel", "Category")
Category.objects.filter(name__in=[c.name for c in catlist]).delete()
def create_new_categories(apps, schema_editor):
create_categories(apps, new_cats)
def delete_new_categories(apps, schema_editor):
delete_categories(apps, new_cats)
def create_old_categories(apps, schema_editor):
create_categories(apps, old_cats)
def delete_old_categories(apps, schema_editor):
delete_categories(apps, old_cats)
def update_preserved_categories(apps, dest):
other = "old" if dest == "new" else "new"
Category = apps.get_model("agenda_culturel", "Category")
cats = Category.objects.filter(name__in=preserved.keys())
ucats = []
for c in cats:
c.color = preserved[c.name][dest].color
c.position = preserved[c.name][dest].position
if preserved[c.name][dest].pictogram != preserved[c.name][other].pictogram:
c.pictogram = preserved[c.name][dest].get_pictogram_file()
ucats.append(c)
Category.objects.bulk_update(ucats, fields=["color", "position", "pictogram"])
def update_preserved_categories_new(apps, schema_editor):
update_preserved_categories(apps, "new")
def update_preserved_categories_old(apps, schema_editor):
update_preserved_categories(apps, "old")
def update_database(apps, cats):
convert = dict([(c.name, c) for c in cats])
# update events
Event = apps.get_model("agenda_culturel", "Event")
events = Event.objects.all()
uevents = []
for e in events:
if e.category and e.category.name in convert.keys():
cat, tag = convert[e.category.name].get_transfered_to_object(apps, e)
e.category = cat
if not tag is None:
if e.tags is None:
e.tags = [tag]
else:
if not tag in e.tags:
e.tags.append(tag)
uevents.append(e)
Event.objects.bulk_update(uevents, fields=["category", "tags"])
# update categorisation rules
CategorisationRule = apps.get_model("agenda_culturel", "CategorisationRule")
crules = CategorisationRule.objects.all()
ucrules = []
for r in crules:
if r.category and r.category.name in convert.keys():
r.category, tag = convert[r.category.name].get_transfered_to_object(apps)
ucrules.append(r)
CategorisationRule.objects.bulk_update(ucrules, fields=["category"])
# update recurrent import
RecurrentImport = apps.get_model("agenda_culturel", "RecurrentImport")
rimports = RecurrentImport.objects.all()
urimports = []
for ri in rimports:
if ri.defaultCategory and ri.defaultCategory.name in convert.keys():
ri.defaultCategory, tag = convert[ri.defaultCategory.name].get_transfered_to_object(apps)
urimports.append(ri)
RecurrentImport.objects.bulk_update(urimports, fields=["defaultCategory"])
def update_database_new(apps, schema_editor):
update_database(apps, old_cats)
def update_database_old(apps, schema_editor):
update_database(apps, new_cats)
def add_tags(apps, schema_editor):
Tag = apps.get_model("agenda_culturel", "Tag")
new_tags = ["cinéma", "théâtre", "concert", "conférence", "exposition"]
new_tags = [Tag(name=t, description="", principal=True) for t in new_tags if Tag.objects.filter(name=t).count() == 0]
Tag.objects.bulk_create(new_tags)
def do_nothing(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
('agenda_culturel', '0098_remove_category_alt_name_remove_category_codename'),
]
operations = [
migrations.RunPython(create_new_categories, reverse_code=delete_new_categories),
migrations.RunPython(update_preserved_categories_new, reverse_code=update_preserved_categories_old),
migrations.RunPython(update_database_new, reverse_code=update_database_old),
migrations.RunPython(delete_old_categories, reverse_code=create_old_categories),
migrations.RunPython(add_tags, reverse_code=do_nothing)
]

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m11 4a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4m0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2m0 7c1.1 0 2.66.23 4.11.69-.61.38-1.11.91-1.5 1.54-.82-.2-1.72-.33-2.61-.33-2.97 0-6.1 1.46-6.1 2.1v1.1h8.14c.09.7.34 1.34.72 1.9h-10.76v-3c0-2.66 5.33-4 8-4m7.5-3h1.5 2v2h-2v5.5a2.5 2.5 0 0 1 -2.5 2.5 2.5 2.5 0 0 1 -2.5-2.5 2.5 2.5 0 0 1 2.5-2.5c.36 0 .69.07 1 .21z"/></svg>

After

Width:  |  Height:  |  Size: 492 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m19 19h-14v-11h14m-3-7v2h-8v-2h-2v2h-1c-1.11 0-2 .89-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-14c0-1.11-.9-2-2-2h-1v-2m-1 11h-5v5h5z"/></svg>

After

Width:  |  Height:  |  Size: 231 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m7 17 3.2-6.8 6.8-3.2-3.2 6.8zm5-5.9a.9.9 0 0 0 -.9.9.9.9 0 0 0 .9.9.9.9 0 0 0 .9-.9.9.9 0 0 0 -.9-.9m0-9.1a10 10 0 0 1 10 10 10 10 0 0 1 -10 10 10 10 0 0 1 -10-10 10 10 0 0 1 10-10m0 2a8 8 0 0 0 -8 8 8 8 0 0 0 8 8 8 8 0 0 0 8-8 8 8 0 0 0 -8-8z"/></svg>

After

Width:  |  Height:  |  Size: 345 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m14 3.5c0 .83-.67 1.5-1.5 1.5s-1.5-.67-1.5-1.5.67-1.5 1.5-1.5 1.5.67 1.5 1.5m-5.5 1.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5m5.5 7-.78-2.25h2.96l2.16-1.08c.37-.17.52-.63.33-1-.17-.37-.63-.53-1-.34l-.82.41-.49-.84c-.29-.65-1-1.02-1.7-.86l-2.47.53c-.69.15-1.19.78-1.19 1.5v.7l-2.43 1.62h.01c-.08.07-.19.16-.25.28l-.89 1.77-1.78.89c-.37.17-.52.64-.33 1.01.13.26.4.41.67.41.11 0 .23-.02.34-.08l2.22-1.11 1.04-2.06 1.4 1.5c-1 3-8 7-8 7s4 2 9 2 9-2 9-2-5-4-7-8m2.85-.91-.32.16h-1.2l.06.16c.52 1.03 1.28 2.09 2.11 3.03l-.53-3.41z"/></svg>

After

Width:  |  Height:  |  Size: 654 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m8.11 19.45c-2.17-.8-3.89-2.67-4.4-5.1l-1.66-7.81c-.24-1.08.45-2.14 1.53-2.37l9.77-2.07.03-.01c1.07-.21 2.12.48 2.34 1.54l.35 1.67 4.35.93h.03c1.05.24 1.73 1.3 1.51 2.36l-1.66 7.82c-.8 3.77-4.52 6.19-8.3 5.38-1.58-.33-2.92-1.18-3.89-2.34zm11.89-11.27-9.77-2.08-1.66 7.82v.03c-.57 2.68 1.16 5.32 3.85 5.89s5.35-1.15 5.92-3.84zm-4 8.32c-.63 1.07-1.89 1.66-3.17 1.39-1.27-.27-2.18-1.32-2.33-2.55zm-7.53-11.33-4.47.96 1.66 7.81.01.03c.15.71.45 1.35.86 1.9-.1-.77-.08-1.57.09-2.37l.43-2c-.45-.08-.84-.33-1.05-.69.06-.61.56-1.15 1.25-1.31h.25l.78-3.81c.04-.19.1-.36.19-.52m6.56 7.06c.32-.53 1-.81 1.69-.66.69.14 1.19.67 1.28 1.29-.33.52-1 .8-1.7.64-.69-.13-1.19-.66-1.27-1.27m-4.88-1.04c.32-.53.99-.81 1.68-.66.67.14 1.2.68 1.28 1.29-.33.52-1 .81-1.69.68-.69-.17-1.19-.7-1.27-1.31m1.82-6.76 1.96.42-.16-.8z"/></svg>

After

Width:  |  Height:  |  Size: 901 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m12 19c.86 0 1.59.54 1.87 1.29.55-.12 1.08-.29 1.59-.52l-1.76-4.15c-.52.25-1.09.38-1.7.38s-1.18-.13-1.7-.38l-1.76 4.15c.51.23 1.04.4 1.59.52.28-.75 1.01-1.29 1.87-1.29m6.25-1.24c-.25-.34-.44-.76-.44-1.26 0-1.09.9-2 2-2l.31.03c.25-.8.38-1.65.38-2.53s-.13-1.73-.38-2.5h-.31c-1.11 0-2-.89-2-2 0-.5.16-.91.44-1.26-1.15-1.24-2.66-2.15-4.38-2.53-.28.75-1.01 1.29-1.87 1.29s-1.59-.54-1.87-1.29c-1.72.38-3.23 1.29-4.38 2.53.28.35.45.79.45 1.26 0 1.11-.9 2-2 2h-.32c-.25.78-.38 1.62-.38 2.5 0 .89.14 1.74.39 2.55l.31-.05c1.11 0 2 .92 2 2 0 .5-.16.93-.44 1.27.32.35.68.67 1.05.96l1.9-4.46c-.45-.65-.71-1.43-.71-2.27a4 4 0 0 1 4-4 4 4 0 0 1 4 4c0 .84-.26 1.62-.71 2.27l1.9 4.46c.38-.29.73-.62 1.06-.97m-6.25 5.24c-1 0-1.84-.74-2-1.71-.63-.13-1.25-.34-1.85-.6l-.98 2.31h-2.17l1.41-3.32c-.53-.38-1.02-.82-1.45-1.31-.24.1-.49.13-.76.13a2 2 0 0 1 -2-2c0-.62.3-1.18.77-1.55-.31-.95-.47-1.92-.47-2.95 0-1 .16-2 .46-2.92-.46-.37-.76-.93-.76-1.58 0-1.09.89-2 2-2 .26 0 .51.06.73.15 1.32-1.47 3.07-2.52 5.07-2.94.16-.97 1-1.71 2-1.71s1.84.74 2 1.71c2 .42 3.74 1.47 5.06 2.93.23-.09.48-.14.75-.14a2 2 0 0 1 2 2c0 .64-.31 1.21-.77 1.57.3.93.46 1.93.46 2.93s-.16 2-.46 2.93c.46.37.77.94.77 1.57 0 1.12-.89 2-2 2-.27 0-.52-.04-.76-.14-.44.49-.93.93-1.46 1.32l1.41 3.32h-2.17l-.98-2.31c-.6.26-1.22.47-1.85.6-.16.97-1 1.71-2 1.71z"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m17 8c-9 2-11.1 8.17-13.18 13.34l1.89.66.95-2.3c.48.17.98.3 1.34.3 11 0 14-17 14-17-1 2-8 2.25-13 3.25s-7 5.25-7 7.25 1.75 3.75 1.75 3.75c3.25-9.25 13.25-9.25 13.25-9.25z"/></svg>

After

Width:  |  Height:  |  Size: 271 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m14.53 1.45-1.08 1.08 1.6 1.6c.22.25.33.54.33.87s-.11.64-.33.86l-3.55 3.61 1 1.08 3.63-3.61c.53-.59.79-1.24.79-1.94s-.26-1.36-.79-1.95zm-3.98 2.02-1.08 1.08.61.56c.22.22.33.52.33.89s-.11.67-.33.89l-.61.56 1.08 1.08.56-.61c.53-.59.8-1.23.8-1.92 0-.72-.27-1.37-.8-1.97zm10.45 1.59c-.69 0-1.33.27-1.92.8l-5.63 5.64 1.08 1 5.58-5.56c.25-.25.55-.38.89-.38s.64.13.89.38l.61.61 1.03-1.08-.56-.61c-.59-.53-1.25-.8-1.97-.8m-14 2.94-5 14 14-5zm12 3.06c-.7 0-1.34.27-1.94.8l-1.59 1.59 1.08 1.08 1.59-1.59c.25-.25.53-.38.86-.38s.63.13.88.38l1.62 1.59 1.05-1.03-1.6-1.64c-.59-.53-1.25-.8-1.95-.8z"/></svg>

After

Width:  |  Height:  |  Size: 684 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m12 3-11 6 4 2.18v6l7 3.82 7-3.82v-6l2-1.09v6.91h2v-8zm6.82 6-6.82 3.72-6.82-3.72 6.82-3.72zm-1.82 7-5 2.72-5-2.72v-3.73l5 2.73 5-2.73z"/></svg>

After

Width:  |  Height:  |  Size: 236 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m4 15h2a2 2 0 0 1 2 2v2h1v-2a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2h1v-2a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2h1v3h-22v-3h1v-2a2 2 0 0 1 2-2m7-8 4 3-4 3zm-7-5h16a2 2 0 0 1 2 2v9.54c-.59-.35-1.27-.54-2-.54v-9h-16v9c-.73 0-1.41.19-2 .54v-9.54a2 2 0 0 1 2-2z"/></svg>

After

Width:  |  Height:  |  Size: 343 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m21.71 20.29-1.42 1.42a1 1 0 0 1 -1.41 0l-11.88-11.86a3.81 3.81 0 0 1 -1 .15 4 4 0 0 1 -3.78-5.3l2.54 2.54.53-.53 1.42-1.42.53-.53-2.54-2.54a4 4 0 0 1 5.3 3.78 3.81 3.81 0 0 1 -.15 1l11.86 11.88a1 1 0 0 1 0 1.41m-19.42-1.41a1 1 0 0 0 0 1.41l1.42 1.42a1 1 0 0 0 1.41 0l5.47-5.46-2.83-2.83m12.24-11.42-4 2v2l-2.17 2.17 2 2 2.17-2.17h2l2-4z"/></svg>

After

Width:  |  Height:  |  Size: 438 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m6 1v2h3v3.4l-4.89-2.02-2.68 6.46 5.54 2.3 4.97 3.68 1.85.77 3.83-9.24-1.85-.77-4.77-.71v-3.87h3v-2zm15.81 5.29-2.31.96.76 1.85 2.31-.96zm-2.03 7.28-.78 1.85 2.79 1.15.76-1.85zm-3.59 5.36-1.85.76.96 2.31 1.85-.77z"/></svg>

After

Width:  |  Height:  |  Size: 314 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m6 19h2v2h-2zm6-16-10 5v13h2v-8h16v8h2v-13zm-4 8h-4v-2h4zm6 0h-4v-2h4zm6 0h-4v-2h4zm-14 4h2v2h-2zm4 0h2v2h-2zm0 4h2v2h-2zm4 0h2v2h-2z"/></svg>

After

Width:  |  Height:  |  Size: 234 B

View File

@ -0,0 +1 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m19 7s-5 7-12.5 7c-2 0-5.5 1-5.5 5v4h11v-4c0-2.5 3-1 7-8l-1.5-1.5m-14.5-4.5v-3h20v14h-3m-9-15h4v2h-4zm-4.5 13c1.93299662 0 3.5-1.5670034 3.5-3.5 0-1.93299662-1.56700338-3.5-3.5-3.5s-3.5 1.56700338-3.5 3.5c0 1.9329966 1.56700338 3.5 3.5 3.5z" fill="none" stroke="#000" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 384 B

View File

@ -32,13 +32,23 @@
</div>
<h1>Les événements <em>{{ tag }}</em></h1></header>
{% if object %}
<p>{{ object.description|safe }}</p>
{% endif %}
{% include 'agenda_culturel/paginator.html' %}
</article>
{% for event in events %}
{% include "agenda_culturel/single-event/event-elegant-inc.html" with event=event day=0 %}
{% for event in paginator_filter %}
{% include "agenda_culturel/single-event/event-elegant-inc.html" with event=event day=0 %}
{% endfor %}
<article>
<footer>
{% include 'agenda_culturel/paginator.html' %}
</footer>
</article>
{% endblock %}

View File

@ -2095,11 +2095,25 @@ class TagDeleteView(PermissionRequiredMixin, DeleteView):
def view_tag(request, t):
events = Event.objects.filter(tags__contains=[t]).order_by(
"start_day", "start_time"
paginator = Paginator(
Event.objects.filter(tags__contains=[t]).order_by(
"start_day", "start_time"),
10,
)
page = request.GET.get("page")
try:
response = paginator.page(page)
except PageNotAnInteger:
response = paginator.page(1)
except EmptyPage:
response = paginator.page(paginator.num_pages)
tag = Tag.objects.filter(name=t).first()
context = {"tag": t, "events": events, "object": tag}
context = {"tag": t, "paginator_filter": response, "object": tag}
return render(request, "agenda_culturel/tag.html", context)