Django: formları kullanan tek bir şablonda birden çok model [kapalı]


114

Bir destek bileti izleme uygulaması oluşturuyorum ve tek bir sayfadan oluşturmak istediğim birkaç modelim var. Biletler, ForeignKey aracılığıyla bir Müşteriye aittir. Notlar da bir ForeignKey aracılığıyla Biletlere aittir. Bir Müşteri seçme (bu tamamen ayrı bir proje) YA DA yeni bir Müşteri oluşturma, ardından bir Bilet oluşturma ve son olarak yeni bilete atanmış bir Not oluşturma seçeneğine sahip olmak istiyorum.

Django'da oldukça yeni olduğum için, her seferinde yeni özellikler deneyerek yinelemeli çalışma eğilimindeyim. ModelForms ile oynadım ama bazı alanları gizlemek ve bazı karmaşık doğrulama işlemleri yapmak istiyorum. Görünüşe göre aradığım kontrol seviyesi ya form setlerini gerektiriyor ya da her şeyi elle yapıyor, kaçınmaya çalıştığım sıkıcı, elle kodlanmış bir şablon sayfasıyla birlikte.

Kaçırdığım hoş bir özellik var mı? Birisinin form setlerini kullanmak için iyi bir referansı veya örneği var mı? Onlar için API dokümanları üzerinde bütün bir hafta sonu geçirdim ve hala bir fikrim yok. Her şeyi parçalayıp elle kodlarsam bu bir tasarım sorunu olur mu?


önce müşteri formunuzu doğrulamalı ve geçerliyse request.POST (new_data = request.POST.copy ()) 'den bir kopya oluşturmalı ve ardından müşteri kimliğini (doğrulanmış müşteri formundan) almalı ve new_data'yı güncelleyerek yapmalısınız müşteri kimliği, yabancı anahtar alanı için bir değer (belki modelinizdeki müşteri). Ve son olarak, ikinci formunuzu (Biletler) doğrulamak için new_data'yı düşünün
Negar37

Yanıtlar:


87

Bunu ModelForms ile uygulamak gerçekten çok zor değil . Diyelim ki Form A, B ve C'ye sahipsiniz. Formların her birini ve sayfayı yazdırıyorsunuz ve şimdi POST'u işlemeniz gerekiyor.

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

İşte özel doğrulama için belgeler.


2
btw, form setlerinin tanımladığınız soruna iyi bir çözüm olduğunu düşünmüyorum. Her zaman bir modelin birden çok örneğini temsil etmek için onları kullandım. Örneğin, bir başvuru formunuz var ve 3 referans modelinin 3 örneğini içeren bir form kümesi yapmak istiyorsunuz.
Jason Christa

1
bunu yaptığınız şekilde .is_valid () çağrısının kısa devre olmadığını unutmayın. Kısa devre yapmak istiyorsanız, .is_valid () işlevini çağırmayı 've' kadar geciktirmeniz gerekir.
Lie Ryan

66

Sadece bir gün önce aynı durumdaydım ve işte 2 sentim:

1) Burada tek formda çoklu model girişinin tartışmasız en kısa ve en öz gösterimini buldum: http://collingrady.wordpress.com/2008/02/18/editing-multiple-objects-in-django-with-newforms/ .

Özetle: Her model için bir form oluşturun, her ikisini de keyarg <form>kullanarak tek bir şablona prefixgönderin ve görünüm tutamacı doğrulamasına sahip olun. Bağımlılık varsa, bağımlı modelden önce "üst" modeli kaydettiğinizden emin olun ve "alt" modeli kaydetmeden önce yabancı anahtar için ebeveynin kimliğini kullanın. Bağlantıda demo var.

2) Belki form kümeleri bunu yapmak için dövülebilir, ancak benim keşfettiğim kadarıyla, form kümeleri öncelikle isteğe bağlı olarak yabancı anahtarlarla başka bir modele / modellere bağlanabilen aynı modelin katlarını girmek içindir . Ancak, birden fazla modelin verilerini girmek için varsayılan bir seçenek yok gibi görünüyor ve bu, formsetin kastettiği şey değil.


26

Çok yakın zamanda bazı problemler yaşadım ve bunu nasıl yapacağımı yeni çözdüm. Üç sınıfınız olduğunu varsayarsak, Birincil, B, C ve B, C'nin birincil için yabancı anahtarı vardır.

    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,
      })

Bu yöntem, istediğiniz doğrulamayı yapmanıza ve aynı sayfada üç nesnenin tümünü oluşturmanıza izin vermelidir. Aynı sayfada birden çok B, C nesnesinin oluşturulmasına izin vermek için javascript ve gizli alanlar da kullandım.


3
Bu örnekte, B ve C modelleri için yabancı anahtarları Birincil modeli gösterecek şekilde nasıl ayarlıyorsunuz?
Kullanıcı

Aynı formda göstermek istediğim sadece iki modelim var. Ancak exclude = ('birincil',) ifadesini alamıyorum. Birincil nedir? Müşteri Yapılandırması ve Sözleşme olmak üzere 2 model varsa. Sözleşmede, CustomerConfig için yabancı anahtar vardır. Customer_config = models.ForeignKey ('CustomerPartnerConfiguration') gibi 'birincil' nedir?
pitchblack408

10

MultiModelForm dan django-betterformsaçıklanan ne yapacağını uygun bir sarıcı Gnudiff cevabı . Düzenli ' ModelFormleri şeffaf bir şekilde (en azından temel kullanım için) tek bir form olarak kullanılan tek bir sınıfa sarar . Aşağıdaki belgelerinden bir örnek kopyaladım.

# 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

Sadece testere django-betterformsve MultiModelForm Cevabınız genelinde gelmeden önce sınıfı. Çözümleri gerçekten iyi görünüyor ancak bir süredir güncellenmemiş gibi görünüyor. Hala bu @jozxyqk kullanıyor musunuz? Herhangi bir problem?
ENCHANCE

@enchance, birkaç yıl oldu. O zamanlar bunu uygun buldum ve etrafındaki daha iyi seçeneklerden biri. Onunla çok süslenmezseniz, biraz zaman kazandırır. Önemsiz olmayan formları özelleştirmeye ve yapmaya başlamak istediğinizde kendi formlarınızı almanın daha kolay olacağını hayal edebiliyorum. Görünümlerde formları ve bağlamları kolayca karıştırmak, django'da gerçekten kaçırdığımı düşündüğüm ilk özellik.
jozxyqk

Cevap için teşekkürler dostum. Sadece çatallamayı ve yol boyunca birkaç şeyi güncellemeyi düşünüyorum. Şimdiye kadar gördüklerime göre gayet iyi çalışıyor. Haklısın, bu büyük bir zaman kazandırıcı.
ENCHANCE

5

Şu anda bir geçici çözüm işlevim var (birim testlerimi geçiyor). Diğer modellerden sadece sınırlı sayıda alan eklemek istediğinizde bana göre iyi bir çözüm.

Burada bir şey mi kaçırıyorum?

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

"Bazı alanları gizlemek ve bazı karmaşık doğrulama işlemleri yapmak istiyorum."

Yerleşik yönetici arayüzüyle başlıyorum.

  1. İstenen alanları göstermek için ModelForm'u oluşturun.

  2. Formu, formun içindeki doğrulama kurallarıyla genişletin. Genellikle bu bir cleanyöntemdir.

    Bu bölümün oldukça iyi çalıştığından emin olun.

Bu yapıldıktan sonra yerleşik yönetici arayüzünden uzaklaşabilirsiniz.

Daha sonra, tek bir web sayfasında birden çok, kısmen ilişkili formlarla dalga geçebilirsiniz. Bu, tüm formları tek bir sayfada sunmak için kullanılan bir dizi şablondur.

Daha sonra, çeşitli biçimlerdeki şeyleri okumak ve doğrulamak için görünüm işlevini yazmanız ve çeşitli nesne kaydetme işlemlerini () yapmanız gerekir.

"Her şeyi parçalayıp elle kodlarsam bu bir tasarım sorunu olur mu?" Hayır, pek fayda sağlamamak için çok fazla zaman.


Nasıl olduğunu bilmiyorum, öyleyse yapma
orokusaki

1
@orokusaki: Daha ne istersiniz? Bu bir çözümü tanımlıyor gibi görünüyor. Daha ne söylenmeli? Soru belirsizdir, bu nedenle gerçek kodu sağlamak zordur. Şikayet etmek yerine, lütfen iyileştirme için bir öneri sunun. Sen ne önerirsin?
S.Lott

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.