2014-12-01 43 views
0

我想創建一個表格,允許我從這些模型分配服務的供應商。由於我使用其他程序使用的數據庫,因此沒有定義M2M關係,因此似乎無法對其進行更改。我也可能是錯的。M2M使用通過和與多個複選框形式

class Service(models.Model): 
    name = models.CharField(max_length=30L, blank=True) 


class ServiceUser(models.Model): 
    service = models.ForeignKey(Service, null=False, blank=False) 
    contact = models.ForeignKey(Contact, null=False, blank=False) 


class SupplierPrice(models.Model): 
    service_user = models.ForeignKey('ServiceUser') 
    price_type = models.IntegerField(choices=PRICE_TYPES) 
    price = models.DecimalField(max_digits=10, decimal_places=4) 

我建立這種形式:

class SupplierServiceForm(ModelForm): 
    class Meta: 
     services = ModelMultipleChoiceField(queryset=Service.objects.all()) 
     model = ServiceUser 

     widgets = { 
      'service': CheckboxSelectMultiple(), 
      'contact': HiddenInput(), 
     } 

這裏是我開始工作就沒有任何成功的觀點:

class SupplierServiceUpdateView(FormActionMixin, TemplateView): 

    def get_context_data(self, **kwargs): 
     supplier = Contact.objects.get(pk=self.kwargs.get('pk')) 
     service_user = ServiceUser.objects.filter(contact=supplier) 

     form = SupplierServiceForm(instance=service_user) 

     return {'form': form} 

我有一種感覺,什麼是錯的我試圖去做的方式。我有一個正確的表單顯示,但它沒有與聯繫人實例化,即使供應商已經在service_user中有一些條目,也不檢查複選框。

回答

0

我的問題的解決方案確實是重新定義oder中的模型以整合使用through參數丟失的m2m關係。然後,我必須使用特殊的init方法調整表單,以使所有選定的服務顯示在複選框中,並使用特殊的save()方法使用m2m關係保存表單。

class Supplier(Contact): 
    services = models.ManyToManyField('Service', through='SupplierPrice') 


class Service(models.Model): 
    name = models.CharField(max_length=30L, blank=True) 


class ServiceUser(models.Model): 
    service = models.ForeignKey(Service, null=False, blank=False) 
    supplier = models.ForeignKey(Supplier, null=False, blank=False) 
    price = models.Decimal(max_digits=10, decimal_places=2, default=0) 

而形式,改編自非常着名的關於澆頭和披薩的帖子。

class SupplierServiceForm(ModelForm): 

    class Meta: 
     model = Supplier 
     fields = ('services',) 

     widgets = { 
      'services': CheckboxSelectMultiple(), 
      'contact_ptr_id': HiddenInput(), 
      } 

     services = ModelMultipleChoiceField(queryset=Service.objects.all(), required=False) 

    def __init__(self, *args, **kwargs): 
     # Here kwargs should contain an instance of Supplier 
     if 'instance' in kwargs: 
      # We get the 'initial' keyword argument or initialize it 
      # as a dict if it didn't exist. 
      initial = kwargs.setdefault('initial', {}) 
      # The widget for a ModelMultipleChoiceField expects 
      # a list of primary key for the selected data (checked boxes). 
      initial['services'] = [s.pk for s in kwargs['instance'].services.all()] 

     ModelForm.__init__(self, *args, **kwargs) 


    def save(self, commit=True): 
     supplier = ModelForm.save(self, False) 
     # Prepare a 'save_m2m' method for the form, 

     def save_m2m(): 
      new_services = self.cleaned_data['services'] 
      old_services = supplier.services.all() 

      for service in old_services: 
       if service not in new_services: 
        service.delete() 

      for service in new_services: 
       if service not in old_services: 
        SupplierPrice.objects.create(supplier=supplier, service=service) 
     self.save_m2m = save_m2m 

     # Do we need to save all changes now? 
     if commit: 
      self.save_m2m() 

     return supplier 

這改變了我的第一個模型,將一個爛攤子在我舊的數據庫,但至少它的工作原理。

0

您正在定義Meta類中的服務。將它放在供應商服務表單開始之後。至少它應該顯示出來。

編輯:

我誤解了你的目標。看起來你想顯示一個只能有1個值的字段的多重選擇。您的服務區域將無法存儲多個服務。 因此,根據定義,您的ServiceUser只能有一個Service。 如果您不想修改數據庫,因爲其他應用程序正在使用它,您可以創建另一個與服務有多對多關係的字段。這可能會導致與使用舊字段的應用的其他部分發生衝突,但是如果不修改關係,我不會看到其他方式。

+0

它顯示旁邊的複選框列表與服務一個新的多個字段的選擇。如果我試圖instanciate與查詢service_user它抱怨queryset沒有屬性__meta__無論如何,我不想多選擇字段,但複選框。 – 2014-12-01 18:58:05

+0

你的意思是我可以通過定義類似的東西來處理:service_user = models.ManyToManyField(ServiceUser)或service_user = models.ManyToManyField(Service)?如果不破壞數據,我可以嘗試。 – 2014-12-01 21:13:46

+0

這是一個與原來無關的新領域。正如前面提到的,唯一的問題是你添加到該字段中的任何內容都不能從應用程序的舊版本訪問。 – cdvv7788 2014-12-01 21:20:07