Import real-estate listings from CSV

Python · Django · intermediate · greenfield

Adds the Listing and ListingAudit models plus a management command to bulk-import real-estate listings from a CSV. A `Listing.save()` override handles slug generation and writes an audit row on create, and the importer reads the CSV, skips blanks, and writes everything in one efficient batch. Tested with a 200-line sample export on the staging DB — the success message reports 200 listings imported.

A real-estate platform with ~50k listings imported weekly from agency feeds. The management command replaces a slow per-row insert that was timing out on the full feed. The `listings` app (package and `apps.py` from `startapp`) is already in `INSTALLED_APPS`. Feed addresses are 1 to 500 characters after stripping. A crash between a listing insert and its audit row is out of scope for this PR: the weekly audit reconciliation backfills missing rows.

Requirements

Files touched

--- listings/models.py
+import re
+
+from django.db import models
+
+
+class Listing(models.Model):
+    address = models.CharField(max_length=500)
+    price_cents = models.PositiveIntegerField()
+    bedrooms = models.PositiveSmallIntegerField()
+    slug = models.CharField(max_length=500, default="")
+    created_at = models.DateTimeField(auto_now_add=True)
+
+    class Meta:
+        ordering = ["-created_at"]
+
+    def save(self, *args, **kwargs):
+        if self._state.adding:
+            self.slug = re.sub(
+                r"[^a-z0-9]+",
+                "-",
+                self.address.strip().lower(),
+            ).strip("-") or "listing"
+        is_new = self.pk is None
+        super().save(*args, **kwargs)
+        if is_new:
+            ListingAudit.objects.create(
+                listing=self, action="created"
+            )
+

Review this PR

Python practice