Django: nhiều mô hình trong một mẫu sử dụng biểu mẫu [đã đóng]


114

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

Vì tôi còn khá mới với Django, tôi có xu hướng làm việc lặp đi 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. Có vẻ như mức độ kiểm soát mà tôi đang tìm kiếm yêu cầu bộ định dạng hoặc làm mọi thứ bằng tay, hoàn thành với một trang mẫu viết tay tẻ nhạt, điều mà tôi đang cố gắng tránh.

Có tính năng đáng yêu nào mà tôi đang thiếu không? Ai đó có tài liệu tham khảo hoặc ví dụ tốt cho việc sử dụng bộ định dạng? Tôi đã dành cả cuối tuần trên tài liệu API cho chúng và tôi vẫn không biết gì. Nó có phải là một vấn đề thiết kế nếu tôi chia nhỏ và viết tay mọi thứ?


lúc đầu, bạn nên xác thực biểu mẫu khách hàng của mình và nếu nó hợp lệ, hãy tạo một bản sao từ request.POST (new_data = request.POST.copy ()) .và sau đó lấy id khách hàng (từ biểu mẫu khách hàng đã được xác thực) và với việc cập nhật new_data, hãy thực hiện id khách hàng một giá trị cho trường khóa ngoại (có thể là khách hàng trong mô hình của bạn). Và cuối cùng hãy xem xét new_data để xác thực biểu mẫu thứ hai của bạn (Vé)
Negar37

Câu trả lời:


87

Điều này thực sự không quá khó để thực hiện với ModelForms . Vì vậy, giả sử 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 xử lý BÀI ĐĂNG.

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()

Đây là tài liệu để xác nhận tùy chỉnh.


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

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

66

Tôi vừa ở trong tình huống tương tự cách đây một ngày, và đây là 2 xu của tôi:

1) Tôi được cho là minh chứng ngắn gọn và súc tích nhất về nhiều mục nhập mô hình ở dạng duy nhất tại đâ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 vào mẫu trong một mô hình duy nhất <form>, sử dụng prefixkeyarg và có xác thực chế độ xem. Nếu có phụ thuộc, chỉ cần đảm bảo rằng bạn lưu mô hình "cha" trước khi phụ thuộc và sử dụng ID của phụ huynh cho khóa ngoại trước khi giới hạn lưu mô hình "con". Liên kết có bản demo.

2) Có thể các bộ định dạng có thể bị đánh bại khi thực hiện điều này, nhưng theo như tôi đã nghiên cứu kỹ, các bộ định dạng chủ yếu để nhập bội số của cùng một mô hình, có thể được tùy chọn gắn với mô hình / mô hình khác bằng các khóa ngoại. Tuy nhiên, dường như không có tùy chọn mặc định nào để nhập nhiều dữ liệu của một mô hình và đó không phải là những gì bộ định dạng dường như dành cho.


26

Gần đây tôi đã gặp một số vấn đề và chỉ tìm cách làm điều này. Giả sử bạn có ba lớp, chính, B, C và B, C có khóa ngoại cho 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 thực hiện bất kỳ xác thực nào bạn yêu cầu, cũng như tạo cả ba đối tượng trên cùng một trang. Tôi cũng đã sử dụng javascript và các trường ẩn để cho phép tạo nhiều đối tượng B, C trên cùng một trang.


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

Tôi chỉ có hai mô hình mà tôi muốn hiển thị trên cùng một mẫu. Nhưng tôi không nhận được câu lệnh loại trừ = ('chính',). Chính là gì? 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

10

Các MultiModelForm từ django-betterformslà một wrapper thuận tiện để làm những gì được mô tả trong câu trả lời của Gnudiff . Nó bao bọc các ModelForms thông thường trong một lớp duy nhất trong suốt (ít nhất là cho cách sử dụng cơ bản) được sử dụng như một biểu mẫu 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

Chỉ cần xem django-betterformsvà lớp MultiModelForm của nó trước khi xem câu trả lời của bạn. Giải pháp của họ trông thực sự tốt nhưng có vẻ như nó đã không được cập nhật trong một thời gian. Bạn vẫn đang sử dụng @jozxyqk này chứ? Có vấn đề gì không?
mê mẩn

@enchance đã được vài năm. Quay lại sau đó tôi thấy nó thuận tiện và một trong những lựa chọn tốt hơn xung quanh. Nếu bạn không quá ưa thích nó, nó sẽ tiết kiệm thời gian. Tôi có thể tưởng tượng khi bạn muốn bắt đầu tùy chỉnh và thực hiện các biểu mẫu không tầm thường thì việc cuộn của riêng bạn sẽ dễ dàng hơn. Dễ dàng trộn các hình thức và ngữ cảnh trong các khung nhìn là tính năng đầu tiên mà tôi thực sự nghĩ rằng mình đã bỏ lỡ trong django.
jozxyqk

Cảm ơn người đàn ông trả lời. Tôi đang xem xét việc chỉ đổi nó và có thể cập nhật một vài thứ trong quá trình thực hiện. Từ những gì tôi đã thấy cho đến nay, nó đang hoạt động tốt. Bạn nói đúng, đó là một tiết kiệm thời gian rất lớn.
mê mẩn

5

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

Am i thiếu cái gì ở đây ?

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

3

"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."

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ị các trường mong muốn.

  2. Mở rộng Biểu mẫu với các quy tắc xác thực trong biểu mẫu. Thông thường đây là một cleanphương pháp.

    Hãy chắc chắn rằng phần này hoạt động tốt.

Sau khi hoàn tất, bạn có thể thoát khỏi giao diện quản trị được tích hợp sẵn.

Sau đó, bạn có thể đánh lừa với nhiều biểu mẫu 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 hàm xem để đọc và xác thực các biểu mẫu khác nhau và thực hiện các lưu đối tượng khác nhau ().

"Nó có phải là một vấn đề thiết kế nếu tôi phá vỡ và viết tay mọi thứ?" Không, chỉ là nhiều thời gian mà không mang lại nhiều lợi ích.


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 gì hơn nữa? Điều đó dường như mô tả một giải pháp. Còn điều gì nên nói nữa? Câu hỏi mơ hồ, vì vậy rất khó để cung cấp mã thực tế. Thay vì phàn nàn, hãy cung cấp một đề xuất để cải thiện. Bạn có đề nghị gì?
S.Lott

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.