Мой кабинет. Профиль пользователя.

Видео отсутствует

Мой кабинет. Профиль пользователя.

Создадим новое приложение под кабинет.

./manage.py startapp cabinet

Вкючим его в настройки проекта.

INSTALLED_APPS = [
   ...
    'cabinet'
]

Создадим модель и унаследуе ее от User (cabinet/models.py).

from django.db import models
from decimal import Decimal
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _

class UserProfile(User):
    publicname = models.CharField(default='',  max_length=250, verbose_name=_(u'ФИО'))
    account = models.DecimalField(max_digits=20, decimal_places=2, default=Decimal(0.00), verbose_name=_(u'Счет'))
    phone = models.CharField(default='', max_length=250, verbose_name=_(u'Телефон'))
    telegram = models.CharField(default='', max_length=250, verbose_name=_(u'Телеграм'))
    skype = models.CharField(default='', max_length=250, verbose_name=_(u'Скайп'))

Создаем и применяем миграцию БД.

./manage.py makemigrations
./manage.py migrate

Создаем роут в новом файле cabinet/urls.py.

from django.urls import path, include
from cabinet.views import index

urlpatterns = [ 
    path('',index, name="cabinet_index"),

]

Добавляем его в корневой роут.

urlpatterns = [
    ...
    path('cabinet/',include('cabinet.urls')),

Делаем вьюху cabinet/views.py.

from django.shortcuts import render

def index(request):
    return render(request,'cabinet_index.html')

Шаблон в новом каталоге cabinet/templates/cabinet_index.html.

{% extends 'layout.html' %}
{% block carousel %} {% endblock %}
{% block content %}
<div class="section margin-top_50">
    <div class="container">
        <h1>Мой кабинет</h1>
        <div class="row">

            <div class="col-md-3 ">
                <div class="btn-group-vertical full-width">
                    <a href="#"  class="btn btn-light">Профиль</a>
                    <a href="#" class="btn btn-light">Мои покупки</a>
                  </div>
            </div>
            <div class="col-md-9 ">
                {% block cabinet_content %}{% endblock %}
            </div>
        </div>
    </div>
</div>

{% endblock %}

Ставим ссылку на раздел в layout.html.

<li><a class="nav-link" href="{% url 'cabinet_index' %}">Мой кабинет</a></li>

Добавляем еще 2 вьюхи.

from course.models import LessonPayments
...
def edit_profile(request):
    return render(request,'edit_profile.html')

def payments(request):
    payments = LessonPayments.objects.filter(user=request.user).order_by('-id')
    return render(request,'payments.html',{'payments': payments})

2 роута в cabinet/urls.py.

from django.urls import path, include
from cabinet.views import index, edit_profile, payments

urlpatterns = [ 
    path('',index, name="cabinet_index"),
    path('profile/edit',edit_profile, name="edit_profile"),
    path('payments',payments, name="payments"),
]

В шаблоне cabinet/templates/cabinet_index.html ставим на них ссылки.

<a href="{% url 'edit_profile' %}"  class="btn btn-light">Профиль</a>
<a href="{% url 'payments' %}" class="btn btn-light">Мои покупки</a>

Создаем шаблоны для редактирования профиля cabinet/templates/edit_profile.html.

{% extends 'cabinet_index.html' %}

{% block cabinet_content %}

        <h1>Редактирование профиля</h1>


{% endblock %}

Для платежей cabinet/templates/payments.html.

{% extends 'cabinet_index.html' %}

{% block cabinet_content %}

        <h1>Мои покупки</h1>
        {% if payments %}
        <table class="table">
            <thead>
              <tr>
                <th scope="col">#</th>
                <th scope="col">Название урока</th>
                <th scope="col">Курс</th>
                <th scope="col">Цена</th>
                <th scope="col">Дата покупки</th>
              </tr>
            </thead>
            <tbody>

                {% for payment in payments %}
                <tr>
                    <th scope="row">{{ payment.id }}</th>
                    <td>{{ payment.lesson }}</td>
                    <td>{{ payment.lesson.course }}</td>
                    <td>50 грн</td>
                    <td>{{ payment.created }} </td>
                </tr>
                {% endfor %}

            </tbody>
          </table>
          {% else %}
            <div class="alert alert-danger" role="alert">
                У вас нет купленных уроков.
            </div>
          {% endif %}

{% endblock %}

Класс формы модели.

Создадим новый файл forms.py где определим класс, привязанный к модели UserProfile.

from django.forms import ModelForm
from cabinet.models import UserProfile

class ProfileForm(ModelForm):
    class Meta:
        model = UserProfile
        fields = ['publicname', 'phone', 'telegram', 'skype']

Заведем объект формы в шаблон.

from .forms import ProfileForm

def edit_profile(request):
    form = ProfileForm()
    return render(request,'edit_profile.html', {'form': form})

Привяжемся к сигналу создания объекта User и создадим для него объект профиля cabinet/models.py .

from django.db.models.signals import post_save
from django.dispatch import receiver

...
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(pk=instance.pk)

Вывод в шаблоне.

{% extends 'cabinet_index.html' %}

{% block cabinet_content %}
        <h1>Редактирование профиля</h1>
        {{ form }}
{% endblock %}

admin

Интегрируем bootstrap

pip install django-crispy-forms

Настройки.

INSTALLED_APPS = [
    ...
    'crispy_forms'
]

CRISPY_TEMPLATE_PACK = 'bootstrap4'

Шаблон.

{% extends 'cabinet_index.html' %}
{% load crispy_forms_tags %}

{% block cabinet_content %}
        <h1>Редактирование профиля</h1>
        <form method="post">
            {% csrf_token %}
            {{ form|crispy }}
            <button type="submit" class="btn btn-success">Сохранить</button>
          </form>
{% endblock %}

Отметим поля как не обязательные.

from django.forms import ModelForm
from cabinet.models import UserProfile

class ProfileForm(ModelForm):
    class Meta:
        model = UserProfile
        fields = ['publicname', 'phone', 'telegram', 'skype']

    def __init__(self, *args, **kwargs):
        super(ProfileForm, self).__init__(*args, **kwargs)
        self.fields['publicname'].required = False
        self.fields['phone'].required = False
        self.fields['telegram'].required = False
        self.fields['skype'].required = False

Сохраним форму во вью.

from django.contrib import messages
from django.shortcuts import redirect
...
def edit_profile(request):
    user = request.user.userprofile

    if request.method == 'POST':
        form = ProfileForm(data = request.POST, instance=user)
        if form.is_valid():
            form.save()
            messages.info(request, 'Спасибо. Ваш профиль был сохранен.')
            return redirect('cabinet_index')
    else:
        form = ProfileForm(instance=user)
    return render(request,'edit_profile.html', {'form': form})
Задать вопрос, прокомментировать.