Русский
Русский
English
Статистика
Реклама

Полезности для разработчика на Django

Предисловие

Для написания данной статьи был изучен очень большой пласт материала, разбросанного по всему Интернету, по форумам, чатам, сайтам-блогам, stackoverflow. Я собрал все воедино, так как это пригодится и мне и очень надеюсь, что другие разработчики на Django, также, останутся довольны данным материалом. Если есть что добавить (улучшить) или поправить, пожалуйста, пишите в комментариях или в Диалоги ( личные сообщения ) Хабр.

Тестирование handler 404

Если мы попытаемся тестировать ошибку 404 при заданном debug = True, то будет получать стандартный для Django отчет об ошибке с указанием о причине, но используя следующий метод вы сможете проверить работоспособность отработки 404 ошибки без лишних забот. На работающем сайте настоятельно рекомендую использовать nginx.

  1. Открываем для редактирования файл settings.py, находящийся в каталоге проекта и устанавливаем значение debug = False

  2. В том же каталоге открываем для редактирования файл urls.py и добавляем следующие строки:

from django.urls import re_pathfrom 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_URL}),

При переключении 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_factoryfrom django.http import HttpResponseRedirectfrom .forms import ExperienceFormdef 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 pisadef 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> в данном шаблоне.

Чтобы русские символы корректно отображались в экспортируемом PDF необходимо загрузить шрифт с поддержкой кириллических (русских) букв и положить его в static/fonts/ , при этом указать до файла-шрифта полный путь с учетом системных каталогов, например в моем случае путь выглядит так:/var/www/cvmaker/static/fonts/arial.ttf , а между тегами <style/> добавляем следующее:

@font-face {         font-family: 'sans-serif';         src: url("/var/www/cvmaker/static/fonts/arial.ttf");         }         body{         font-family: "sans-serif";         }

Таким образом в экспортируемом PDF-файле мы видим вместо черных квадратиков на месте русских букв нормальные кириллические символы:

Источник: habr.com
К списку статей
Опубликовано: 05.04.2021 14:09:20
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Разработка веб-сайтов

Python

Django

Xhtml2pdf

Formset

Разработка сайтов

Html

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru