2012-01-25 28 views
5

Tôi có hai mô hình:Lưu mới chính nước ngoài với hình thức django

class Studio(models.Model): 
    name = models.CharField("Studio", max_length=30, unique=True) 

class Film(models.Model): 
    studio = models.ForeignKey(Studio, verbose_name="Studio") 
    name = models.CharField("Film Name", max_length=30, unique=True) 

Tôi có một hình thức phim cho phép người sử dụng để thể chọn một Studio từ trước, hoặc gõ vào một cái mới:

class FilmForm(forms.Form): 
    studio = forms.ModelChoiceField(Studio.objects, required=False) 
    new_studio = forms.CharField(max_length=30, required=False, label = "New Studio Name") 
    name = forms.CharField(max_length=30, label = "Film Name") 

Có xác thực để đảm bảo rằng tên new_studio chưa tồn tại. Nếu người dùng nhập new_studio, tôi muốn lưu studio và sau đó lưu Phim mới.

form = FilmForm(request.POST) 
if form.is_valid(): # All validation rules pass 
    std = Studio(name = form.cleaned_data['new_studio']) 
    std.save() 

Nhưng sau đó làm cách nào để lưu chủ thể Phim đối tượng id studio mới? Tôi đã thấy this question, nhưng nếu tôi có nhiều trường khác trong mô hình Phim và Biểu mẫu Phim thì sao? Nếu tôi sử dụng câu trả lời được liên kết, tôi sẽ phải nhập mỗi trường:

studio = Studio.objects.get(name=request.POST['new_studio']) 
newFilm=Film(name=form.name, studio=studio, field_one = form.field_one, field_two = form.field_two, etc.) 

Cách chính xác để thực hiện điều này là gì?

Trả lời

5

Thực sự, vấn đề duy nhất của bạn là bạn đã sử dụng tiêu chuẩn Form thay vì ModelForm. Form không có phương thức save vì phương thức này không liên quan đến bất kỳ thứ gì (nghĩa là nó không biết phải lưu gì hoặc lưu ở đâu).

Tuy nhiên, nếu bạn sử dụng ModelForm, bạn cần phải chăm sóc mọi logic liên quan đến việc tạo một studio mới trong biểu mẫu. Điều này thực sự tốt hơn, bởi vì sau đó bạn chỉ có thể sử dụng biểu mẫu và không phải lo lắng về bất cứ điều gì khác: biểu mẫu chứa tất cả logic cần thiết để lưu chính xác.

class FilmForm(forms.ModelForm): 
    class Meta: 
     model = Film 

    # only need to define `new_studio`, other fields come automatically from model 
    new_studio = forms.CharField(max_length=30, required=False, label = "New Studio Name") 

    def __init__(self, *args, **kwargs): 
     super(FilmForm, self).__init__(*args, **kwargs) 
     # make `studio` not required, we'll check for one of `studio` or `new_studio` in the `clean` method 
     self.fields['studio'].required = False 

    def clean(self): 
     studio = self.cleaned_data.get('studio') 
     new_studio = self.cleaned_data.get('new_studio') 
     if not studio and not new_studio: 
      # neither was specified so raise an error to user 
      raise forms.ValidationError('Must specify either Studio or New Studio!') 
     elif not studio: 
      # get/create `Studio` from `new_studio` and use it for `studio` field 
      studio, created = Studio.objects.get_or_create(name=new_studio) 
      self.cleaned_data['studio'] = studio 

     return super(FilmForm, self).clean() 

Sau đó, theo quan điểm của bạn, tất cả các bạn cần là:

if form.is_valid(): 
    form.save() 
+0

oh, hmm. Tốt đẹp! Tôi nghĩ tôi phải đi một chặng đường dài để bù đắp cho khả năng thêm một studio mới. Cảm ơn! –

+0

Tôi đang gặp một vấn đề.Tôi đã tạo kiểm tra xác thực cho một studio trùng lặp (nếu người dùng nhập new_studio đã tồn tại). Các mã chính xác đạt đến ValidationError, nhưng dường như vẫn tiếp tục làm sạch anyway và cho tôi lỗi: Không thể gán None: "Film.studio" không cho phép giá trị null. –

+0

Phương pháp 'sạch' sẽ giải quyết mọi vấn đề đó. Nếu 'new_studio' tồn tại, nó sẽ chỉ đơn giản là lấy studio hiện có thay vì tạo một cái mới (' get_or_create'), vì vậy việc kiểm tra xác nhận bạn có là không cần thiết. Trường hợp duy nhất không được bảo vệ bởi phương thức 'clean' ở trên là nếu' studio' được nhập nhưng 'new_studio' thì không. Tuy nhiên, đó sẽ không phải là một lỗi và không có gì đặc biệt cần phải được thực hiện trong kịch bản đó. Tôi tưởng tượng bất cứ điều gì kiểm tra xác nhận bạn đang làm là rối tung với các giá trị bằng cách nào đó. –

2

tôi stumbled trên câu hỏi này và tôi nghĩ rằng tôi có một câu trả lời tốt hơn cho những người tìm kiếm trong tương lai.

Django đi kèm với thứ được gọi là Inline Formsets giúp bạn quản lý các mối quan hệ trong biểu mẫu.

Bạn chỉ cần tạo mô hình của mình giống như bạn đã thực hiện với ForeignKeys tương ứng. Sau đó, trong Forms.py nhập này

from django.forms.models import inlineformset_factory 

Sau đó:

YOUR_FORMSET = inlineformset_factory(Model1,Model2) 

Trở lại trên yout views.py bạn nên nhập cả mẫu của bạn và tạo ra YOUR_FORMSET mới của bạn.

Sau khi làm điều này, phương pháp của bạn nên sử dụng inlineformset như thế này:

def add_question(request): 

    if request.method == 'POST': 


     form =AddQuestionForm(request.POST, request.FILES) 
     if form.is_valid(): 
      new_question = form.save(commit=False) 

      question_formset = QuestionFormset(request.POST, instance=new_question) 
      if question_formset.is_valid(): 
       form.save() 
       question_formset.save() 
       return HttpResponseRedirect(reverse('polls:detail',args=(new_question.pk,))) 
     else: 
      print(form.errors) 
    else: 
     form = AddQuestionForm() 
     question_formset = QuestionFormset(instance=Question()) 
    return render(request, 'polls/add.html', {'form':form, 'question_formset':question_formset,}) 

Tôi đang sử dụng ví dụ của riêng tôi nhưng ý tưởng được giải thích.

Nếu bạn muốn đọc bản giải thích cụ thể hơn, hãy đọc số blog post tuyệt vời này mà tôi đã tìm thấy.

+0

Cảm ơn bài đăng blog tuyệt vời đó :) – Martin

+0

Hy vọng nó sẽ giúp nhiều người hơn :) – villancikos

+0

liên kết cung cấp cho 404 – AmiNadimi

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