use formsets for screening questions, create views for applying to jobs
This commit is contained in:
parent
7b33b832fe
commit
34b77e8a4e
8 changed files with 128 additions and 13 deletions
|
@ -1,5 +1,5 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import Job, Application, Tag, Question
|
from .models import Job, Application, Tag, Question, Answer
|
||||||
|
|
||||||
admin.site.register([Job, Application, Tag, Question])
|
admin.site.register([Job, Application, Tag, Question, Answer])
|
||||||
|
|
|
@ -2,7 +2,7 @@ from django import forms
|
||||||
from django.forms import inlineformset_factory
|
from django.forms import inlineformset_factory
|
||||||
from dal.autocomplete import ModelSelect2Multiple
|
from dal.autocomplete import ModelSelect2Multiple
|
||||||
|
|
||||||
from .models import Job, Question
|
from .models import Job, Question, Application, Answer
|
||||||
|
|
||||||
|
|
||||||
class JobForm(forms.ModelForm):
|
class JobForm(forms.ModelForm):
|
||||||
|
@ -23,8 +23,37 @@ class QuestionForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Application
|
||||||
|
exclude = ('job', 'applicant')
|
||||||
|
|
||||||
|
|
||||||
|
class AnswerForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Answer
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields['text'].required = True
|
||||||
|
self.fields['question'].disabled = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def inlineformset_factory(cls, extra=3):
|
||||||
|
return inlineformset_factory(
|
||||||
|
Application,
|
||||||
|
Answer,
|
||||||
|
form=cls,
|
||||||
|
min_num=extra,
|
||||||
|
max_num=extra,
|
||||||
|
validate_min=True,
|
||||||
|
can_delete=False,
|
||||||
|
can_order=False)
|
||||||
|
|
||||||
|
|
||||||
QuestionFormSet = inlineformset_factory(
|
QuestionFormSet = inlineformset_factory(
|
||||||
Job, Question, form=QuestionForm, can_delete=False, can_order=False)
|
Job, Question, form=QuestionForm, can_delete=False, can_order=False)
|
||||||
|
|
||||||
QuestionUpdateFormSet = inlineformset_factory(
|
QuestionUpdateFormSet = inlineformset_factory(
|
||||||
Job, Question, form=QuestionForm, can_delete=True, can_order=False)
|
Job, Question, form=QuestionForm, can_delete=True, can_order=False)
|
||||||
|
|
23
jobs/migrations/0003_auto_20181020_0622.py
Normal file
23
jobs/migrations/0003_auto_20181020_0622.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 2.1.2 on 2018-10-20 06:22
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('jobs', '0002_auto_20181017_1104'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='application',
|
||||||
|
name='cover_letter',
|
||||||
|
field=models.TextField(blank=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='question',
|
||||||
|
name='name',
|
||||||
|
field=models.TextField(verbose_name='Question Title'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -70,6 +70,7 @@ class Application(models.Model):
|
||||||
User, related_name="applications", on_delete=models.CASCADE)
|
User, related_name="applications", on_delete=models.CASCADE)
|
||||||
job = models.ForeignKey(
|
job = models.ForeignKey(
|
||||||
Job, related_name="applications", on_delete=models.CASCADE)
|
Job, related_name="applications", on_delete=models.CASCADE)
|
||||||
|
cover_letter = models.TextField(blank=True)
|
||||||
|
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
|
13
jobs/templates/jobs/application_form.html
Normal file
13
jobs/templates/jobs/application_form.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends 'base.html' %} {% block title %}Apply to job{% endblock %} {% load crispy_forms_tags %} {% block body_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<form method="POST" action=".">
|
||||||
|
{% csrf_token %} {{ form |crispy }}
|
||||||
|
<h4>Screening Questions</h4>
|
||||||
|
{{ answer_form |crispy }}
|
||||||
|
<input class="btn btn-primary submit" type="submit" value="Post Job" />
|
||||||
|
</form>
|
||||||
|
{{form.media}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -22,7 +22,7 @@
|
||||||
- {{question.name}} <br/>
|
- {{question.name}} <br/>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<br/>
|
<br/>
|
||||||
<a href="#" class="card-link">Apply</a>
|
<a href="{% url 'jobs:job_apply' job.pk %}" class="card-link">Apply</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
12
jobs/urls.py
12
jobs/urls.py
|
@ -1,17 +1,17 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from . import views
|
from .views import Index, JobCreate, JobList, JobDetail, ApplicationCreate
|
||||||
from . import autocomplete as autocomplete_views
|
from . import autocomplete as autocomplete_views
|
||||||
|
|
||||||
app_name = 'jobs'
|
app_name = 'jobs'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.Index.as_view(), name='index'),
|
path('', Index.as_view(), name='index'),
|
||||||
path('jobs/create/', views.JobCreate.as_view(), name='create'),
|
path('jobs/create/', JobCreate.as_view(), name='create'),
|
||||||
path('jobs/', views.JobList.as_view(), name='list'),
|
path('jobs/', JobList.as_view(), name='list'),
|
||||||
path('jobs/<int:pk>/detail/', views.JobDetail.as_view(), name='job_detail'),
|
path('jobs/<int:pk>/detail/', JobDetail.as_view(), name='job_detail'),
|
||||||
|
path('jobs/<int:job_pk>/apply/', ApplicationCreate.as_view(), name='job_apply'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# autocomplete endpoints
|
# autocomplete endpoints
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
path(
|
path(
|
||||||
|
|
|
@ -4,8 +4,8 @@ from django.views.generic import (
|
||||||
TemplateView, ListView, CreateView, DetailView
|
TemplateView, ListView, CreateView, DetailView
|
||||||
)
|
)
|
||||||
|
|
||||||
from .models import Job
|
from .models import Job, Application, Question
|
||||||
from .forms import JobForm, QuestionFormSet
|
from .forms import JobForm, QuestionFormSet, ApplicationForm, AnswerForm
|
||||||
|
|
||||||
|
|
||||||
class Index(TemplateView):
|
class Index(TemplateView):
|
||||||
|
@ -59,3 +59,52 @@ class JobCreate(CreateView):
|
||||||
self.get_context_data(
|
self.get_context_data(
|
||||||
form=form,
|
form=form,
|
||||||
question_form=question_form))
|
question_form=question_form))
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationCreate(CreateView):
|
||||||
|
# TODO: restrict users from re-application
|
||||||
|
model = Application
|
||||||
|
form_class = ApplicationForm
|
||||||
|
success_url = reverse_lazy("jobs:list")
|
||||||
|
|
||||||
|
def get_question_queryset(self):
|
||||||
|
return Question.objects.filter(job_id=self.kwargs['job_pk']).order_by('id')
|
||||||
|
|
||||||
|
def get_answer_formset(self, *args):
|
||||||
|
questions = self.get_question_queryset()
|
||||||
|
return AnswerForm.inlineformset_factory(
|
||||||
|
extra=questions.count())(initial=[{
|
||||||
|
'question': q.id
|
||||||
|
} for q in questions], *args)
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
self.object = None
|
||||||
|
form = self.get_form(self.get_form_class())
|
||||||
|
answer_form = self.get_answer_formset()
|
||||||
|
return self.render_to_response(
|
||||||
|
self.get_context_data(form=form, answer_form=answer_form))
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
self.object = None
|
||||||
|
form_class = self.get_form_class()
|
||||||
|
form = self.get_form(form_class)
|
||||||
|
answer_form = self.get_answer_formset(self.request.POST)
|
||||||
|
if (form.is_valid() and answer_form.is_valid()):
|
||||||
|
return self.form_valid(form, answer_form)
|
||||||
|
else:
|
||||||
|
return self.form_invalid(form, answer_form)
|
||||||
|
|
||||||
|
def form_valid(self, form, answer_form):
|
||||||
|
self.object = form.save(commit=False)
|
||||||
|
self.object.applicant = self.request.user
|
||||||
|
self.object.job = Job.objects.get(id=self.kwargs['job_pk'])
|
||||||
|
self.object.save()
|
||||||
|
|
||||||
|
answer_form.instance = self.object
|
||||||
|
answer_form.save()
|
||||||
|
|
||||||
|
return HttpResponseRedirect(self.get_success_url())
|
||||||
|
|
||||||
|
def form_invalid(self, form, answer_form):
|
||||||
|
return self.render_to_response(
|
||||||
|
self.get_context_data(form=form, answer_form=answer_form))
|
||||||
|
|
Loading…
Reference in a new issue