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:
parent
f5d753d441
commit
cc39c22e87
|
|
@ -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': '简历',
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -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']
|
||||
|
|
@ -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
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
from django.urls import path
|
||||
from .views import MyResumeView
|
||||
|
||||
urlpatterns = []
|
||||
urlpatterns = [
|
||||
path('me/', MyResumeView.as_view()),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in New Issue