Foreword
To write this article, a very large layer of material was studied, scattered all over the Internet, in forums, chats, blog sites, stackoverflow. I put it all together, as it will be useful to me and I really hope that other Django developers will also be happy with this material. If there is anything to add (improve) or correct, please write in the comments or in Dialogues (private messages) Habr.
Handler 404 testing
If we try to test the 404 error with the given debug = True, then we will receive a standard Django error report indicating the reason, but using the following method you can check that the 404 error is working without unnecessary worries. On a working site, I highly recommend using nginx.
Open for editing the settings.py file located in the project directory and set the value debug = False
In the same directory, open the urls.py file for editing and add the following lines:
from django.urls import re_path
from django.views.static import serve #
re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
re_path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}),
debug false, , , django nginx, , , 404 Django localhost, python manage.py runserver .
, , Python/Django , .
( :
: habrhabr
: pp#6JZ2\a7y=
: , .
, Worker - FK Experience:
class Worker(models.Model):
public_cv = models.BooleanField(default=False, verbose_name='Can everyone see your resume ?')
cv_name = models.CharField(max_length=250, verbose_name='CV name', blank=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name='Author', default=0)
# +
def __str__(self):
return self.name
def publish(self):
self.published_date = timezone.now()
self.save()
class Experience(models.Model):
worker = models.ForeignKey(Worker, on_delete=models.CASCADE)
title = models.CharField(max_length=200, verbose_name='Position name')
# +
def __str__(self):
return self.title
def publish(self):
self.published_date = timezone.now()
self.save()
# +
, - django-admin, StackedInline:
class ExperienceInstance(admin.StackedInline):
model = Experience
extra = 1
@admin.register(Worker)
class PublishWorkers(admin.ModelAdmin):
inlines = [
ExperienceInstance,]
Django-admin, Experience Worker " Experience":
views.py , Experience Experience, Formset:
from django.forms import inlineformset_factory
from django.http import HttpResponseRedirect
from .forms import ExperienceForm
def expformview(request, worker_uid):
worker = Worker.objects.get(uid=worker_uid)
ExperienceFormset = inlineformset_factory(
Worker, Experience, form=ExperienceForm, extra=1, max_num=15, can_delete=True
)
if request.method == 'POST':
formset = ExperienceFormset(request.POST, instance=worker)
if formset.is_valid():
formset.save()
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
formset = ExperienceFormset(instance=worker)
return render(request, 'site/expform.html',
{
'formset': formset,
'worker': worker,
}
)
, forms.py ExperienceForm:
class ExperienceForm(forms.ModelForm):
started = forms.DateField(
required=False,
label='Start date',
widget=forms.TextInput(attrs={'placeholder': 'YYYY-MM-DD'})
)
ended = forms.DateField(
required=False,
label='End date',
widget=forms.TextInput(attrs={'placeholder': 'YYYY-MM-DD'})
)
class Meta:
model = Experience
fields = ('title',
'selfedu',
)
HTML. Crispy . {{formset.media}}
WYSIWYG- ckeditor. type="submit"
, :
HTML
{% extends 'site/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% if worker.author == request.user%}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Experience | {{worker}}</title>
</head>
<body>
<center>
<div class="col-lg-5" style="margin:1em;">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">Basic information</li>
<li class="breadcrumb-item active" aria-current="page"><b>Experience</b></li>
<li class="breadcrumb-item">Education</li>
<li class="breadcrumb-item">Certification</li>
<li class="breadcrumb-item">Awards</li>
<li class="breadcrumb-item">Projects</li>
</ol>
</nav>
</div>
</center>
<h2 align="center" style="margin:1em;">{{worker}}'s Experience form</h2>
<form method="post">
{% csrf_token %}
<div class="row" style="margin:2em 0 2em 0;">
<div class="col-lg-5 mx-auto">
{{formset.media}}
{{formset|crispy}}
</div>
<div class="col-lg-12">
<center><button type="submit" class="btn btn-outline-warning">Save & Add</button>
<a href="edu"><button type="button" class="btn btn-outline-success">Next > Education</button></a></center>
</div>
</div>
</form>
</body>
</html>
{%else%}
<div class="row">
<div class="col-lg-12" style="margin-top:6em;">
<center>
<h2>You have not access to this section</h2>
</center>
</div>
</div>
{%endif%}
{% endblock %}
:
PDF ( )
, HTML PDF XHTML2PDF; venv :
pip install xhtml2pdf
views.py:
from xhtml2pdf import pisa
def render_pdf_view(request, worker_uid):
template_path = 'site/pdf.html'
worker = Worker.objects.get(uid=worker_uid)
exp = Experience.objects.filter(worker=worker)
context = {
'worker': worker,
'exp': exp,
}
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'filename="%s_%s.pdf"' % (worker.name, worker.created_date.strftime('%Y-%m-%d')) # PDF : _--
#
template = get_template(template_path)
html = template.render(context)
# PDF
pisa_status = pisa.CreatePDF(html, dest=response, )
#
if pisa_status.err:
return HttpResponse('We had some errors <pre>' + html + '</pre>')
return response
HTML , , PDF , <style></style>
.
To Russian characters are correctly displayed in the exported PDF you want to download a font that supports the Cyrillic (Russian) letters, and put it in the static / fonts /, at the same time indicate to-text file full path in view of system directories, such as in my case, the path looks like this: /var/www/cvmaker/static/fonts/arial.ttf
, and <style/>
add the following between the tags :
@font-face {
font-family: 'sans-serif';
src: url("/var/www/cvmaker/static/fonts/arial.ttf");
}
body{
font-family: "sans-serif";
}
Thus, in the exported PDF file, instead of black squares in place of Russian letters, we see normal Cyrillic characters: