0

フォームセットを使用して画像をアップロードし、多対多の関係を使用してモデルにリンクしています。ステータス フォームの下にフォームセットを表示して、ユーザーがステータス フィールドに入力し、画像を追加してから、[保存] または [別の画像を保存して追加] をクリックします。

最後のケースでは、事前に入力されたステータス フォームを表示し、フォームセット内に、アップロードされたファイルを処理するための通常のものを含むブロック (画像へのリンク、削除するチェックボックス、別の画像をアップロードするためのファイル入力) を表示する必要があります。最後に、2 番目の画像をアップロードするための空のファイルを入力します。現在、2 つの空のファイルを入力しています。

フォームセットは、既に 1 つの画像がアップロードされていることを認識していますが、それを管理するために何も表示しません。これはフォームセットの ImageField の通常の動作ですか、それともフォームセット データを提供する方法に問題がありますか?

コードは次のとおりです。

# Models
class Image(models.Model):
    image = ImageField(upload_to='uploads/status/images/',)


class Status(models.Model):
    author = models.ForeignKey(User,)
    images = models.ManyToManyField(Image, blank=True, null=True)
    body = models.TextField()

# Forms
class StatusForm(forms.ModelForm):
    class Meta:
        model = Status
        fields = ['body',]


class ImageForm(forms.ModelForm):
    class Meta:
        model = Image
        fields = ['image',]

# View
@csrf_protect
def form(request, id=None, template_name='status/form.html'):
    if id:
        status = get_object_or_404(Status, pk=id)
        images = status.images.all().values()
    else:
        status = Status(author=request.user)
        images = None

    if request.method == 'POST':
        form = StatusForm(request.POST, instance=status)
        formset = ImageFormSet(request.POST, request.FILES, initial=images)

        if form.is_valid():
            try:
                status = form.save()

                if formset.is_valid():
                    try:
                        for form in formset:
                            image = form.save()
                            status.images.add(image)
                            status.save()

                        if request.POST.get('_add_image', None):
                            return HttpResponseRedirect(reverse('status_edit', args=[status.id]))
                        else:
                            messages.success(request, 'Status saved')
                            return HttpResponseRedirect(request.POST.get('next', '/'))
                    except:
                        messages.error(request, 'Technical error')
            except:
                messages.error(request, 'Technical error')
    else:
        form = StatusForm(instance=status)
        formset = ImageFormSet(initial=images)

    return render_to_response(template_name, {
        'form': form,
        'formset': formset,
        'next': request.GET.get('next', '/'),
    }, context_instance=RequestContext(request))

テンプレート:

<form action="" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.non_field_errors }}
    <input type="hidden" name="next" value="{{ next }}" />
    {{ form.body }}
    {{ form.body.errors }}
    <hr />
    {{ formset }}
    <hr />
    <div class="pull-right">
        <input name="_add_image" class="btn" type="submit" value="Add another image">
        <input name="_complete" class="btn btn-primary" type="submit" value="Save">
    </div>
</form>
4

1 に答える 1

0

M2M 関係では「正常」です。インライン フォームセットは現在設計されているため、編集中のメイン オブジェクトに戻る外部キーが必要です。存在する唯一の場所は、M2M 関係の結合テーブル (Django 用語では「スルー」モデル) です。そのモデル自体は通常、関係の両側に 1 つずつ、2 つの外部キーで構成されています。

編集したいモデルのすべてのフィールドと、既存のフィールドを選択するための通常の選択フィールドを含むカスタムフォームを作成し、フォームのフィールドから新しいインスタンスを作成するロジックを作成するというアイデアをいじりましたそれを唯一の実フィールドである外部キーに割り当てます。ただし、記述するコードは多く、そのほとんどは使用シナリオごとに固有であり、脆いものです (フォームとモデルを常に同期させるように注意する必要があります)。結局その考えは捨てました。いつの日か、Django が何らかのメカニズムを提供する日が来るかもしれませんが、今のところは対処するのが最善です。

于 2012-05-24T16:02:04.297 に答える