天天看點

如何了解Django的save(commit=False)方法和save_m2m()方法

什麼時候使用save(commit=False)方法,save_m2m方法以及如何使用是Django表單forms進階必需了解的知識。我們今天就帶你來看一看。

何時使用save(commit=False)方法

Stackoverflow上其實已經有了一段非常精煉的答案。英文原文如下,我把它翻譯了一下:

That's useful when you get most of your model data from a form, but need to populate some 

null=False

 fields with non-form data. Saving with commit=False gets you a model object, then you can add your extra data and save it.

當你通過表單擷取你的模型資料,但是需要給模型裡null=False字段添加一些非表單的資料,該方法會非常有用。如果你指定commit=False,那麼save方法不會了解将表單資料存儲到資料庫,而是給你傳回一個目前對象。這時你可以添加表單以外的額外資料,再一起存儲。

save(commit=False)方法實際應用案例

下面我們來看一個實際應用案例。我們建立了一個叫文章Article的模型,裡面包含title, body和作者author等多個字段,其中author字段非空null=False。我們由Article模型建立了一個ArticleForm表單,可以讓使用者發表新文章,但是我們故意把author字段除外了,因為我們不希望使用者編輯作者。

最後使用者送出的表單資料裡肯定沒有author,當這樣的資料送出到資料庫時肯定會有問題的。是以我們先通過 article = form.save(commit=False)建立article執行個體,此時讓Django先不要發送資料到資料庫,等待我們把author添加好後,再把資料一起存儲到資料庫中。

下面是視圖檔案views.py的代碼。最重要的是ArticleForm構成和article_create方法。

from .models import Article
from django.forms import ModelForm
from django.http import HttpResponseRedirect
from django.shortcuts import render

class ArticleForm(ModelForm):
    class Meta:
        model = Article
        exclude = ['author']


def article_create(request):
    if request.method == 'POST':
        form = ArticleForm(request.POST)
        if form.is_valid():
            article = form.save(commit=False)
            # commit=False告訴Django先不送出到資料庫.
            article.author = request.user  # 添加額外資料
            article.save()  # 發送到資料庫

            return HttpResponseRedirect("/blog/")
    else:
        form = ArticleForm()
    return render(request, 'blog/article_create_form.html', {'form': form})      

如果你使用Django自帶的基于類的視圖(CBV), 你可以使用form_valid方法完成上述同樣的操作。具體代碼如下。

from django.views.generic.edit import CreateView
from .models import Article
from django.forms import ModelForm


# Create your views here.
class ArticleForm(ModelForm):
    class Meta:
        model = Article
        exclude = ['author']

        
class ArticleCreateView(CreateView):
    model = Article
    form_class = ArticleForm
    template_name = 'blog/article_create_form.html'

    # Associate form.instance.user with self.request.user
    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)
      

何時使用save_m2m方法及如何使用

save_m2m方法隻用來存儲多對多的關系。當你同時滿足下面兩個條件時,你需要使用此方法。如果你直接使用save()或form_valid()方法,是可以直接存儲多對多(m2m)關系的,不需要用save_m2m。

  • 你使用了save(commit=False)方法
  • 你的model裡有多對多的關系(比如tags)

假設我們文章模型裡有tags這個多對多的字段,我們的article_create方法需要增加一行。

def article_create(request):
    if request.method == 'POST':
        form = ArticleForm(request.POST)
        if form.is_valid():
            article = form.save(commit=False)
            # commit=False tells Django that "Don't send this to database yet.

            article.author = request.user  # Set the user object here
            article.save()  # Now you can send it to DB
            form.save_m2m()

            return HttpResponseRedirect("/blog/")
    else:
        form = ArticleForm()
    return render(request, 'blog/article_create_form.html', {'form': form})      

欲擷取更多Python與Django Web開發實戰與教程,請積極關注我們微信公衆号。

如何了解Django的save(commit=False)方法和save_m2m()方法