Как разместить форму django в навигационной панели, чтобы она появлялась на каждой странице? - PullRequest
1 голос
/ 12 марта 2020

У меня есть форма, набор запросов которой зависит от request.user, и чье начальное значение зависит от ключа сеанса. Основными моделями являются Пользователь (небольшая модификация модели пользователя по умолчанию) и Учетная запись, между которыми существует отношение многие ко многим. Форма позволяет пользователю изменить учетную запись, которую он просматривает, и этот выбор должен сохраняться, пока пользователь перемещается по сайту. Форма отлично работает, когда создается в одном представлении и передается в один шаблон, но я хочу, чтобы форма отображалась в верхней панели навигации, чтобы пользователь мог изменять учетные записи из любого места.

Вот форма:

class ChangeAccountContextForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user')
        self.current_account_id = kwargs.pop('account_id')
        super(ChangeAccountContextForm, self).__init__(*args, **kwargs)
        self.fields['account_choices'].queryset = self.user.accounts.all()
        try:
            self.fields['account_choices'].initial = Account.objects.get(id=self.current_account_id)
        except(Account.DoesNotExist):
            self.fields['account_choices'].initial = None
    #queryset and initial are set to None, because they are assigned dynamically in the constructor (see above)
    account_choices = forms.ModelChoiceField(queryset=None, initial=None, label='Account:', widget=forms.Select(attrs={'onChange':'this.form.submit()', 'class': 'custom-select mr-sm-2 ml-2'}), required=True )

    class Meta:
        model = User
        fields = ['account_choices']

А вот существующее представление, в котором используется форма:

@login_required
def welcome_view(request):
    user = request.user
    context = {}
    accounts = user.accounts.all().order_by('account_name')
    context['accounts'] = accounts
    context['num_accounts'] = len(accounts)

    try:
        account_id = request.session['current_account_id']
    except (KeyError):
        account_id = None

    if request.method == 'POST':
        form = ChangeAccountContextForm(request.POST, user=user, account_id=account_id)
        context['form'] = form
        if form.is_valid():
            new_account_context = form.cleaned_data['account_choices']           
            request.session['current_account_name'] = new_account_context.account_name
            request.session['current_account_id'] = new_account_context.id

    else:
        form = ChangeAccountContextForm(user=user, account_id=account_id)
        context['form'] = form

    return render(request, 'welcome.html', context)

(Кстати, ключи сессии установлены когда пользователь входит в систему.)

Учитывая зависимость от request.user и переменных, хранящихся в сеансе, я не уверен, как включить форму на каждой странице, не восстанавливая форму в каждом представлении, как показано выше. , Полагаю, это сработает, но я уверен, что подход должен быть более DRY.

1 Ответ

0 голосов
/ 13 марта 2020

Это частичный ответ на мой собственный вопрос. Я добавляю его сюда, потому что думаю, что документации для добавления формы в пользовательский тег шаблона не хватает.

1.) Создайте папку с именем templatetags (с, конечно, __init__.py) и добавьте account_context_form.py (или какое-либо имя имеет смысл для вас). Моя выглядит так:

from django import template
from userauth.forms import ChangeAccountContextForm

register = template.Library()

@register.inclusion_tag('account_context_form.html')
def account_context_form(**kwargs):
    user = kwargs['user']
    account_id = kwargs['account_id']
    form = ChangeAccountContextForm(user=user, account_id=account_id)
    return {'account_context_form' : form }
создайте файл html, который вы передаете тегу, и сохраните в папке шаблонов. В моем случае, account_context_form. html '
<form class="form-inline" action="{{ request.path }}" method="POST">{% csrf_token %}
    {{ account_context_form }}
</form>
в base_generi c. html (или там, где это когда-либо имеет смысл), назовите тег следующим образом:
{% load account_context_form %}
{% account_context_form user=request.user account_id=request.session.current_account_id %}

Что касается того, как на самом деле обрабатывать запрос POST, см. мой вопрос (и мой ответ) здесь: Как обработать запрос POST из Django формы, загруженной с помощью пользовательского тега шаблона?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...