5

モデル:

class ProjectType(models.Model):
    project_type_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=45, help_text='Type of project', verbose_name='Project Type')
    slug = models.SlugField(max_length=45, blank=True)
    description = models.CharField(max_length=400, help_text='Description of the main  purpose of the project', verbose_name='Project Type Description')
    default = models.BooleanField(default=False)
    owner = models.ForeignKey(User)
class Meta:
    ...
    unique_together = (('slug', 'owner'),('name', 'owner'))

ProjectType を作成/更新するためのフォームが必要です。所有者フィールドに注意してください- 現在ログインしているユーザーであるはずです。問題は、unique_togetherの制約が正しく検証されるようにする方法です。

フォームに所有者フィールドを表示したくありません。これは現在のユーザーであるため、システムによって自動的に設定される必要があります。しかし、これをどのように実行しようとしても、検証が機能しないか、他のエラーが発生します。

私が試したアプローチの中で(個別または組み合わせて):

  • 関連する ModelField に隠しフィールドを作成する
  • ProjectTypeForm でinitを (さまざまな方法で)定義します。たとえば、次のようになります。

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(ProjectTypeForm, self).__init__(*args, **kwargs)
        self.fields['owner'].initial = self.user
    
  • 次のようなビューで値を設定します。

    ...
    if request.method == 'POST':
        project_type = ProjectType(owner=request.user)
        form = ProjectTypeForm(request.POST, instance=project_type, user = request.user.pk) # also tries w/o pk
    ...
    
  • 次の行に沿って、さまざまな方法でフォームの clean() メソッドをオーバーライドします。

    def clean(self):
        cleaned_data = super(ProjectTypeForm, self).clean()
        slug=cleaned_data.get('slug')
        owner = cleaned_data.get('owner')
    
        if slug:
            user = User.objects.get(pk=owner)
            ...
    

これらのアプローチの多くは、stackoverflow.com にあるさまざまな回答に基づいています。ただし、何を試しても、必要なことを達成する方法が見つかりません。(1) 所有者フィールドの自動設定と (2) 一意性の検証: owner/type_name と owner/type_slug。私が持っている典型的なエラーは、(a)所有者がユーザーとして認識されない (PK として扱われる)、(b) 検証が正しくない (検証がない、または編集中の同じレコードであるという事実を見逃しているなど) です。 、(c) 所有者は必須フィールドです。

レコードについて -所有者がフォームの通常のフィールドである場合、すべてが期待どおりに機能しますが、ユーザーが所有者の値を設定できるようにすることはできません。

これに対するエレガントな解決策はありますか?

ありがとう!

4

2 に答える 2

5

フォームから所有者フィールドを除外し、フォームの init メソッドでユーザーを保存します。これを使用してフォームを検証できます。

class ProjectTypeForm(...):
    ...
    def __init__(self, user, *args, **kwargs):
        super(ProjectTypeForm, self).__init__(*args, **kwargs)
        self.user = user

    def clean(self):
        user_projects = ProjectType.objects.filter(owner=self.user)
        if user_projects.filter(slug=self.cleaned_data['slug']):
            raise forms.ValidationError('...')
        elif user_projects.filter(name=self.cleaned_data['name']):
            raise forms.ValidationError('...')
        else:
            return self.cleaned_data

次に、ビューで、新しい ProjectType を作成するときに次のようにします。

if request.method == 'POST':
    form = ProjectTypeForm(request.user, request.POST)
    if form.is_valid():
        ptype = form.save(commit=False)
        ptype.owner = request.user
        ptype.save()

ただし、既存の ProjectType オブジェクトを保存する必要はありません。

于 2012-05-02T23:37:17.103 に答える
0

コメントで述べたように、考えられる解決策の 1 つは、基本的に Django フォームに沿って、フォームで所有者フィールドを使用することです。したがって、私が行ったことは、次のようにinitを変更したことです。

def __init__(self, user, *args, **kwargs):
    super(ProjectTypeForm, self).__init__(*args, **kwargs)
    self.fields['owner'] = forms.ModelChoiceField(
        label='Owner*',
        queryset=User.objects.filter(username=user.username),
        help_text="Project types are unique to logged-in users who are set as their owners.",
        required=True,
        empty_label=None)

基本的に、それはまだ ChoiceField を使用していますが、それを 1 つのオプション (現在のユーザー) に設定しています。さらに、empty_label=None は、「空の」選択肢がないことを保証します。その結果、(ユーザー名は一意であるため) 現在のユーザー名が表示され、それ以外の場合はドロップダウン リストでより多くの選択肢がある唯一の選択肢になります。

ビューでは、次のアプローチに従います。

...
if request.method == 'POST':
    project_type = ProjectType()
    form = ProjectTypeForm(request.user,request.POST, instance=project_type,)
    if form.is_valid():
        project_type.save()

        return HttpResponseRedirect(reverse('project_types'))
else:
    form = ProjectTypeForm(request.user)
...

基本的にはそれだけです - 一意の制約 (および全体) の検証は魅力のように機能します。

私はこの解決策が好きですか?いいえ、私はそれをハックだと考えています (皮肉なことに、標準の Django アプローチに沿っていたとしても)。しかし、それにはまったく不要なものが必要です。このアプローチの利点の 1 つは、プロジェクト タイプの所有者として設定されていることを現在のユーザーに明確に伝えることです。しかし、これを念頭に置いても、現在のユーザー X が作成中のプロジェクト タイプの所有者として設定されるというメッセージを (フィールドではなく) 表示したいと思います。したがって、誰かがより良い解決策を持っている場合は、それを提出して、Django の完全な機能と柔軟性を説明してください。

于 2012-05-03T15:37:45.263 に答える