# Generated by Django 4.2.30 on 2026-05-28 07:31 from django.db import migrations, models import django.db.models.deletion import django_resized.forms import properties.models class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Property', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name_fr', models.CharField(max_length=200, verbose_name='nom (français)')), ('name_en', models.CharField(max_length=200, verbose_name='name (English)')), ('slug', models.SlugField(blank=True, max_length=220, unique=True, verbose_name='slug')), ('property_type', models.CharField(choices=[('house', 'Maison'), ('apartment', 'Appartement'), ('land', 'Terrain'), ('commercial', 'Local commercial'), ('other', 'Autre')], max_length=20, verbose_name='type de bien')), ('status', models.CharField(choices=[('sale', 'À vendre'), ('rent', 'À louer')], max_length=10, verbose_name='statut')), ('is_active', models.BooleanField(default=True, verbose_name='actif / visible')), ('price', models.DecimalField(decimal_places=0, max_digits=12, verbose_name='prix (€)')), ('price_on_request', models.BooleanField(default=False, verbose_name='prix sur demande')), ('total_land_area', models.DecimalField(blank=True, decimal_places=0, max_digits=10, null=True, verbose_name='surface totale du terrain (m²)')), ('living_area', models.DecimalField(decimal_places=0, max_digits=8, verbose_name='surface habitable (m²)')), ('rooms_count', models.PositiveSmallIntegerField(verbose_name='nombre de pièces')), ('bedrooms_count', models.PositiveSmallIntegerField(verbose_name='nombre de chambres')), ('bathrooms_count', models.PositiveSmallIntegerField(verbose_name="nombre de salles d'eau")), ('has_elevator', models.BooleanField(default=False, verbose_name='ascenseur')), ('exposure', models.CharField(blank=True, choices=[('N', 'Nord'), ('S', 'Sud'), ('E', 'Est'), ('O', 'Ouest'), ('NE', 'Nord-Est'), ('NO', 'Nord-Ouest'), ('SE', 'Sud-Est'), ('SO', 'Sud-Ouest')], max_length=2, verbose_name='exposition')), ('has_garden', models.BooleanField(default=False, verbose_name='jardin')), ('has_pool', models.BooleanField(default=False, verbose_name='piscine')), ('has_dependencies', models.BooleanField(default=False, verbose_name='dépendances')), ('construction_year', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='année de construction')), ('condition', models.CharField(choices=[('new', 'Neuf'), ('good', 'Bon état'), ('to_refresh', 'À rafraîchir'), ('to_renovate', 'À rénover')], max_length=20, verbose_name='état du bien')), ('energy_class', models.CharField(blank=True, choices=[('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D'), ('E', 'E'), ('F', 'F'), ('G', 'G')], max_length=1, verbose_name='classe énergie (DPE)')), ('energy_value', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='valeur DPE (kWh/m²/an)')), ('ges_class', models.CharField(blank=True, choices=[('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D'), ('E', 'E'), ('F', 'F'), ('G', 'G')], max_length=1, verbose_name='classe GES')), ('ges_value', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='valeur GES (kgCO₂/m²/an)')), ('description_fr', models.TextField(verbose_name='description (français)')), ('description_en', models.TextField(verbose_name='description (English)')), ('address', models.CharField(max_length=300, verbose_name='adresse')), ('city', models.CharField(max_length=100, verbose_name='ville')), ('postal_code', models.CharField(max_length=10, verbose_name='code postal')), ('latitude', models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True, verbose_name='latitude')), ('longitude', models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True, verbose_name='longitude')), ('thumbnail', django_resized.forms.ResizedImageField(blank=True, crop=None, force_format='WEBP', keep_meta=True, null=True, quality=85, scale=1.0, size=[900, 600], upload_to='properties/covers/', verbose_name='image de couverture')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='créé le')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='modifié le')), ], options={ 'verbose_name': 'bien immobilier', 'verbose_name_plural': 'biens immobiliers', 'ordering': ['-created_at'], }, bases=(properties.models.BilingualMixin, models.Model), ), migrations.CreateModel( name='PropertyFeature', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name_fr', models.CharField(max_length=100, verbose_name='nom (français)')), ('name_en', models.CharField(max_length=100, verbose_name='name (English)')), ('icon', models.CharField(blank=True, help_text='Classe CSS ou caractère unicode (ex: 🔥)', max_length=50, verbose_name='icône')), ], options={ 'verbose_name': 'caractéristique', 'verbose_name_plural': 'caractéristiques', 'ordering': ['name_fr'], }, bases=(properties.models.BilingualMixin, models.Model), ), migrations.CreateModel( name='Room', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name_fr', models.CharField(max_length=100, verbose_name='nom (français)')), ('name_en', models.CharField(max_length=100, verbose_name='name (English)')), ('order', models.PositiveSmallIntegerField(db_index=True, default=0, verbose_name='ordre')), ('property', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rooms', to='properties.property', verbose_name='bien')), ], options={ 'verbose_name': 'pièce', 'verbose_name_plural': 'pièces', 'ordering': ['order', 'id'], }, bases=(properties.models.BilingualMixin, models.Model), ), migrations.CreateModel( name='PropertyEnvironment', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('location_type', models.CharField(choices=[('city', 'Ville'), ('village', 'Village'), ('countryside', 'Campagne')], max_length=20, verbose_name='type de localisation')), ('description_fr', models.TextField(blank=True, verbose_name='description géographique (français)')), ('description_en', models.TextField(blank=True, verbose_name='geographic description (English)')), ('has_supermarket', models.BooleanField(default=False, verbose_name='supérette')), ('has_food_shop', models.BooleanField(default=False, verbose_name='alimentation')), ('has_bakery', models.BooleanField(default=False, verbose_name='boulangerie')), ('has_newspaper_shop', models.BooleanField(default=False, verbose_name='journaux / tabac presse')), ('has_bar', models.BooleanField(default=False, verbose_name='bar / café')), ('has_tobacco_shop', models.BooleanField(default=False, verbose_name='bureau de tabac')), ('has_garage', models.BooleanField(default=False, verbose_name='garage / garagiste')), ('has_gas_station', models.BooleanField(default=False, verbose_name='station essence')), ('has_city_hall_services', models.BooleanField(default=False, verbose_name='services de la mairie')), ('has_nursery', models.BooleanField(default=False, verbose_name='crèche')), ('has_public_school', models.BooleanField(default=False, verbose_name='école publique')), ('has_doctor', models.BooleanField(default=False, verbose_name='médecin')), ('has_pharmacy', models.BooleanField(default=False, verbose_name='pharmacie')), ('has_physiotherapist', models.BooleanField(default=False, verbose_name='cabinet kinésithérapeute')), ('has_nurse', models.BooleanField(default=False, verbose_name='cabinet infirmier')), ('property', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='environment', to='properties.property', verbose_name='bien')), ], options={ 'verbose_name': 'environnement', 'verbose_name_plural': 'environnements', }, bases=(properties.models.BilingualMixin, models.Model), ), migrations.AddField( model_name='property', name='features', field=models.ManyToManyField(blank=True, to='properties.propertyfeature', verbose_name='caractéristiques'), ), migrations.CreateModel( name='Photo', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('image', django_resized.forms.ResizedImageField(crop=None, force_format='WEBP', keep_meta=True, quality=85, scale=1.0, size=[1600, 1067], upload_to='properties/photos/', verbose_name='image')), ('caption_fr', models.CharField(blank=True, max_length=200, verbose_name='légende (français)')), ('caption_en', models.CharField(blank=True, max_length=200, verbose_name='caption (English)')), ('is_cover', models.BooleanField(default=False, verbose_name='photo de couverture')), ('order', models.PositiveSmallIntegerField(db_index=True, default=0, verbose_name='ordre')), ('property', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='properties.property', verbose_name='bien')), ('room', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='photos', to='properties.room', verbose_name='pièce')), ], options={ 'verbose_name': 'photo', 'verbose_name_plural': 'photos', 'ordering': ['order', 'id'], }, bases=(properties.models.BilingualMixin, models.Model), ), migrations.CreateModel( name='ContactRequest', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=200, verbose_name='nom')), ('email', models.EmailField(max_length=254, verbose_name='email')), ('phone', models.CharField(blank=True, max_length=30, verbose_name='téléphone')), ('message', models.TextField(verbose_name='message')), ('ip_address', models.GenericIPAddressField(blank=True, null=True, verbose_name='adresse IP')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='reçu le')), ('property', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='contact_requests', to='properties.property', verbose_name='bien concerné')), ], options={ 'verbose_name': 'demande de contact', 'verbose_name_plural': 'demandes de contact', 'ordering': ['-created_at'], }, ), ]