Django - 内联表单集 - 如何设置当前用户
Django - Inline formset - How to set current user
-Objective-
我需要在内联表单集中将当前用户设置为表单字段的自动内容。 (目前不工作)
版本
Python 3.9.2 - Django 3.2
上下文:
我创建了一个列表,其中有一些 objects(Headers)。
从列表中,我可以创建新的 headers 并使用 foreign-key(由 PK-primarykey 调用)访问 detail-page(详细视图)。
在此页面中,我可以看到有关 1 个特定 header 的更多信息。
每个 header 可以有多行信息需要链接到它。
这些行是使用(最多 4 个不同的)特定内联表单集创建或更新的。
-问题和错误-
我创建了正确呈现的表单,但我需要为每一行设置一个自动获取“当前用户”作为其内容的字段。
我无法保存和接收“用户不能为空”。
我无法找到解决方案并尝试了很多方法但仍然遇到此错误。
非常感谢任何有关如何解决此问题的帮助。
提前致谢,
下面是一些代码:
URLS.PY
from django.urls import path, re_path
from fttlapp import views
app_name= 'fttlapps'
urlpatterns = [
path('fttlapphome2/', views.Fttlapphome2View.as_view(), name='fttlapphome2'),
path('fttlogheader/', views.HeadfttlogListView.as_view(), name='headfttlogs'),
path('fttlogheader/add/', views.HeadfttlogCreateView.as_view(), name='headfttlogcreate'),
path('fttlogheader/<int:pk>/', views.HeadfttlogDetailView.as_view(), name='headfttlogdetail'),
path('fttlogheader/<int:pk>/flights/edit/', views.HeadfttlogDeafttlogEditView.as_view(), name='head_flight_edit'),
]
FORMS.PY
from django import forms
from django.contrib.auth.models import User
from django.db.models.fields import CharField, DateField
from django.forms import ModelForm, widgets
from django.forms.fields import ChoiceField
from django.forms.models import ModelChoiceField
from django.utils import timezone
# Load necessary to manage Form in Form
from django.forms.models import inlineformset_factory
# Load Tables
from fttlapp.models import Headfttlog, Deafttlog, Debfttlog
###############################################################################
# Forms for Headfttlog #
###############################################################################
class HeadfttlogcreateForm(ModelForm):
class Meta:
model = Headfttlog
exclude = ['hea_creator', 'hea_modifier']
widgets = {
'hea_fttldate' : forms.TextInput(attrs={'type': 'date'}),
'hea_nxtcheckdate' : forms.TextInput(attrs={'type': 'date'}),
'hea_transfereddate' : forms.TextInput(attrs={'type': 'date'}),
}
## Calendar widget to work both with Create and Update needs to be TextInput with type date
## Calendar widget not compatible with localized_fields !
###############################################################################
# Forms for Headfttlog with Deafttlog details view Management #
###############################################################################
HeadfttlogDeafttlogFormset = inlineformset_factory(Headfttlog, Deafttlog,
fields=('dea_linetype', 'dea_fttlcode', 'dea_airportfrom', 'dea_airportto',
'dea_instrtimestart', 'dea_instrtimeend', 'dea_instrtimetot',
'dea_blocktimestart', 'dea_blocktimeend', 'dea_blocktimetot',
'dea_flighttimestart', 'dea_flighttimeend', 'dea_flighttimetot',
'dea_approach', 'dea_landing', 'dea_external', 'dea_fuel', 'dea_oil',
'dea_lessonnotes', 'dea_preflightsignature', 'dea_invoiceaccount',
'dea_transfered', 'dea_transfereddate',
'dea_reccanceled', 'dea_creator', 'dea_modifier'),
widgets={
'dea_instrtimestart' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_instrtimeend' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_instrtimetot' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_blocktimestart' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_blocktimeend' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_blocktimetot' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_flighttimestart' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_flighttimeend' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_flighttimetot' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_reccanceled' : forms.HiddenInput,
'dea_creator' : forms.HiddenInput,
'dea_modifier' : forms.HiddenInput,
}, extra=1, max_num=8)
VIEWS.PY
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
# Load necessary view
from django.views.generic import (
TemplateView, ListView, CreateView, DetailView, FormView)
from django.views.generic.detail import SingleObjectMixin
# Load for security and access management
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import PermissionRequiredMixin
# Load functions and tools for search bar management
from fttlapp.filters import HeadfttlogFilter
import operator
from functools import partial, reduce
from django.db.models import Q
# Load functions for messages management
from django.contrib import messages
# Load Tables & Forms
from fttlapp.models import Headfttlog
from fttlapp.forms import HeadfttlogcreateForm
from fttlapp.forms import HeadfttlogDeafttlogFormset
###############################################################################
# FTTL home page management #
###############################################################################
@login_required
def fttlapphome(request):
context = {}
return render(request, 'fttlapp/fttlapphome.html', context)
###############################################################################
# FTTL home page 2 management #
###############################################################################
class Fttlapphome2View(TemplateView, LoginRequiredMixin):
template_name = 'fttlapp/fttlapphome2.html'
###############################################################################
# Headfttlog - List view Management #
###############################################################################
class HeadfttlogListView(ListView, LoginRequiredMixin, PermissionRequiredMixin):
permission_required = 'fttlapp.view_headfttlog'
model = Headfttlog
template_name = 'fttlapp/headfttlog_list.html'
paginate_by = 10
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['myFilter'] = HeadfttlogFilter(
self.request.GET, queryset=self.get_queryset())
return context
# Following redefintion necessary to obtain correct pagination after Filter plugin
def get_queryset(self):
queryset = super().get_queryset()
return HeadfttlogFilter(self.request.GET, queryset=queryset).qs
###############################################################################
# Headfttlog - Create view Management Headfttlog #
###############################################################################
class HeadfttlogCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
permission_required = 'fttlapp.add_headfttlog'
model = Headfttlog
template_name = 'fttlapp/headfttlogcreate_form.html'
form_class = HeadfttlogcreateForm
def form_valid(self, form):
form.instance.hea_creator = self.request.user
form.instance.hea_modifier = self.request.user
messages.add_message(
self.request,
messages.SUCCESS,
'The LOG has been created'
)
return super().form_valid(form)
###############################################################################
# Headfttlog - Detail view Management Headfttlog #
###############################################################################
class HeadfttlogDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
permission_required = 'fttlapp.view_headfttlog'
model = Headfttlog
template_name = 'fttlapp/headfttlogdetail.html'
###############################################################################
# Headfttlog with Deafttlog details view Management #
###############################################################################
class HeadfttlogDeafttlogEditView(LoginRequiredMixin, PermissionRequiredMixin, SingleObjectMixin, FormView):
permission_required = ('fttlapp.add_headfttlog','fttlapp.change_headfttlog',
'fttlapp.add_deafttlog', 'fttlapp.change_deafttlog')
model = Headfttlog
template_name = 'fttlapp/head_flight_edit.html'
### 1. Identification of the single Headfttlog we will work with
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Headfttlog.objects.all())
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Headfttlog.objects.all())
return super().post(request, *args, **kwargs)
### 2. FormSet creation - instance is the link to the above data.
def get_form(self, form_class=None):
return HeadfttlogDeafttlogFormset(**self.get_form_kwargs(), instance=self.object)
def formset_valid(self, form):
form.dea_creator = self.request.user
form.dea_modifier = self.request.user
form.save()
messages.add_message(
self.request,
messages.SUCCESS,
'Changes were saved.'
)
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse('fttlapps:headfttlogdetail', kwargs={'pk': self.object.pk})
###############################################################################
# End of view Management #
###############################################################################
HTML
{% extends 'base/dibase3.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% crispy formset %}
{% block title %}Editing Flights and Instructions for {{ headfttlog.fttlcode }}{% endblock %}
{% block content %}
<style>
.box{
max-width: fit-content;
margin: auto;
}
</style>
</div>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<div class="text-start">
<a class="btn btn-outline-info " href="{% url 'fttlapps:headfttlogdetail' pk=headfttlog.pk %}">Back to Detail</a>
</div>
</div>
</nav>
<hr>
<div class="container">
<form action="" method="post" enctype="multipart/form-data">
{% for hidden_field in form.hidden_fields %}
{{ hidden_field.errors }}
{{ hidden_field }}
{% endfor %}
{% csrf_token %}
{{ form.management_form }}
{{ form.non_form_errors }}
<h3>Update Collection</h3>
{% for deafttlog_form in form.forms %}
<hr>
<h5>
{% if deafttlog_form.instance.id %}
Deafttlog: {{ deafttlog_form.instance.dea_linetype }}
{% else %}
{% if form.forms|length > 1 %}
Add another deafttlog
{% else %}
Add a deafttlog
{% endif %}
{% endif %}
</h5>
{% for hidden_field in deafttlog_form.hidden_fields %}
{{ hidden_field.errors }}
{% endfor %}
<table>
{{ deafttlog_form }}
</table>
{% endfor %}
<hr>
<p>
<button type="submit" value="Update Flight" class="btn btn-primary w-100 mb-3">Update Flight</button>
<a href="{{ author.get_absolute_url }}" role="button" class="btn btn-secondary w-100">Return</a>
</p>
</form>
{% endblock content %}
对于 creator
和 modifier
模型字段之类的审计字段,我通常会在模型字段定义中设置 blank=True, null=True
。只需这样做,您的代码就会起作用,因为您已经在视图中处理 dea_creator
和 dea_modifier
的设置。
如果你想像现在这样在数据库中强制执行此操作,则必须将 request.user
传递给你的表单集并将其设置为 dea_creator
字段的初始值正在初始化表格。
编辑:
我上面提到的另一种方法,在你的 HeadfttlogDeafttlogFormset
中,而不是设置 fields
和 widgets
,创建一个实际的表格来使用,例如 DeafttlogForm
,并在那里设置 fields
和 widgets
。然后在你的表单集中,你设置 form=DeafttlogForm
.
在新建的DeafttlogForm
中,初始化dea_creator
字段:
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(DeafttlogForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if not instance.id and user:
self.initial['dea_creator'] = user
然后在HeadfttlogDeafttlogEditView
中添加一个get_form_kwargs
方法:
def get_form_kwargs(self):
kwargs = super(HeadfttlogDeafttlogEditView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
-Objective- 我需要在内联表单集中将当前用户设置为表单字段的自动内容。 (目前不工作)
版本 Python 3.9.2 - Django 3.2
上下文: 我创建了一个列表,其中有一些 objects(Headers)。 从列表中,我可以创建新的 headers 并使用 foreign-key(由 PK-primarykey 调用)访问 detail-page(详细视图)。
在此页面中,我可以看到有关 1 个特定 header 的更多信息。 每个 header 可以有多行信息需要链接到它。 这些行是使用(最多 4 个不同的)特定内联表单集创建或更新的。
-问题和错误- 我创建了正确呈现的表单,但我需要为每一行设置一个自动获取“当前用户”作为其内容的字段。 我无法保存和接收“用户不能为空”。
我无法找到解决方案并尝试了很多方法但仍然遇到此错误。
非常感谢任何有关如何解决此问题的帮助。 提前致谢,
下面是一些代码:
URLS.PY
from django.urls import path, re_path
from fttlapp import views
app_name= 'fttlapps'
urlpatterns = [
path('fttlapphome2/', views.Fttlapphome2View.as_view(), name='fttlapphome2'),
path('fttlogheader/', views.HeadfttlogListView.as_view(), name='headfttlogs'),
path('fttlogheader/add/', views.HeadfttlogCreateView.as_view(), name='headfttlogcreate'),
path('fttlogheader/<int:pk>/', views.HeadfttlogDetailView.as_view(), name='headfttlogdetail'),
path('fttlogheader/<int:pk>/flights/edit/', views.HeadfttlogDeafttlogEditView.as_view(), name='head_flight_edit'),
]
FORMS.PY
from django import forms
from django.contrib.auth.models import User
from django.db.models.fields import CharField, DateField
from django.forms import ModelForm, widgets
from django.forms.fields import ChoiceField
from django.forms.models import ModelChoiceField
from django.utils import timezone
# Load necessary to manage Form in Form
from django.forms.models import inlineformset_factory
# Load Tables
from fttlapp.models import Headfttlog, Deafttlog, Debfttlog
###############################################################################
# Forms for Headfttlog #
###############################################################################
class HeadfttlogcreateForm(ModelForm):
class Meta:
model = Headfttlog
exclude = ['hea_creator', 'hea_modifier']
widgets = {
'hea_fttldate' : forms.TextInput(attrs={'type': 'date'}),
'hea_nxtcheckdate' : forms.TextInput(attrs={'type': 'date'}),
'hea_transfereddate' : forms.TextInput(attrs={'type': 'date'}),
}
## Calendar widget to work both with Create and Update needs to be TextInput with type date
## Calendar widget not compatible with localized_fields !
###############################################################################
# Forms for Headfttlog with Deafttlog details view Management #
###############################################################################
HeadfttlogDeafttlogFormset = inlineformset_factory(Headfttlog, Deafttlog,
fields=('dea_linetype', 'dea_fttlcode', 'dea_airportfrom', 'dea_airportto',
'dea_instrtimestart', 'dea_instrtimeend', 'dea_instrtimetot',
'dea_blocktimestart', 'dea_blocktimeend', 'dea_blocktimetot',
'dea_flighttimestart', 'dea_flighttimeend', 'dea_flighttimetot',
'dea_approach', 'dea_landing', 'dea_external', 'dea_fuel', 'dea_oil',
'dea_lessonnotes', 'dea_preflightsignature', 'dea_invoiceaccount',
'dea_transfered', 'dea_transfereddate',
'dea_reccanceled', 'dea_creator', 'dea_modifier'),
widgets={
'dea_instrtimestart' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_instrtimeend' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_instrtimetot' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_blocktimestart' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_blocktimeend' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_blocktimetot' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_flighttimestart' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_flighttimeend' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_flighttimetot' : forms.TimeInput(format= '%H:%M', attrs={'type': 'time'}),
'dea_reccanceled' : forms.HiddenInput,
'dea_creator' : forms.HiddenInput,
'dea_modifier' : forms.HiddenInput,
}, extra=1, max_num=8)
VIEWS.PY
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
# Load necessary view
from django.views.generic import (
TemplateView, ListView, CreateView, DetailView, FormView)
from django.views.generic.detail import SingleObjectMixin
# Load for security and access management
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import PermissionRequiredMixin
# Load functions and tools for search bar management
from fttlapp.filters import HeadfttlogFilter
import operator
from functools import partial, reduce
from django.db.models import Q
# Load functions for messages management
from django.contrib import messages
# Load Tables & Forms
from fttlapp.models import Headfttlog
from fttlapp.forms import HeadfttlogcreateForm
from fttlapp.forms import HeadfttlogDeafttlogFormset
###############################################################################
# FTTL home page management #
###############################################################################
@login_required
def fttlapphome(request):
context = {}
return render(request, 'fttlapp/fttlapphome.html', context)
###############################################################################
# FTTL home page 2 management #
###############################################################################
class Fttlapphome2View(TemplateView, LoginRequiredMixin):
template_name = 'fttlapp/fttlapphome2.html'
###############################################################################
# Headfttlog - List view Management #
###############################################################################
class HeadfttlogListView(ListView, LoginRequiredMixin, PermissionRequiredMixin):
permission_required = 'fttlapp.view_headfttlog'
model = Headfttlog
template_name = 'fttlapp/headfttlog_list.html'
paginate_by = 10
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['myFilter'] = HeadfttlogFilter(
self.request.GET, queryset=self.get_queryset())
return context
# Following redefintion necessary to obtain correct pagination after Filter plugin
def get_queryset(self):
queryset = super().get_queryset()
return HeadfttlogFilter(self.request.GET, queryset=queryset).qs
###############################################################################
# Headfttlog - Create view Management Headfttlog #
###############################################################################
class HeadfttlogCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
permission_required = 'fttlapp.add_headfttlog'
model = Headfttlog
template_name = 'fttlapp/headfttlogcreate_form.html'
form_class = HeadfttlogcreateForm
def form_valid(self, form):
form.instance.hea_creator = self.request.user
form.instance.hea_modifier = self.request.user
messages.add_message(
self.request,
messages.SUCCESS,
'The LOG has been created'
)
return super().form_valid(form)
###############################################################################
# Headfttlog - Detail view Management Headfttlog #
###############################################################################
class HeadfttlogDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
permission_required = 'fttlapp.view_headfttlog'
model = Headfttlog
template_name = 'fttlapp/headfttlogdetail.html'
###############################################################################
# Headfttlog with Deafttlog details view Management #
###############################################################################
class HeadfttlogDeafttlogEditView(LoginRequiredMixin, PermissionRequiredMixin, SingleObjectMixin, FormView):
permission_required = ('fttlapp.add_headfttlog','fttlapp.change_headfttlog',
'fttlapp.add_deafttlog', 'fttlapp.change_deafttlog')
model = Headfttlog
template_name = 'fttlapp/head_flight_edit.html'
### 1. Identification of the single Headfttlog we will work with
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Headfttlog.objects.all())
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Headfttlog.objects.all())
return super().post(request, *args, **kwargs)
### 2. FormSet creation - instance is the link to the above data.
def get_form(self, form_class=None):
return HeadfttlogDeafttlogFormset(**self.get_form_kwargs(), instance=self.object)
def formset_valid(self, form):
form.dea_creator = self.request.user
form.dea_modifier = self.request.user
form.save()
messages.add_message(
self.request,
messages.SUCCESS,
'Changes were saved.'
)
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse('fttlapps:headfttlogdetail', kwargs={'pk': self.object.pk})
###############################################################################
# End of view Management #
###############################################################################
HTML
{% extends 'base/dibase3.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% crispy formset %}
{% block title %}Editing Flights and Instructions for {{ headfttlog.fttlcode }}{% endblock %}
{% block content %}
<style>
.box{
max-width: fit-content;
margin: auto;
}
</style>
</div>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<div class="text-start">
<a class="btn btn-outline-info " href="{% url 'fttlapps:headfttlogdetail' pk=headfttlog.pk %}">Back to Detail</a>
</div>
</div>
</nav>
<hr>
<div class="container">
<form action="" method="post" enctype="multipart/form-data">
{% for hidden_field in form.hidden_fields %}
{{ hidden_field.errors }}
{{ hidden_field }}
{% endfor %}
{% csrf_token %}
{{ form.management_form }}
{{ form.non_form_errors }}
<h3>Update Collection</h3>
{% for deafttlog_form in form.forms %}
<hr>
<h5>
{% if deafttlog_form.instance.id %}
Deafttlog: {{ deafttlog_form.instance.dea_linetype }}
{% else %}
{% if form.forms|length > 1 %}
Add another deafttlog
{% else %}
Add a deafttlog
{% endif %}
{% endif %}
</h5>
{% for hidden_field in deafttlog_form.hidden_fields %}
{{ hidden_field.errors }}
{% endfor %}
<table>
{{ deafttlog_form }}
</table>
{% endfor %}
<hr>
<p>
<button type="submit" value="Update Flight" class="btn btn-primary w-100 mb-3">Update Flight</button>
<a href="{{ author.get_absolute_url }}" role="button" class="btn btn-secondary w-100">Return</a>
</p>
</form>
{% endblock content %}
对于 creator
和 modifier
模型字段之类的审计字段,我通常会在模型字段定义中设置 blank=True, null=True
。只需这样做,您的代码就会起作用,因为您已经在视图中处理 dea_creator
和 dea_modifier
的设置。
如果你想像现在这样在数据库中强制执行此操作,则必须将 request.user
传递给你的表单集并将其设置为 dea_creator
字段的初始值正在初始化表格。
编辑:
我上面提到的另一种方法,在你的 HeadfttlogDeafttlogFormset
中,而不是设置 fields
和 widgets
,创建一个实际的表格来使用,例如 DeafttlogForm
,并在那里设置 fields
和 widgets
。然后在你的表单集中,你设置 form=DeafttlogForm
.
在新建的DeafttlogForm
中,初始化dea_creator
字段:
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(DeafttlogForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if not instance.id and user:
self.initial['dea_creator'] = user
然后在HeadfttlogDeafttlogEditView
中添加一个get_form_kwargs
方法:
def get_form_kwargs(self):
kwargs = super(HeadfttlogDeafttlogEditView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs