如何在 django 的 CreateView 中使用两个不同的模型
How to use two different models in CreateView in django
我有以下型号:
class BankAccount(models.Model):
owner = models.ForeignKey(User)
class MoneyTransfer(models.Model):
sender = models.ForeignKey(BankAccount)
和url:
url(r'^accounts/(?P<pk>\w+)/send_transfer$', SendTransfer.as_view(), name='SendTransfer')
表示"I want to send money from Account with id=pk"
这是我的观点:
class SendTransfer(View):
form_class = SendTransferForm
template_name = 'dashboard/send_transfer.html'
def get(self, request, *args, **kwargs):
instance = BankAccount.objects.get(id=self.kwargs['pk'])
if instance.is_legal():
if instance.organization.owners.all().filter(user__id=self.request.user.id).count() == 0:
return None
else:
if instance.citizen.user.id != self.request.user.id:
return None
return render(self.request, self.template_name, self.get_context_data())
def post(self, request, *args, **kwargs):
sender = BankAccount.objects.get(id=kwargs['pk'])
form = self.form_class(sender, self.request.user, request.POST)
if form.is_valid():
MoneyTransfer.objects.create(sender=sender,
receiver=BankAccount.objects.get(id=self.request.POST['receiver']),
total=float(self.request.POST['total']),
when=timezone.localtime(timezone.now()),
comment=self.request.POST['comment'])
return redirect('AccountDetail', kwargs['pk'])
data = self.get_context_data()
data['form'] = form
return render(request, self.template_name, data)
def get_context_data(self):
account = BankAccount.objects.get(id=self.kwargs['pk'])
return {'form': SendTransferForm(account, self.request.user),
'user': self.request.user,
'account': account}
我认为 CBV 有很多冗余代码。我可以做些什么来缩短它?
UPD
我当前的代码:
class SendTransfer(SingleObjectMixin, FormView):
model = BankAccount
form_class = SendTransferForm
template_name = 'dashboard/send_transfer.html'
def dispatch(self, request, *args, **kwargs):
self.object = self.get_object()
return super(SendTransfer, self).dispatch(request, *args, **kwargs)
def get_object(self, queryset=None):
obj = super(SendTransfer, self).get_object(queryset)
if obj.is_legal():
if not obj.organization.owners.filter(user=self.request.user).exists():
raise Http404
else:
if obj.citizen.user != self.request.user:
raise Http404
return obj
def form_valid(self, form):
data = form.cleaned_data
MoneyTransfer.objects.create(sender=self.object,
receiver=data['receiver'], # ModelChoiceField in the form
total=data['total'], # FloatField in the form, etc.
when=timezone.localtime(timezone.now()),
comment=data['comment'])
return redirect('AccountDetail', self.object.pk)
dispatch() 方法的最后一行引发 TypeError: init() takes at least 3 arguments (1 given)
CBV 专为代码重用而设计。如果您还没有另一个 class 可以从您发布的代码中获益,那么实际的代码量几乎是相同的,无论是 CBV 还是普通函数。
但是更 pythonic 和 Django-ish(从我有偏见的 POV)的方式是:
- 从
FormView
而不是 View
继承您的 class。这稍微简化了表单管理。
- 添加一个
SingleObjectMixin
以免费从 url kwargs 获取对象。
- 将对象验证移至
get_object()
方法。如果您的对象未通过验证,则引发 404 是一个很好的做法。
- 重构
get_context_data()
,因为您已经在上下文中拥有所有这些数据(request
、form
和 object
)
不要依赖 self.request.POST
,而是通过表单清理数据。
class SendTransfer(SingleObjectMixin, FormView):
model = BankAccount
form_class = SendTransferForm
template_name = 'dashboard/send_transfer.html'
def dispatch(self, request, *args, **kwargs):
self.object = self.get_object()
return super(SendTransfer).dispatch(request, *args, **kwargs)
def get_object(self, queryset=None):
obj = super(SendTransfer, self).get_object(queryset)
if obj.is_legal():
if not obj.organization.owners.filter(user=self.request.user).exists():
raise Http404
else:
if obj.citizen.user != self.request.user:
raise Http404
return obj
def form_valid(self, form):
data = form.cleaned_data
MoneyTransfer.objects.create(sender=self.object,
receiver=data['receiver'], # ModelChoiceField in the form
total=data['total'], # FloatField in the form, etc.
when=timezone.localtime(timezone.now()),
comment=data['comment'])
return redirect('AccountDetail', self.object.pk)
由于 CBV 魔法,您的一些代码已经消失,一些只是转移到其他方法。看看吧,欢迎大家多多指教
我有以下型号:
class BankAccount(models.Model):
owner = models.ForeignKey(User)
class MoneyTransfer(models.Model):
sender = models.ForeignKey(BankAccount)
和url:
url(r'^accounts/(?P<pk>\w+)/send_transfer$', SendTransfer.as_view(), name='SendTransfer')
表示"I want to send money from Account with id=pk"
这是我的观点:
class SendTransfer(View):
form_class = SendTransferForm
template_name = 'dashboard/send_transfer.html'
def get(self, request, *args, **kwargs):
instance = BankAccount.objects.get(id=self.kwargs['pk'])
if instance.is_legal():
if instance.organization.owners.all().filter(user__id=self.request.user.id).count() == 0:
return None
else:
if instance.citizen.user.id != self.request.user.id:
return None
return render(self.request, self.template_name, self.get_context_data())
def post(self, request, *args, **kwargs):
sender = BankAccount.objects.get(id=kwargs['pk'])
form = self.form_class(sender, self.request.user, request.POST)
if form.is_valid():
MoneyTransfer.objects.create(sender=sender,
receiver=BankAccount.objects.get(id=self.request.POST['receiver']),
total=float(self.request.POST['total']),
when=timezone.localtime(timezone.now()),
comment=self.request.POST['comment'])
return redirect('AccountDetail', kwargs['pk'])
data = self.get_context_data()
data['form'] = form
return render(request, self.template_name, data)
def get_context_data(self):
account = BankAccount.objects.get(id=self.kwargs['pk'])
return {'form': SendTransferForm(account, self.request.user),
'user': self.request.user,
'account': account}
我认为 CBV 有很多冗余代码。我可以做些什么来缩短它?
UPD
我当前的代码:
class SendTransfer(SingleObjectMixin, FormView):
model = BankAccount
form_class = SendTransferForm
template_name = 'dashboard/send_transfer.html'
def dispatch(self, request, *args, **kwargs):
self.object = self.get_object()
return super(SendTransfer, self).dispatch(request, *args, **kwargs)
def get_object(self, queryset=None):
obj = super(SendTransfer, self).get_object(queryset)
if obj.is_legal():
if not obj.organization.owners.filter(user=self.request.user).exists():
raise Http404
else:
if obj.citizen.user != self.request.user:
raise Http404
return obj
def form_valid(self, form):
data = form.cleaned_data
MoneyTransfer.objects.create(sender=self.object,
receiver=data['receiver'], # ModelChoiceField in the form
total=data['total'], # FloatField in the form, etc.
when=timezone.localtime(timezone.now()),
comment=data['comment'])
return redirect('AccountDetail', self.object.pk)
dispatch() 方法的最后一行引发 TypeError: init() takes at least 3 arguments (1 given)
CBV 专为代码重用而设计。如果您还没有另一个 class 可以从您发布的代码中获益,那么实际的代码量几乎是相同的,无论是 CBV 还是普通函数。
但是更 pythonic 和 Django-ish(从我有偏见的 POV)的方式是:
- 从
FormView
而不是View
继承您的 class。这稍微简化了表单管理。 - 添加一个
SingleObjectMixin
以免费从 url kwargs 获取对象。 - 将对象验证移至
get_object()
方法。如果您的对象未通过验证,则引发 404 是一个很好的做法。 - 重构
get_context_data()
,因为您已经在上下文中拥有所有这些数据(request
、form
和object
) 不要依赖
self.request.POST
,而是通过表单清理数据。class SendTransfer(SingleObjectMixin, FormView): model = BankAccount form_class = SendTransferForm template_name = 'dashboard/send_transfer.html' def dispatch(self, request, *args, **kwargs): self.object = self.get_object() return super(SendTransfer).dispatch(request, *args, **kwargs) def get_object(self, queryset=None): obj = super(SendTransfer, self).get_object(queryset) if obj.is_legal(): if not obj.organization.owners.filter(user=self.request.user).exists(): raise Http404 else: if obj.citizen.user != self.request.user: raise Http404 return obj def form_valid(self, form): data = form.cleaned_data MoneyTransfer.objects.create(sender=self.object, receiver=data['receiver'], # ModelChoiceField in the form total=data['total'], # FloatField in the form, etc. when=timezone.localtime(timezone.now()), comment=data['comment']) return redirect('AccountDetail', self.object.pk)
由于 CBV 魔法,您的一些代码已经消失,一些只是转移到其他方法。看看吧,欢迎大家多多指教