2009-02-20 34 views
91

Tôi đang tạo ứng dụng theo dõi vé hỗ trợ và có một vài mô hình mà tôi muốn tạo từ một trang. Vé thuộc về một khách hàng thông qua một ForeignKey. Ghi chú thuộc về Vé thông qua một ForeignKey là tốt. Tôi muốn có tùy chọn chọn một Khách hàng (đó là một dự án riêng biệt hoàn toàn) HOẶC tạo một Khách hàng mới, sau đó tạo một Vé và cuối cùng tạo một Ghi chú được giao cho vé mới.Django: nhiều mô hình trong một mẫu sử dụng biểu mẫu

Vì tôi khá mới đối với Django, tôi có xu hướng làm việc lặp lại, thử các tính năng mới mỗi lần. Tôi đã chơi với ModelForms nhưng tôi muốn ẩn một số trường và thực hiện một số xác thực phức tạp. Nó có vẻ như mức độ kiểm soát mà tôi đang tìm kiếm hoặc yêu cầu các formets hoặc làm tất cả mọi thứ bằng tay, hoàn chỉnh với một trang mẫu mã tay, tẻ nhạt, mà tôi đang cố gắng tránh.

Có một số tính năng đáng yêu tôi bị thiếu không? Có ai đó có một tài liệu tham khảo hay ví dụ tốt để sử dụng formets? Tôi đã dành cả một ngày cuối tuần trên tài liệu API cho họ và tôi vẫn không biết gì. Đây có phải là vấn đề thiết kế nếu tôi phá vỡ và mã hóa tất cả mọi thứ không?

Trả lời

2

"Tôi muốn ẩn một số trường và thực hiện xác thực phức tạp."

Tôi bắt đầu với giao diện quản trị được tích hợp sẵn.

  1. Xây dựng ModelForm để hiển thị trường mong muốn.

  2. Mở rộng Biểu mẫu bằng các quy tắc xác thực trong biểu mẫu. Thông thường, đây là phương thức clean.

    Đảm bảo phần này hoạt động khá tốt.

Sau khi hoàn tất, bạn có thể di chuyển ra khỏi giao diện quản trị được cài sẵn.

Sau đó, bạn có thể đánh lừa xung quanh bằng nhiều biểu mẫu có liên quan một phần trên một trang web. Đây là một loạt các công cụ mẫu để trình bày tất cả các biểu mẫu trên một trang duy nhất.

Sau đó, bạn phải viết chức năng xem để đọc và xác nhận các thứ biểu mẫu khác nhau và thực hiện các đối tượng khác nhau save().

"Đây có phải là vấn đề thiết kế nếu tôi phân tích và mã hóa tất cả mọi thứ không?" Không, nó chỉ là rất nhiều thời gian cho không nhiều lợi ích.

+0

Tôi không biết làm thế nào, do đó không làm điều đó – orokusaki

+1

@orokusaki: Bạn muốn thêm điều gì? Điều đó dường như mô tả một giải pháp. Còn gì nữa? Câu hỏi là mơ hồ, vì vậy thật khó để cung cấp mã thực sự. Thay vì than phiền, vui lòng cung cấp đề xuất cải tiến. Bạn có đề nghị gì? –

71

Điều này thực sự không quá khó để thực hiện với ModelForms. Vì vậy, hãy nói rằng bạn có Biểu mẫu A, B và C. Bạn in ra từng biểu mẫu và trang và bây giờ bạn cần phải xử lý POST.

if request.POST(): 
    a_valid = formA.is_valid() 
    b_valid = formB.is_valid() 
    c_valid = formC.is_valid() 
    # we do this since 'and' short circuits and we want to check to whole page for form errors 
    if a_valid and b_valid and c_valid: 
     a = formA.save() 
     b = formB.save(commit=False) 
     c = formC.save(commit=False) 
     b.foreignkeytoA = a 
     b.save() 
     c.foreignkeytoB = b 
     c.save() 

Here là tài liệu để xác thực tùy chỉnh.

+2

btw, tôi không nghĩ rằng formets là giải pháp tốt cho vấn đề bạn mô tả. Tôi luôn sử dụng chúng để thể hiện nhiều trường hợp của một mô hình. Ví dụ. bạn có một mẫu đơn đăng ký và bạn muốn 3 tham chiếu đến bạn tạo một bộ mẫu có 3 trường hợp của mô hình Tham chiếu. –

+0

lưu ý rằng, với cách bạn thực hiện, cuộc gọi .is_valid() không phải là ngắn mạch. Nếu bạn muốn đoản mạch nó, bạn sẽ cần phải trì hoãn việc gọi hàm .is_valid() cho đến khi 'và'. –

22

Tôi gần đây đã gặp phải một số vấn đề và chỉ tìm ra cách thực hiện việc này. Giả sử bạn có ba lớp học, tiểu học, B, C và B, C có một khóa ngoại đến chính

class PrimaryForm(ModelForm): 
     class Meta: 
      model = Primary 

    class BForm(ModelForm): 
     class Meta: 
      model = B 
      exclude = ('primary',) 

    class CForm(ModelForm): 
     class Meta: 
      model = C 
      exclude = ('primary',) 

    def generateView(request): 
     if request.method == 'POST': # If the form has been submitted... 
      primary_form = PrimaryForm(request.POST, prefix = "primary") 
      b_form = BForm(request.POST, prefix = "b") 
      c_form = CForm(request.POST, prefix = "c") 
      if primary_form.is_valid() and b_form.is_valid() and c_form.is_valid(): # All validation rules pass 
        print "all validation passed" 
        primary = primary_form.save() 
        b_form.cleaned_data["primary"] = primary 
        b = b_form.save() 
        c_form.cleaned_data["primary"] = primary 
        c = c_form.save() 
        return HttpResponseRedirect("/viewer/%s/" % (primary.name)) 
      else: 
        print "failed" 

     else: 
      primary_form = PrimaryForm(prefix = "primary") 
      b_form = BForm(prefix = "b") 
      c_form = Form(prefix = "c") 
    return render_to_response('multi_model.html', { 
    'primary_form': primary_form, 
    'b_form': b_form, 
    'c_form': c_form, 
     }) 

