我有两个类,一个叫phase1
,一个叫phase2
。 phase2
中有phase1
个实例(作为外键关系)。现在我想创建另一个名为POObject
的类,它具有一个名为purchase
的外键值, 一个phase1
或一个phase2
个对象。也就是说,我希望能够创建POObject
purchase
设置为phase1
实例,然后将其更改为phase2
实例。
我相信这叫做Duck Typing,但我不确定在Django中是否有一种简单的方法。我知道Python很容易让Duck打字,但我猜测数据库不会允许它,至少没有一些额外的工作。
有关如何做到这一点的任何建议将不胜感激。
在实施orlenko的建议后,我无法添加新项目。以下是处理创建新实例的视图。它的工作方式是在purchase
中创建新的new
,然后使用purchase
中new2
的实例创建POObject
。
def new(request):
if request.method == 'POST':
form = PurchaseOrderForm(request.POST)
if form.is_valid():
new_po = form.save()
return HttpResponseRedirect('/workflow/%s' %new_po.request_number)
else:
return render(request, 'input.html', {'input_type': 'Purchase Order','formset': form, 'error': True})
else:
form = PurchaseOrderForm()
return render(request, 'input.html', {'input_type': 'Purchase Order','formset': form,})
def new2(request, number):
po=PurchaseOrder.objects.get(pk=number)
if request.method == 'POST':
form = WorkflowForm(request.POST, initial={'purchase': PurchaseOrder.objects.get(pk=number), 'state': 'request'})
if form.is_valid():
new_flow = form.save()
return HttpResponse('Good')
else:
print form.errors
return render(request, 'new-workflow.html', {'form': form, 'purchase': po})
else:
form = WorkflowForm(initial={'purchase': PurchaseOrder.objects.get(pk=number), 'state': 'request'})
return render(request, 'new-workflow.html', {'form': form, 'purchase': po, 'type': 'New'})
适当的表格类是:
class WorkflowForm(ModelForm):
purchase1=forms.ModelChoiceField(queryset=PurchaseOrder.objects.all(), required=False)
purchase2=forms.ModelChoiceField(queryset=Phase2.objects.all(), required=False)
details = forms.CharField(required=False)
class Meta:
model = POObject
答案 0 :(得分:1)
我认为Lalo的建议是正确的。您可以尝试Django content types:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class Phase1(models.Model):
#...
class Phase2(models.Model):
#...
class POObject(models.Model):
# Standard names.
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
# Your 'generic' foreign key.
purchase = generic.GenericForeignKey('content_type', 'object_id')
然后,你可以这样做:
phase1 = Phase1.objects.get(id='xyz')
phase2 = Phase2.objects.get(id='abc')
p1 = POObject(purchase=phase1)
p1.save()
p2 = POObject(purchase=phase2)
p2.save()
您必须在django.contrib.contenttypes
设置中加入INSTALLED_APPS
(默认情况下会包含此设置)。
答案 1 :(得分:0)
模型类比其他Python代码更具限制性,因为它们必须转换为实际的数据库表以及它们之间的关系。
但你的想法是"灵活的FK"可以像这样实现:
class Phase1(Model):
#...
class Phase2(Model):
#...
class POObject(Model):
phase1 = ForeignKey(Phase1, null=True)
phase2 = ForeignKey(Phase2, null=True, related_name='+')
def get_phase(self):
if self.phase2_id: # more likely case first
return self.phase2
return self.phase1
def set_phase(self, phase):
# Detect which type it is
if isinstance(phase, Phase2):
self.phase2 = phase
self.phase1 = None
else:
self.phase2 = None
self.phase1 = phase
phase = property(get_phase, set_phase)
在这里,我们有两个可选的FK并使用其中一个。 phase
属性隐藏了详细信息,并允许您将两个FK视为一个。将阶段记录分配给po_object.phase时,代码会指出要将FK指向哪个表。