2010-06-19 24 views
15

Bir 'through' sınıf tablosu içeren bir m2m veri kaydetme konusunda sorun yaşıyorum. Seçili tüm üyeleri (formda seçili) içinden tabloya kaydetmek istiyorum. Ancak, görünümdeki 'geçiş' tablosunu nasıl başlatacağımı bilmiyorum.Django m2m form "içinden" kaydet tablo

kodum:

class Classroom(models.Model): 
    user = models.ForeignKey(User, related_name = 'classroom_creator') 
    classname = models.CharField(max_length=140, unique = True) 
    date = models.DateTimeField(auto_now=True) 
    open_class = models.BooleanField(default=True) 
    members = models.ManyToManyField(User,related_name="list of invited members", through = 'Membership') 

class Membership(models.Model): 
     accept = models.BooleanField(User) 
     date = models.DateTimeField(auto_now = True) 
     classroom = models.ForeignKey(Classroom, related_name = 'classroom_membership') 
     member = models.ForeignKey(User, related_name = 'user_membership') 

ve görünümde

:

def save_classroom(request): 
    classroom_instance = Classroom() 
    if request.method == 'POST': 
     form = ClassroomForm(request.POST, request.FILES, user = request.user) 
     if form.is_valid(): 
      new_obj = form.save(commit=False) 
      new_obj.user = request.user 
      new_obj.save() 
      membership = Membership(member = HERE SELECTED ITEMS FROM FORM,classroom=new_obj) 

      membership.save() 

nasıl Üyelik tablo için üyelik initialize gerektiğini doğru doldurulması?

cevap

19

ne gerek daha olasıdır Ara tabloları kullanmanız durumunda, POST verilerini elle işlemeniz ve tüm gerekli alanlarla Üyelik nesneleri oluşturmanız gerekir (similar problem). request.POST (.getlist) manipüle nasıl

def save_classroom(request): 
    if request.method == 'POST': 
     form = ClassroomForm(request.POST, request.FILES) 

     if form.is_valid(): 
      new_obj = form.save(commit=False) 
      new_obj.user = request.user 
      new_obj.save() 

      for member_id in request.POST.getlist('members'): 
       membership = Membership.objects.create(member_id = int(member_id), classroom = new_obj) 
      return HttpResponseRedirect('/') 
    else: 
     form = ClassroomForm() 
    return render_to_response('save_classroom.html', locals()) 

Not: En temel çözüm gibi bir şey için görünümünüzü değiştirmektir. Bunun nedeni, post ve get'in bazı sonuçları olan QueryDict nesnesi olmasıdır (request.POST ['members'] her zaman bir nesne döndürecektir!).

Bu kodu değiştirebilir

(vb hata işleme) daha güvenilir olsun ve daha ayrıntılı, örneğin:

member = get_object_or_404(User, pk = member_id) 
membership = Membership.objects.create(member = member , classroom = new_obj) 

Ama bir döngü içinde bazı db sorgulama yapılarak unutmayın bir olmadığı Genel olarak iyi bir fikir (performans açısından).

+0

bu kadardı! Python için oldukça yeni olduğumdan, gerçekten bazı baş ağrıları yarattı. Thnx çok! – dana

+0

Soru: Sınıfın yaratıcısını üye olarak eklemek istiyorum (required.user) ve bu listeye nasıl yapabilirim? Teşekkürler! – dana

+1

Amacınızı aldığımdan emin değilim. Kullanıcı ve sınıf (üyelik = Membership.objects.create (üye = request.user, sınıf = new_obj) ) arasında yeni bir bağlantı oluşturmak için yeni üyelik nesnesi (döngü dışında) oluşturabilir veya ekstra member_id (POST içinde request.user) kimliği ve varolan kodu (döngü için) kullanarak kullanıcı sınıfı ilişkisi oluşturulacaktır. İkinci seçenek için, formunuzdaki bazı gizli alanlarda request.user.id dosyasını saklamanız gerekir. – dzida

1

Ayrıca üyelik sınıfa belirtmek gerekir:

membership = Membership(member = request.user, 
         classroom=new_obj) #if new_obj if your classroom 
membership.save() 

Ben de accept = models.BooleanField(User) yılında User kaldırmak sanırım. auto_now'u kullanıyorsanız kaydetme tarihini ayarlamak gerekli olmamalıdır!

