簡體   English   中英

Django Forms - 多對多關系

[英]Django Forms - Many to Many relationships

對Django來說相對較新,並嘗試將標准實踐拼湊在一起以處理表單中的M2M關系。 我已經有模型和數據庫平方。

對於這個例子,我在我的項目項目中編寫了一個應用程序,我正在嘗試添加類別。 為了簡單起見,文章有標題,正文,時間戳(不包含在表格中)和類別。 我更喜歡使用復選框來表示文章可以屬於的一個或多個類別。

到目前為止,我有:

models.py

class Category(models.Model):
    category = models.CharField(max_length=100)

    def __unicode__(self):
        return self.category


class Article(models.Model):
    title = models.CharField(max_length=200)
    body = models.TextField()
    pub_date = models.DateTimeField(auto_now_add=True)
    category = models.ManyToManyField(Category)

    def __unicode__(self):
        return self.title

views.py

def article_index(request):
    return render_to_response('article_index.html', {'articles': Article.objects.all()})

def article_detail(request, article_id=1):
    return render_to_response('article_detail.html', {'article': Article.objects.get(id=article_id)} )

def article_create(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ArticleForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            article = Article.objects.create(
                title=form.cleaned_data['title'],
                body=form.cleaned_data['body'],
                category=form.cleaned_data['category']
            )
            return redirect('article_index') # Redirect after POST
    else:
        form = ArticleForm() # An unbound form

    return render(request, 'article_form.html', { 'form': form })

forms.py

class ArticleForm(forms.Form):
    title = forms.CharField(required=True)
    body = forms.CharField(required=True, widget=forms.Textarea)
    category = forms.MultipleChoiceField(Category.objects.all(), widget=forms.CheckboxSelectMultiple)

我目前堅持的兩個項目是:

1)在視圖'article_create'中,我不確定如何創建類別(ies)作為Article對象的一部分。 在shell中,我必須通過調用save()來創建文章,然后在之后添加每個類別。 我是否需要在此處執行類似的操作,例如創建文章然后遍歷每個類別? 示例代碼表示贊賞。

2)尚未編寫'article_edit',假設它與create非常相似,但我不確定是否或如何處理邏輯以將先前選擇的類別與當前提交進行比較。 或者,我是否應該刪除正在編輯的文章的所有類別條目,並根據當前提交重新輸入? 這可能是最簡單的。 再次,此示例代碼將有所幫助。

謝謝!

每個文件的評論......

models.py

class Category(models.Model):
    category = models.CharField(max_length=100)

類別的名稱應該命名為name 一個名為category的字段我希望是models.ForeignKey("Category")

class Article(models.Model):
    title = models.CharField(max_length=200)
    body = models.TextField()
    pub_date = models.DateTimeField(auto_now_add=True)
    category = models.ManyToManyField(Category)

正如亞當指出的那樣,這應該被命名為categories 此外,它的反向(鏈接到Article Category中的字段)應該命名為articles 所以我們得到:

    categories = models.ManyToManyField(Category, related_name="articles")

所以現在你可以得到一個包含類別中所有文章的查詢集,例如:

get_object_or_404(Category, id=int(cat_id, 10)).articles.all()

views.py

def article_detail(request, article_id=1):

這里不要使用默認值。 ID 1沒有什么特別之處,如果有人忘記了ID,那應該是一個錯誤。

def article_create(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ArticleForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            article = Article.objects.create(
                title=form.cleaned_data['title'],
                body=form.cleaned_data['body'],
                category=form.cleaned_data['category']
            )

通過使用ModelForm ,這簡化為:

def article_create(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ArticleForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            form.save()
        return redirect('article_index') # Redirect after POST
    else:
        form = ArticleForm() # An unbound form

    return render(request, 'article_form.html', {'form': form})

forms.py

class ArticleForm(forms.Form):

你真的應該使用ModelForm這里的文檔 ):

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = ["title", "body", "category"]
        widgets = {
            'body': forms.Textarea(),
            'category': forms.CheckboxSelectMultiple()
        }

關於你的問題:

1)在視圖'article_create'中,我不確定如何創建類別(ies)作為Article對象的一部分。 在shell中,我必須通過調用save()來創建文章,然后在之后添加每個類別。 我是否需要在此處執行類似的操作,例如創建文章然后遍歷每個類別? 示例代碼表示贊賞。

IIRC, ModelForm.save()將為您處理這個問題。

2)尚未編寫'article_edit',假設它與create非常相似,但我不確定是否或如何處理邏輯以將先前選擇的類別與當前提交進行比較。 或者,我是否應該刪除正在編輯的文章的所有類別條目,並根據當前提交重新輸入? 這可能是最簡單的。 再次,此示例代碼將有所幫助。

編輯幾乎就像創建一樣。 您所要做的就是將原始對象與表單相關聯。 (通常,您可以從URL中找出原始對象的內容。)所以類似於:

def article_edit(request, article_id):
    article = get_object_or_404(Article, id=int(article_id, 10))

    if request.method == 'POST': # If the form has been submitted...
        form = ArticleForm(request.POST, instance=article)
        if form.is_valid(): # All validation rules pass
            form.save()
        return redirect('article_index') # Redirect after POST
    else:
        form = ArticleForm(instance=article)

    return render(request, 'article_form.html', {'form': form})

編輯:作為下面的jheld評論,您可以將article_createarticle_edit組合到一個視圖方法中:

def article_modify(request, article_id=None):
    if article_id is not None:
        article = get_object_or_404(Article, id=int(article_id, 10))
    else:
        article = None

    if request.method == 'POST': # If the form has been submitted...
        form = ArticleForm(request.POST, instance=article)
        if form.is_valid(): # All validation rules pass
            form.save()
        return redirect('article_index') # Redirect after POST
    else:
        form = ArticleForm(instance=article)

    return render(request, 'article_form.html', {'form': form})

然后網址很簡單:

url(r"^/article/edit/(?P<article_id>[0-9]+)$", "app.views.article_modify", name="edit"),
url(r"^/article/new$", "app.views.article_modify", name="new"),

我想通過重命名啟動category的模型categories奇異命名只是將是一個連續的頭痛- ,並相應地更新相關的代碼。

那時,你非常接近。 在提交文章時,在您的成功分支中,將類別指定為單獨的語句。

article = Article.objects.create(
    title=form.cleaned_data['title'],
    body=form.cleaned_data['body']
)
# note changed plural name on the m2m attr & form field
article.categories.add(*form.cleaned_data['categories'])
# alternately
# for cat in form.cleaned_data['categories']:
#     article.categories.add(cat)
return redirect('article_index') # Redirect after POST

哦,並且,贊賞避免使用ModelForm 自己連接表單實例管道更容易,這個問題在涉及ModelForm要復雜ModelForm

對於編輯視圖,是的,清除和重新添加是最簡單的。 有更有效的方法,但沒有什么是值得復雜的,直到它實際上是一個問題。 調用clear的方法將是article.categories.clear() ,重新添加與上面相同。

你可以這樣做,例如:

  if todo_list_form.is_valid():
                todo_list = todo_list_form.save(commit=False)
                todo_list.save()
                todo_list_form.save_m2m()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM