[英]Django - Multiple custom models on the same form
我正在使用 Django 2.1 和 PostgreSQL。 我的問題是我正在嘗試創建一個表單來同時編輯兩個不同的模型。 該模型與 FK 相關,我看到的每個示例都與用戶和配置文件模型有關,但是我無法復制我真正需要的東西。
我的模型簡化以顯示有關它們的相關信息是:
# base model for Campaigns.
class CampaignBase(models.Model):
....
project = models.ForeignKey(Project, on_delete=models.CASCADE)
creation_date = models.DateTimeField(auto_now_add=True)
start_date = models.DateTimeField(null=True, blank=True)
end_date = models.DateTimeField(null=True, blank=True)
....
# define investment campaign made on a project.
class InvestmentCampaign(models.Model):
....
campaign = models.ForeignKey(CampaignBase, on_delete=models.CASCADE, null=True, blank=True)
description = models.CharField(
blank=True,
max_length=25000,
)
....
我要創建的表單是包含 FK CampaignBase
的end_date
和InvestmentCampaign
的Description
的表單。
現在我有這個UpdateView
來編輯 InvestmentCampaign,我需要適應我的實際需要,也就是更新CampaignBase
model:
class ProjectEditInvestmentCampaignView(LoginRequiredMixin, SuccessMessageMixin, generic.UpdateView):
template_name = 'webplatform/project_edit_investment_campaign.html'
model = InvestmentCampaign
form_class = CreateInvestmentCampaignForm
success_message = 'Investment campaign updated!'
def get_success_url(self):
return reverse_lazy('project-update-investment-campaign', args=(self.kwargs['project'], self.kwargs['pk']))
# Make the view only available for the users with current fields
def dispatch(self, request, *args, **kwargs):
self.object = self.get_object()
# here you can make your custom validation for any particular user
if request.user != self.object.campaign.project.user:
raise PermissionDenied()
return super().dispatch(request, *args, **kwargs)
# Set field as current user
def form_valid(self, form):
campaign = InvestmentCampaign.objects.get(pk=self.kwargs['campaign'])
form.instance.campaign = campaign
form.instance.history_change_reason = 'Investment campaign updated'
return super(ProjectEditInvestmentCampaignView, self).form_valid(form)
def get_context_data(self, **kwargs):
project = Project.objects.get(pk=self.kwargs['project'])
context = super(ProjectEditInvestmentCampaignView, self).get_context_data(**kwargs)
context['project'] = project
return context
我的 forms 是:
class CreateCampaignBaseForm(forms.ModelForm):
class Meta:
model = CampaignBase
fields = ('end_date',)
widgets = {
'end_date': DateTimePickerInput(),
}
def __init__(self, *args, **kwargs):
# first call parent's constructor
super(CreateCampaignBaseForm, self).__init__(*args, **kwargs)
# evade all labels and help text to appear when using "as_crispy_tag"
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper._help_text_inline = True
class CreateInvestmentCampaignForm(forms.ModelForm):
class Meta:
model = InvestmentCampaign
fields = ('description')
widgets = {
'description': SummernoteWidget(attrs={'summernote': {
'placeholder': 'Add some details of the Investment Campaign here...'}}),
}
def __init__(self, *args, **kwargs):
# first call parent's constructor
super(CreateInvestmentCampaignForm, self).__init__(*args, **kwargs)
# evade all labels and help text to appear when using "as_crispy_tag"
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper._help_text_inline = True
我到處讀到,最好的方法是使用基於 function 的視圖,並調用我擁有的每個 forms 然后進行驗證。 問題是我不知道如何在 forms 中使用正確的 object 填充字段,而且,我不知道如何執行與 get_context_data 等效的操作,也不知道如何使self
的 ZDBC11CAA5BDA99F77E6FBEDDAB8 等效於get_success_url
(因為基於 function 的視圖我只有請求屬性,所以我無法訪問 kwargs)。
我見過一些人使用django-betterforms ,但同樣,唯一的例子是 auth 和 profile 模型,我看不到用我自己的模型復制它的方法。
非常感謝。
如果您只想更改BaseCampaign
上的一個字段end_date
,那么您應該只使用一種表單。 只需在CreateInvestmentCampaignForm
和form.valid()
方法中添加end_date
作為附加字段(例如forms.DateTimeField()
),保存表單后,在相關活動上設置值:
def form_valid(self, form):
inv_campaign = form.save(commit=False)
inv_campaign.campaign.end_date = form.cleaned_data['end_date']
inv_campaign.campaign.save()
inv_campaign.history_change_reason = ...
return super().form_valid(form)
以下是如何將end_date
添加到表單並正確初始化它:
class CreateInvestmentCampaignForm(ModelForm):
end_date = forms.DateTimeField(blank=True)
class Meta:
model = InvestmentCampaign
fields = ('description')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance.campaign:
self.fields['end_date'].initial = self.instance.campaign.end_date
根據關於@dirkgroten 答案的對話,我開發了對我有用的東西以及我實際使用的東西,但我將他的答案推銷為正確的,因為他的代碼也很實用。
因此,與此同時,他正在啟動表單上的值,我正在使用視圖通過添加def get_initial(self):
並在def form_valid(self, form):
上添加驗證來做到這一點:
在觀點上:
...
def get_initial(self):
"""
Returns the initial data to use for forms on this view.
"""
initial = super(ProjectEditInvestmentCampaignView, self).get_initial()
initial['end_date'] = self.object.campaign.end_date
return initial
...
# Set field as current user
def form_valid(self, form):
form.instance.history_change_reason = 'Investment campaign updated'
is_valid = super(ProjectEditInvestmentCampaignView, self).form_valid(form)
if is_valid:
# the base campaign fields
campaign = form.instance.campaign
campaign.end_date = form.cleaned_data.get("end_date")
campaign.save()
return is_valid
在表單上,我剛剛添加了end_date
字段:
class CreateInvestmentCampaignForm(forms.ModelForm):
end_date = forms.DateTimeField()
class Meta:
model = InvestmentCampaign
fields = ('description',)
widgets = {
'description': SummernoteWidget(attrs={'summernote': {
'placeholder': 'Add some details of the Investment Campaign here...'}}),
'end_date': DateTimePickerInput(), # format='%d/%m/%Y %H:%M')
}
def __init__(self, *args, **kwargs):
# first call parent's constructor
super(CreateInvestmentCampaignForm, self).__init__(*args, **kwargs)
# evade all labels and help text to appear when using "as_crispy_tag"
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper._help_text_inline = True
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.