First commit
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
# 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'],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.30 on 2026-05-28 08:20
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('properties', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='property',
|
||||
name='total_area',
|
||||
field=models.DecimalField(decimal_places=0, default=0, max_digits=8, verbose_name='surface totale (m²)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='property',
|
||||
name='condition',
|
||||
field=models.CharField(choices=[('new', 'Neuf'), ('exellent', 'Exellent état'), ('good', 'Bon état'), ('to_refresh', 'À rafraîchir'), ('to_renovate', 'À rénover')], max_length=20, verbose_name='état du bien'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,43 @@
|
||||
# Generated by Django 4.2.30 on 2026-05-28 16:59
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('properties', '0002_property_total_area_alter_property_condition'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='property',
|
||||
name='meta_description_en',
|
||||
field=models.CharField(blank=True, max_length=160, verbose_name='SEO description (English)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='property',
|
||||
name='meta_description_fr',
|
||||
field=models.CharField(blank=True, max_length=160, verbose_name='description SEO (français)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='property',
|
||||
name='meta_keywords_en',
|
||||
field=models.CharField(blank=True, max_length=300, verbose_name='SEO keywords (English)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='property',
|
||||
name='meta_keywords_fr',
|
||||
field=models.CharField(blank=True, max_length=300, verbose_name='mots-clés SEO (français)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='property',
|
||||
name='meta_title_en',
|
||||
field=models.CharField(blank=True, max_length=70, verbose_name='SEO title (English)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='property',
|
||||
name='meta_title_fr',
|
||||
field=models.CharField(blank=True, max_length=70, verbose_name='titre SEO (français)'),
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user