2010-05-05 37 views
74

Có thể có nhiều mô hình được bao gồm trong một đơn ModelForm trong django không? Tôi đang cố tạo biểu mẫu chỉnh sửa tiểu sử. Vì vậy, tôi cần bao gồm một số trường từ Mô hình người dùng mô hình UserProfile. Hiện nay tôi đang sử dụng 2 hình thức như thế nàyNhiều mô hình trong một django ModelForm đơn?

class UserEditForm(ModelForm): 

    class Meta: 
     model = User 
     fields = ("first_name", "last_name") 

class UserProfileForm(ModelForm): 

    class Meta: 
     model = UserProfile 
     fields = ("middle_name", "home_phone", "work_phone", "cell_phone") 

Có cách nào để củng cố những thành một hình thức hoặc để tôi chỉ cần tạo ra một hình thức và xử lý các tải db và tiết kiệm bản thân mình?

+0

Bản sao có thể có của [Django: nhiều mô hình trong một mẫu sử dụng biểu mẫu] (http://stackoverflow.com/questions/569468/django-multiple-models-in-one-template-using-forms) –

Trả lời

73

Bạn chỉ có thể hiển thị cả hai biểu mẫu trong mẫu bên trong một phần tử html <form>. Sau đó, chỉ cần xử lý các biểu mẫu riêng biệt trong chế độ xem. Bạn vẫn có thể sử dụng form.save() và không phải xử lý việc tải db và tự lưu.

Trong trường hợp này, bạn không nên cần đến, nhưng nếu bạn định sử dụng biểu mẫu có cùng tên trường, hãy xem các hình thức django prefix kwarg. (Tôi đã trả lời một câu hỏi về nó here).

+0

Đây là một lời khuyên tốt, nhưng có những trường hợp không áp dụng, ví dụ: mẫu biểu mẫu tùy chỉnh cho một bộ định dạng. – Wtower

+3

Điều gì sẽ là một cách đơn giản để làm cho chế độ xem dựa trên lớp có khả năng hiển thị nhiều hơn một biểu mẫu và một mẫu sau đó kết hợp chúng thành cùng một phần tử '

'? – jozxyqk

+0

Nhưng làm thế nào? Thông thường, một 'FormView' chỉ có một' form_class' được gán cho nó. – erikbwork

2

Có thể bạn nên xem Inline formsets. Các biểu mẫu nội tuyến được sử dụng khi các mô hình của bạn liên quan đến khóa ngoại.

+0

Biểu mẫu nội tuyến là được sử dụng khi bạn cần làm việc với mối quan hệ một đến nhiều. Chẳng hạn như một công ty nơi bạn thêm nhân viên. Tôi đang cố gắng kết hợp 2 bảng vào một hình thức duy nhất. Đó là mối quan hệ 1-1. –

+0

Việc sử dụng biểu mẫu Inline sẽ hoạt động, nhưng có khả năng ít hơn lý tưởng. Bạn cũng có thể tạo một Mô hình xử lý quan hệ cho bạn, và sau đó sử dụng một biểu mẫu duy nhất. Chỉ cần có một trang đơn với 2 biểu mẫu như được đề xuất trong http://stackoverflow.com/questions/2770810/muliple-models-in-a-single-django-modelform/2774732#2774732 sẽ hoạt động. –

2

Bạn có thể kiểm tra my answer here để biết sự cố tương tự.

Bài viết nói về cách kết hợp hồ sơ đăng ký và hồ sơ người dùng vào một biểu mẫu nhưng có thể được tổng quát hóa thành bất kỳ kết hợp ModelForm nào.

5

Bạn có thể thử sử dụng phần mã này:

class CombinedFormBase(forms.Form): 
    form_classes = [] 

    def __init__(self, *args, **kwargs): 
     super(CombinedFormBase, self).__init__(*args, **kwargs) 
     for f in self.form_classes: 
      name = f.__name__.lower() 
      setattr(self, name, f(*args, **kwargs)) 
      form = getattr(self, name) 
      self.fields.update(form.fields) 
      self.initial.update(form.initial) 

    def is_valid(self): 
     isValid = True 
     for f in self.form_classes: 
      name = f.__name__.lower() 
      form = getattr(self, name) 
      if not form.is_valid(): 
       isValid = False 
     # is_valid will trigger clean method 
     # so it should be called after all other forms is_valid are called 
     # otherwise clean_data will be empty 
     if not super(CombinedFormBase, self).is_valid() : 
      isValid = False 
     for f in self.form_classes: 
      name = f.__name__.lower() 
      form = getattr(self, name) 
      self.errors.update(form.errors) 
     return isValid 

    def clean(self): 
     cleaned_data = super(CombinedFormBase, self).clean() 
     for f in self.form_classes: 
      name = f.__name__.lower() 
      form = getattr(self, name) 
      cleaned_data.update(form.cleaned_data) 
     return cleaned_data 

Ví dụ Cách sử dụng:

class ConsumerRegistrationForm(CombinedFormBase): 
    form_classes = [RegistrationForm, ConsumerProfileForm] 

class RegisterView(FormView): 
    template_name = "register.html" 
    form_class = ConsumerRegistrationForm 

    def form_valid(self, form): 
     # some actions... 
     return redirect(self.get_success_url()) 
+0

Có vẻ như điều này không thể được sử dụng trong quản trị do một số kiểm tra rõ ràng: 'admin.E016) Giá trị của' biểu mẫu 'phải được kế thừa từ' BaseModelForm'.' – WhyNotHugo

2

erikbwork và tôi cả hai đã có những vấn đề mà người ta chỉ có thể bao gồm một mô hình thành một generic Lớp Dựa Lượt xem. Tôi tìm thấy một cách tương tự như tiếp cận nó như Miao, nhưng mô đun hơn.

Tôi đã viết một Mixin để bạn có thể sử dụng tất cả các Chế độ xem dựa trên lớp chung. Xác định mô hình, trường và bây giờ cũng child_model và child_field - và sau đó bạn có thể bọc các trường của cả hai mô hình trong một thẻ như mô tả Zach.

class ChildModelFormMixin: 
    ''' extends ModelFormMixin with the ability to include ChildModelForm ''' 
    child_model = "" 
    child_fields =() 
    child_form_class = None 

    def get_child_model(self): 
     return self.child_model 

    def get_child_fields(self): 
     return self.child_fields 

    def get_child_form(self): 
     if not self.child_form_class: 
      self.child_form_class = model_forms.modelform_factory(self.get_child_model(), fields=self.get_child_fields()) 
     return self.child_form_class(**self.get_form_kwargs()) 

    def get_context_data(self, **kwargs): 
     if 'child_form' not in kwargs: 
      kwargs['child_form'] = self.get_child_form() 
     return super().get_context_data(**kwargs) 

    def post(self, request, *args, **kwargs): 
     form = self.get_form() 
     child_form = self.get_child_form() 

     # check if both forms are valid 
     form_valid = form.is_valid() 
     child_form_valid = child_form.is_valid() 

     if form_valid and child_form_valid: 
      return self.form_valid(form, child_form) 
     else: 
      return self.form_invalid(form) 

    def form_valid(self, form, child_form): 
     self.object = form.save() 
     save_child_form = child_form.save(commit=False) 
     save_child_form.course_key = self.object 
     save_child_form.save() 

     return HttpResponseRedirect(self.get_success_url()) 

Ví dụ Cách sử dụng:

class ConsumerRegistrationUpdateView(UpdateView): 
    model = Registration 
    fields = ('firstname', 'lastname',) 
    child_model = ConsumerProfile 
    child_fields = ('payment_token', 'cart',) 

Hoặc với ModelFormClass:

class ConsumerRegistrationUpdateView(UpdateView): 
    model = Registration 
    fields = ('firstname', 'lastname',) 
    child_model = ConsumerProfile 
    child_form_class = ConsumerProfileForm 

Done. Hy vọng rằng sẽ giúp một ai đó.

+0

Trong 'save_child_form.course_key = self.object' này , '.course_key' là gì? –

Các vấn đề liên quan