diff --git a/resume/education/admin.py b/resume/education/admin.py index ef76252..963bafc 100644 --- a/resume/education/admin.py +++ b/resume/education/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin # Internal imports -from resume.education.models import Education, EducationSkill +from resume.education.models import Education, EducationSkill, Language class EducationSkillInline(SortableStackedInline, admin.TabularInline): @@ -20,3 +20,13 @@ class EducationAdmin(SortableAdminBase, admin.ModelAdmin): ordering = ('-end_date', '-start_date') readonly_fields = ('created_at', 'updated_at') inlines = [EducationSkillInline] + + +@admin.register(Language) +class LanguageAdmin(admin.ModelAdmin): + list_display = ('name', 'level') + list_display_links = ('name', 'level') + list_filter = ('name', 'level') + search_fields = ('name', 'level') + ordering = ('name',) + readonly_fields = ('created_at', 'updated_at') diff --git a/resume/education/migrations/0005_language.py b/resume/education/migrations/0005_language.py new file mode 100644 index 0000000..e890b61 --- /dev/null +++ b/resume/education/migrations/0005_language.py @@ -0,0 +1,32 @@ +# Generated by Django 4.0.5 on 2023-10-05 03:32 + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('profiles', '0004_alter_profile_skills'), + ('education', '0004_alter_education_gpa'), + ] + + operations = [ + migrations.CreateModel( + name='Language', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')), + ('name', models.CharField(max_length=255, verbose_name='Name')), + ('level', models.CharField(choices=[('basic', 'Elementary proficiency'), ('intermediate', 'Limited working proficiency'), ('advanced', 'Professional working proficiency'), ('fluent', 'Full professional proficiency'), ('native', 'Native or bilingual proficiency')], max_length=12, verbose_name='Level')), + ('profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='languages', to='profiles.profile', verbose_name='Profile')), + ], + options={ + 'verbose_name': 'Language', + 'verbose_name_plural': 'Languages', + 'ordering': ['name'], + }, + ), + ] diff --git a/resume/education/models.py b/resume/education/models.py index 567670a..54803ba 100644 --- a/resume/education/models.py +++ b/resume/education/models.py @@ -52,3 +52,27 @@ class Meta: verbose_name = _('Education Skill') verbose_name_plural = _('Education Skills') ordering = ['order'] + + +class Language(ModelBase): + class LanguageLevels(models.TextChoices): + BASIC = ('basic', _('Elementary proficiency')) + INTERMEDIATE = ('intermediate', _('Limited working proficiency')) + ADVANCED = ('advanced', _('Professional working proficiency')) + FLUENT = ('fluent', _('Full professional proficiency')) + NATIVE = ('native', _('Native or bilingual proficiency')) + + name = models.CharField(_('Name'), max_length=255, blank=False, null=False) + level = models.CharField(_('Level'), max_length=12, choices=LanguageLevels.choices, blank=False, null=False) + + profile = models.ForeignKey( + 'profiles.Profile', verbose_name='Profile', related_name='languages', on_delete=models.CASCADE + ) + + def __str__(self): + return f'{self.name} - {self.level}' + + class Meta: + verbose_name = _('Language') + verbose_name_plural = _('Languages') + ordering = ['name'] diff --git a/resume/education/serializers.py b/resume/education/serializers.py index a6b264f..443be1e 100644 --- a/resume/education/serializers.py +++ b/resume/education/serializers.py @@ -2,7 +2,7 @@ from rest_framework import serializers # Internal imports -from resume.education.models import Education +from resume.education.models import Education, Language class EducationSerializer(serializers.ModelSerializer): @@ -23,3 +23,13 @@ class Meta: 'country', 'skills', ) + + +class LanguageSerializer(serializers.ModelSerializer): + class Meta: + model = Language + fields = ( + 'name', + 'level', + ) + extra_kwargs = {'level': {'choices': Language.LanguageLevels.choices}} diff --git a/resume/education/viewsets.py b/resume/education/viewsets.py index e603f6b..65933fd 100644 --- a/resume/education/viewsets.py +++ b/resume/education/viewsets.py @@ -2,11 +2,17 @@ from rest_framework import viewsets # Internal imports -from resume.education.models import Education -from resume.education.serializers import EducationSerializer +from resume.education.models import Education, Language +from resume.education.serializers import EducationSerializer, LanguageSerializer class EducationViewSet(viewsets.ModelViewSet): queryset = Education.objects.all() serializer_class = EducationSerializer permission_classes = [] + + +class LanguageViewSet(viewsets.ModelViewSet): + queryset = Language.objects.all() + serializer_class = LanguageSerializer + permission_classes = [] diff --git a/resume/profiles/admin.py b/resume/profiles/admin.py index 5d873fb..ca390e1 100644 --- a/resume/profiles/admin.py +++ b/resume/profiles/admin.py @@ -4,7 +4,7 @@ from django.forms import ModelForm, ModelMultipleChoiceField, SelectMultiple # Internal imports -from resume.education.models import Education +from resume.education.models import Education, Language from resume.profiles.models import Profile, SocialLink from resume.roles.models import Role from resume.skills.models import Skill @@ -25,6 +25,11 @@ class EducationInline(admin.TabularInline): extra = 1 +class LanguageInline(admin.TabularInline): + model = Language + extra = 1 + + class ProfileSkillInline(SortableStackedInline, admin.TabularInline): model = Profile.skills.through extra = 1 @@ -52,6 +57,7 @@ class ProfileAdmin(SortableAdminBase, admin.ModelAdmin): SocialLinkInline, RoleInline, EducationInline, + LanguageInline, ProfileSkillInline, ) diff --git a/resume/profiles/serializers.py b/resume/profiles/serializers.py index 3c3a0f8..7bec7cf 100644 --- a/resume/profiles/serializers.py +++ b/resume/profiles/serializers.py @@ -2,7 +2,7 @@ from rest_framework import serializers # Internal imports -from resume.education.serializers import EducationSerializer +from resume.education.serializers import EducationSerializer, LanguageSerializer from resume.profiles.models import Profile, SocialLink from resume.roles.serializers import RoleSerializer from resume.skills.serializers import SkillSerializer @@ -42,6 +42,7 @@ class ProfileSerializer(serializers.ModelSerializer): social_links = SocialLinkSerializer(many=True) roles = RoleSerializer(many=True) education = EducationSerializer(many=True) + languages = LanguageSerializer(many=True) skills = SkillSerializer(many=True) def get_name(self, obj): # noqa @@ -62,6 +63,7 @@ class Meta: 'social_links', 'roles', 'education', + 'languages', 'skills', )