phương pháp này sẽ cho phép bạn làm bất cứ điều gì xác nhận bạn yêu cầu, cũng như tạo ra cả ba đối tượng trên cùng một trang. Tôi cũng đã sử dụng các trường javascript và ẩn để cho phép tạo nhiều đối tượng B, C trên cùng một trang.

+2

Trong ví dụ này, làm cách nào để bạn thiết lập khóa ngoài cho các mô hình B và C để trỏ đến mô hình Chính? – User

+0

Tôi chỉ có hai mô hình mà tôi muốn hiển thị trên cùng một biểu mẫu. Nhưng tôi không nhận được câu lệnh exclude = ('primary',). Điều gì là chính? Nếu có 2 mô hình CustomerConfig và Contract. Hợp đồng có khóa ngoài cho CustomerConfig. Chẳng hạn như customer_config = models.ForeignKey ('CustomerPartnerConfiguration') 'Chính' là gì? – pitchblack408

62

Tôi chỉ là trong khoảng tình cảnh tương tự một ngày trước, và đây là của tôi 2 cent:

1) Tôi tìm thấy cho là các cuộc biểu tình ngắn nhất và ngắn gọn nhất của entry mô hình đa dạng duy nhất ở đây: http://collingrady.wordpress.com/2008/02/18/editing-multiple-objects-in-django-with-newforms/.

Tóm lại: Tạo biểu mẫu cho từng mô hình, gửi cả hai mẫu vào một mẫu đơn lẻ <form>, sử dụng phím prefix và có chế độ xem xử lý xác thực. Nếu có sự phụ thuộc, chỉ cần đảm bảo bạn lưu mô hình "cha mẹ" trước khi phụ thuộc và sử dụng ID của cha mẹ cho khóa ngoài trước khi cam kết lưu mô hình "con". Liên kết có bản demo.

2) Có thể formets có thể bị đánh vào việc này, nhưng theo như tôi delved, formets chủ yếu để nhập bội số của cùng một mô hình, mà có thể được tùy chọn gắn với mô hình/mô hình khác bằng khóa ngoài. Tuy nhiên, dường như không có tùy chọn mặc định để nhập nhiều hơn một dữ liệu của mô hình và đó không phải là những gì mà formset có ý nghĩa.

3

Tôi hiện đang có chức năng giải pháp thay thế (nó vượt qua các bài kiểm tra đơn vị của tôi). Đó là một giải pháp tốt cho ý kiến ​​của tôi khi bạn chỉ muốn thêm một số lượng hạn chế của các lĩnh vực từ các mô hình khác.

Tôi có thiếu gì đó ở đây không?

class UserProfileForm(ModelForm): 
    def __init__(self, instance=None, *args, **kwargs): 
     # Add these fields from the user object 
     _fields = ('first_name', 'last_name', 'email',) 
     # Retrieve initial (current) data from the user object 
     _initial = model_to_dict(instance.user, _fields) if instance is not None else {} 
     # Pass the initial data to the base 
     super(UserProfileForm, self).__init__(initial=_initial, instance=instance, *args, **kwargs) 
     # Retrieve the fields from the user model and update the fields with it 
     self.fields.update(fields_for_model(User, _fields)) 

    class Meta: 
     model = UserProfile 
     exclude = ('user',) 

    def save(self, *args, **kwargs): 
     u = self.instance.user 
     u.first_name = self.cleaned_data['first_name'] 
     u.last_name = self.cleaned_data['last_name'] 
     u.email = self.cleaned_data['email'] 
     u.save() 
     profile = super(UserProfileForm, self).save(*args,**kwargs) 
     return profile 
8

Các MultiModelForm từ django-betterforms là một wrapper thuận tiện để làm những gì được mô tả trong Gnudiff's answer. Nó kết thúc thường xuyên ModelForm s trong một lớp duy nhất mà là minh bạch (ít nhất là cho sử dụng cơ bản) được sử dụng như một hình thức duy nhất. Tôi đã sao chép một ví dụ từ tài liệu của họ bên dưới.

# forms.py 
from django import forms 
from django.contrib.auth import get_user_model 
from betterforms.multiform import MultiModelForm 
from .models import UserProfile 

User = get_user_model() 

class UserEditForm(forms.ModelForm): 
    class Meta: 
     fields = ('email',) 

class UserProfileForm(forms.ModelForm): 
    class Meta: 
     fields = ('favorite_color',) 

class UserEditMultiForm(MultiModelForm): 
    form_classes = { 
     'user': UserEditForm, 
     'profile': UserProfileForm, 
    } 

# views.py 
from django.views.generic import UpdateView 
from django.core.urlresolvers import reverse_lazy 
from django.shortcuts import redirect 
from django.contrib.auth import get_user_model 
from .forms import UserEditMultiForm 

User = get_user_model() 

class UserSignupView(UpdateView): 
    model = User 
    form_class = UserEditMultiForm 
    success_url = reverse_lazy('home') 

    def get_form_kwargs(self): 
     kwargs = super(UserSignupView, self).get_form_kwargs() 
     kwargs.update(instance={ 
      'user': self.object, 
      'profile': self.object.profile, 
     }) 
     return kwargs 
Các vấn đề liên quan