feat: add Resume model with JSONB fields and file upload

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
TianyangZhang 2026-03-24 17:43:24 +08:00
parent f5d753d441
commit cc39c22e87
8 changed files with 126 additions and 1 deletions

View File

@ -0,0 +1,34 @@
# Generated by Django 4.2.20 on 2026-03-24 09:43
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Resume',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50, verbose_name='姓名')),
('gender', models.CharField(blank=True, choices=[('male', ''), ('female', ''), ('other', '其他')], max_length=10)),
('birthday', models.DateField(blank=True, null=True)),
('education', models.JSONField(default=list, verbose_name='教育经历')),
('experience', models.JSONField(default=list, verbose_name='工作经历')),
('attachment', models.FileField(blank=True, null=True, upload_to='resumes/')),
('updated_at', models.DateTimeField(auto_now=True)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='resume', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': '简历',
},
),
]

View File

@ -0,0 +1,32 @@
from django.db import models
from django.conf import settings
class Resume(models.Model):
GENDER_CHOICES = [('male', ''), ('female', ''), ('other', '其他')]
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='resume'
)
name = models.CharField(max_length=50, verbose_name='姓名')
gender = models.CharField(max_length=10, choices=GENDER_CHOICES, blank=True)
birthday = models.DateField(null=True, blank=True)
education = models.JSONField(default=list, verbose_name='教育经历')
experience = models.JSONField(default=list, verbose_name='工作经历')
attachment = models.FileField(upload_to='resumes/', null=True, blank=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = '简历'
def to_snapshot(self):
"""序列化为投递快照,与主表解耦"""
return {
'name': self.name,
'gender': self.gender,
'birthday': str(self.birthday) if self.birthday else None,
'education': self.education,
'experience': self.experience,
'attachment_url': self.attachment.url if self.attachment else None,
}

View File

@ -0,0 +1,10 @@
from rest_framework import serializers
from .models import Resume
class ResumeSerializer(serializers.ModelSerializer):
class Meta:
model = Resume
fields = ['id', 'name', 'gender', 'birthday', 'education',
'experience', 'attachment', 'updated_at']
read_only_fields = ['updated_at']

View File

@ -0,0 +1,29 @@
import pytest
from django.contrib.auth import get_user_model
from apps.resumes.models import Resume
User = get_user_model()
@pytest.fixture
def seeker():
return User.objects.create_user(username='seeker1', password='pass', role='seeker')
@pytest.mark.django_db
class TestResumeModel:
def test_create_resume(self, seeker):
resume = Resume.objects.create(
user=seeker,
name='张三',
gender='male',
education=[{'school': '北京大学', 'degree': '本科', 'major': '计算机'}],
experience=[{'company': 'ABC公司', 'position': '工程师', 'duration': '2年'}],
)
assert resume.name == '张三'
assert len(resume.education) == 1
assert len(resume.experience) == 1
def test_seeker_has_one_resume(self, seeker):
Resume.objects.create(user=seeker, name='张三')
assert Resume.objects.filter(user=seeker).count() == 1

View File

@ -1,3 +1,6 @@
from django.urls import path
from .views import MyResumeView
urlpatterns = []
urlpatterns = [
path('me/', MyResumeView.as_view()),
]

View File

@ -0,0 +1,17 @@
from rest_framework import generics
from .models import Resume
from .serializers import ResumeSerializer
from apps.accounts.permissions import IsSeeker
class MyResumeView(generics.RetrieveUpdateAPIView):
"""求职者获取/更新自己的简历(不存在则自动创建)"""
serializer_class = ResumeSerializer
permission_classes = [IsSeeker]
def get_object(self):
resume, _ = Resume.objects.get_or_create(
user=self.request.user,
defaults={'name': self.request.user.username}
)
return resume