membership = Membership(member = HERE SELECTED ITEMS FROM FORM,classroom=new_obj) 
membership.save() 

form.save_m2m() 

ile Ama: Ama belki `auto_now_add size yerini alabilir (değil aracı masanın üzerinden) Normal m2m ilişkisi kullanılarak durumunda ( http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.DateField)

+0

sayesinde doğal bir çözüm gibi görünüyor, sorun o new_obj - benim sınıf henüz oluşturulmadı sanırım. şimdi, new_obj.save() öğesinden sonra yukarıdaki bildirimi ekledim ve yeni hata: Arabirim modeli belirten ManyToManyField değerlerini ayarlanamıyor. Bunun yerine Üyelik Yöneticisini kullanın. :) – dana

+0

Membership.objects.create() ile deneyin, ancak classromm nesnesini belirtmeyi unutmayın! –

+0

Bir soruyu yıllar öncesinden yeniden güncellemekten ötürü özür dilerim, ancak kayıt oluşturmaktan ziyade ne güncellemek isterseniz? Bir kayıt zaten mevcutsa, güncelleme yapmak yerine objects.create yeni bir kayıt eklemez mi? – nlr25

0

Bu, form_valid yöntemini kullanan benzer ancak farklı bir uygulama için genel bir UpdateForm sınıf tabanlı görünümünde (django 1.8) bunu yaptım.

def form_valid(self, form): 
    """ 
    If the form is valid, save the associated model. 
    """ 
    self.object.members.clear() 
    self.object = form.save(commit=False) 
    self.object.user = self.request.user 
    self.object.save() 

    list_of_members = form.cleaned_data['members'] 

    ClassRoom.objects.bulk_create([ 
      Membership(
       Course=self.object, 
       member=member_person, 
       order=num) 
      for num, member_person in enumerate(list_of_members) 
     ]) 
    return super(ModelFormMixin, self).form_valid(form) 
1

Dzida'nın yaptığı gibi, ancak bunun yerine form.cleaned_data'yı kullanın.yayın:

def save_classroom(request): 
    if request.method == 'POST': 
     form = ClassroomForm(request.POST, request.FILES) 

     if form.is_valid(): 
      new_obj = form.save(commit=False) 
      new_obj.user = request.user 
      new_obj.save() 

      for member in form.cleaned_data['members'].all(): 
       Membership.objects.create(member = member, classroom = new_obj) 

      return HttpResponseRedirect('/') 
    else: 
     form = ClassroomForm() 
    return render_to_response('save_classroom.html', locals()) 
Ayrıca bazı üyelikleri yüzden, silinebilir dikkate almak gerekir

:

def save_classroom(request): 
    if request.method == 'POST': 
     form = ClassroomForm(request.POST, request.FILES) 

     if form.is_valid(): 
      new_obj = form.save(commit=False) 
      new_obj.user = request.user 
      new_obj.save() 

      final_members = form.cleaned_data['members'].all() 
      initial_members = form.initial['members'].all() 

      # create and save new members 
      for member in final_members: 
       if member not in initial_members: 
        Membership.objects.create(member = member, classroom = new_obj) 

      # delete old members that were removed from the form 
      for member in initial_members: 
       if member not in final_members: 
        Membership.objects.filter(member = member, classroom = new_obj).delete() 

      return HttpResponseRedirect('/') 
    else: 
     form = ClassroomForm() 
    return render_to_response('save_classroom.html', locals()) 

Eğer (jenerik CBV gibi: form_class=ClassroomForm) modeli formları kullanırsanız, geçersiz kılma ve tasarruf mantığı koymak save yöntemde, bir şey gibi yukarıda:

ClassroomForm(forms.ModelForm): 
    members = ModelMultipleChoiceField(
     queryset=Classroom.objects.all(), 
     widget=SelectMultiple 
    ) 

    def save(self, commit=True): 
     classroom = super().save(commit=False) 
      if commit: 
       classroom.save() 
       if 'members' in self.changed_data: 
        final_members = form.cleaned_data['members'].all() 
        initial_members = form.initial['members'].all() 

        # create and save new members 
        for member in final_members: 
         if member not in initial_members: 
          Membership.objects.create(member = member, classroom = new_obj) 

        # delete old members that were removed from the form 
        for member in initial_members: 
         if member not in final_members: 
          Membership.objects.filter(member = member, classroom = new_obj).delete() 

     return classroom