2

我有两个类,一个叫phase1,一个叫phase2phase2其中有一个实例phase1(作为外键关系)。现在我想创建另一个名为 的类POObject,它有一个外键值purchase可以调用aphase1phase2对象。也就是说,我希望能够创建一个POObject带有purchase集合的phase1实例,然后再将其更改为一个phase2实例。

我相信这被称为 Duck Typing,但我不确定在 Django 中是否有简单的方法。我知道 Python 很容易允许 Duck Typing,但我猜如果没有至少一些额外的工作,数据库不会允许它。

任何关于如何做到这一点的建议将不胜感激。

实施 orlenko 的建议后,我无法添加新项目。以下是处理创建新实例的视图。它的工作方式是创建一个新purchase的 in new,然后使用该purchasein的实例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
4

2 回答 2

2

我认为拉洛的提议是对的。您可以尝试Django 内容类型

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设置中(默认情况下包含)。

于 2013-06-18T20:45:24.957 回答
-1

模型类比 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 视为一个。当您将 Phase 记录分配给 po_object.phase 时,代码会确定 FK 指向哪个表。

于 2013-06-18T18:31:49.270 回答