Prefacio
Para escribir este artículo, se estudió una capa muy grande de material, esparcido por Internet, en foros, chats, blogs, stackoverflow. Lo puse todo junto, ya que me será útil y realmente espero que otros desarrolladores de Django también estén contentos con este material. Si hay algo que agregar (mejorar) o corregir, por favor escriba en los comentarios o en Diálogos (mensajes privados) Habr.
Prueba del controlador 404
Si intentamos probar el error 404 con la depuración dada = Verdadero, entonces recibiremos un informe de error estándar de Django indicando el motivo, pero usando el siguiente método puede verificar que el error 404 está funcionando sin preocupaciones innecesarias. En un sitio de trabajo, recomiendo encarecidamente usar nginx.
Abra para editar el archivo settings.py ubicado en el directorio del proyecto y establezca el valor debug = False
En el mismo directorio, abra el archivo urls.py para editarlo y agregue las siguientes líneas:
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>
.
Para que los caracteres rusos se muestren correctamente en el PDF exportado, desea descargar una fuente que admita las letras cirílicas (rusas) y ponerla en estática / fuentes /, al mismo tiempo, indique la ruta completa del archivo de texto a la vista del sistema directorios, como en mi caso, la ruta se ve así:, /var/www/cvmaker/static/fonts/arial.ttf
y <style/>
agregue lo siguiente entre las etiquetas :
@font-face {
font-family: 'sans-serif';
src: url("/var/www/cvmaker/static/fonts/arial.ttf");
}
body{
font-family: "sans-serif";
}
Por lo tanto, en el archivo PDF exportado, en lugar de cuadrados negros en lugar de letras rusas, vemos caracteres cirílicos normales: