去年帮朋友改造房产中介的业务系统时,我基于Python技术栈设计了一套房屋租赁管理系统。这个项目融合了Flask的轻量灵活和Django的全能生态,实现了从房源采集到合同管理的全流程数字化。相比市面上动辄数十万的商业软件,这套系统用开源技术栈实现了90%的核心功能,特别适合中小型中介机构或房东群体使用。
系统最核心的价值在于解决了三个痛点:一是通过自动化爬虫聚合多平台房源,二是用智能匹配算法连接租客需求与房源特征,三是电子合同签署与租金提醒功能降低了人工管理成本。整个系统采用前后端分离架构,前端用Vue.js实现响应式界面,后端API分别用Flask和Django构建不同服务模块,数据库则按业务场景混合使用PostgreSQL和MongoDB。
在技术选型阶段,我对比了三种方案:
最终选择混合方案主要基于以下考量:
经验提示:混合架构中要特别注意路由命名冲突,建议给Flask服务添加
/api/flask/前缀,Django服务使用/api/django/前缀
整个系统分为六个核心模块:
| 模块名称 | 技术栈 | 核心功能 | 数据存储 |
|---|---|---|---|
| 用户中心 | Django | 注册登录、权限管理 | PostgreSQL |
| 房源管理 | Django | 房源CRUD、图片处理 | PostgreSQL |
| 爬虫调度中心 | Flask | 多平台房源采集、数据清洗 | MongoDB |
| 智能推荐 | Flask | 租客偏好匹配、排序算法 | Redis |
| 合同管理 | Django | 电子签章、租金提醒 | PostgreSQL |
| 数据分析 | Flask | 房源热度统计、租金走势 | MongoDB |
数据流动采用事件驱动架构,关键流程举例:
房源数据采集面临三个主要挑战:反爬机制、数据异构和增量更新。我的解决方案是:
python复制# 基于Scrapy+Selenuim的动态爬虫示例
class LianjiaSpider(scrapy.Spider):
name = "lianjia"
def start_requests(self):
# 使用代理中间件
yield scrapy.Request(
url="https://sh.lianjia.com/zufang",
meta={"proxy": "http://proxy_pool:5010"},
callback=self.parse_district
)
def parse_district(self, response):
# 处理动态渲染内容
driver = response.meta.get('driver')
if not driver:
driver = webdriver.Chrome()
driver.get(response.url)
# 模拟人类滚动行为
for _ in range(3):
driver.execute_script("window.scrollBy(0, 800)")
time.sleep(random.uniform(1, 3))
# 提取结构化数据
items = []
for card in driver.find_elements(By.CSS_SELECTOR, '.content__list--item'):
item = RentalItem()
item['source'] = 'lianjia'
item['title'] = card.find_element(...).text
# 其他字段解析...
items.append(item)
# 存入MongoDB并去重
self.mongo_collection.bulk_write([
UpdateOne(
{'hash': md5(item['url'])},
{'$set': dict(item)},
upsert=True
) for item in items
])
关键优化点:
推荐算法采用特征工程+轻量级机器学习方案:
python复制# 基于特征的房源排序算法
class RecommendationEngine:
def __init__(self):
self.user_features = UserFeatureLoader()
self.house_features = HouseFeatureLoader()
def recommend(self, user_id, top_n=10):
# 加载用户画像
u_feats = self.user_features.get(user_id)
# 候选房源初筛
candidates = self._preselect(u_feats)
# 计算匹配分数
scores = []
for house in candidates:
h_feats = self.house_features.get(house['id'])
score = self._calculate_score(u_feats, h_feats)
scores.append((house, score))
# 排序返回
return sorted(scores, key=lambda x: -x[1])[:top_n]
def _calculate_score(self, u_feats, h_feats):
# 价格权重(非线性处理)
price_score = 1 / (1 + abs(u_feats['price_pref'] - h_feats['price'])/1000)
# 位置分(地理距离)
loc_score = 1 / (1 + haversine(u_feats['loc'], h_feats['loc']))
# 特征交叉
cross_features = [
u_feats['like_style'] == h_feats['style'],
u_feats['require_parking'] and h_feats['has_parking'],
# 其他交叉特征...
]
return 0.4*price_score + 0.3*loc_score + 0.3*sum(cross_features)
实际应用中还需要考虑:
项目根目录结构如下:
code复制rental_system/
├── django_app/ # Django主项目
│ ├── settings.py # 包含FLASK_SERVICE_URL配置
│ └── urls.py
├── flask_app/ # Flask微服务
│ ├── requirements.txt
│ └── app.py
├── shared/ # 公共代码
│ ├── models.py # 通用数据模型
│ └── utils.py # 工具函数
└── docker-compose.yml
关键集成点处理:
会话共享:使用Redis存储Session
python复制# Django配置
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
# Flask配置
app.secret_key = 'same_as_django'
app.config['SESSION_TYPE'] = 'redis'
跨服务API调用
python复制# Django中调用Flask服务
import requests
def get_recommendations(user_id):
url = f"{settings.FLASK_SERVICE_URL}/recommend/{user_id}"
try:
resp = requests.get(url, timeout=3)
return resp.json()
except requests.exceptions.RequestException:
return []
统一认证处理
python复制# Flask中的JWT验证装饰器
from functools import wraps
import jwt
def django_jwt_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
token = request.headers.get('Authorization')
try:
payload = jwt.decode(
token,
'django_secret_key', # 与Django设置一致
algorithms=['HS256']
)
g.user_id = payload['user_id']
except Exception:
return {'error': 'Invalid token'}, 401
return f(*args, **kwargs)
return decorated_function
在压力测试中发现的三个性能瓶颈及解决方案:
房源列表页响应慢
python复制# 优化前的危险代码
houses = House.objects.all()
result = [{
'id': h.id,
'owner': h.owner.name, # 每次访问触发新查询
# ...
} for h in houses]
# 优化方案
houses = House.objects.select_related('owner').prefetch_related('images')
paginator = Paginator(houses, per_page=20)
推荐计算耗时
图片加载卡顿
使用Docker Compose编排服务:
yaml复制version: '3.8'
services:
django:
build: ./django_app
ports:
- "8000:8000"
depends_on:
- redis
- postgres
flask:
build: ./flask_app
ports:
- "5000:5000"
environment:
- MONGO_URI=mongodb://mongo:27017
postgres:
image: postgres:13
volumes:
- pg_data:/var/lib/postgresql/data
mongo:
image: mongo:4.4
volumes:
- mongo_data:/data/db
redis:
image: redis:6
volumes:
pg_data:
mongo_data:
关键配置经验:
yaml复制django:
deploy:
resources:
limits:
cpus: '1'
memory: 1G
python复制# Django日志配置示例
LOGGING = {
'handlers': {
'file': {
'class': 'logging.handlers.RotatingFileHandler',
'filename': '/var/log/django/app.log',
'maxBytes': 1024*1024*5, # 5MB
'backupCount': 5,
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'INFO',
},
},
}
推荐使用Prometheus+Grafana监控以下指标:
Django服务:
Flask服务:
基础设施:
告警规则示例:
yaml复制# prometheus/rules.yml
groups:
- name: django-alerts
rules:
- alert: HighErrorRate
expr: sum(rate(django_http_requests_total{status=~"5.."}[5m])) by (path) / sum(rate(django_http_requests_total[5m])) by (path) > 0.05
for: 10m
labels:
severity: critical
annotations:
summary: "High error rate on {{ $labels.path }}"
Django与Flask的静态文件冲突
python复制# flask_app/app.py
app = Flask(__name__, static_folder='flask_static')
跨服务事务不一致
python复制def create_order():
try:
# 步骤1:扣款
payment_service.charge()
# 步骤2:生成合同
contract = ContractService.create()
# 步骤3:更新房源状态
HouseService.reserve()
except Exception as e:
# 逆向操作
if 'contract' in locals():
ContractService.revert(contract.id)
raise e
地理位置查询性能差
sql复制-- 创建空间索引
CREATE INDEX idx_house_location ON house USING GIST(location);
-- 附近房源查询
SELECT * FROM house
WHERE ST_DWithin(
location,
ST_MakePoint(121.47, 31.23)::geography,
1000 -- 1公里范围内
);
测试策略
代码组织规范
性能优化路线图
mermaid复制graph TD
A[基准测试] --> B[识别瓶颈]
B --> C{类型}
C -->|数据库| D[查询优化+索引]
C -->|网络| E[CDN+压缩]
C -->|计算| F[异步任务+缓存]
这套系统经过半年生产环境验证,目前日均处理:
最让我自豪的是帮助客户将房源匹配效率提升了60%,人工管理时间减少了75%。如果让我重新设计,我会在以下方面改进: