2009-09-27 16 views
18

私はStudentと呼ばれるいくつかのフィールドを持つモデルと、ユーザーとのOneToOne関係(django.contrib.auth.User)を持っています。djangoモデルフォーム。関連するモデルのフィールドを含める

class Student(models.Model): 

    phone = models.CharField(max_length = 25) 
    birthdate = models.DateField(null=True) 
    gender = models.CharField(max_length=1,choices = GENDER_CHOICES) 
    city = models.CharField(max_length = 50) 
    personalInfo = models.TextField() 
    user = models.OneToOneField(User,unique=True) 

その後、私はそのモデルのフィールドがクラスメタ属性で使用

class StudentForm (forms.ModelForm): 
    class Meta: 
     model = Student 

のためのModelFormを持って、私はテンプレートで唯一のいくつかのフィールドを表示することができました。ただし、表示するユーザーフィールドを指定することはできますか?

何かのように:

fields =('personalInfo','user.username') 

現在は何も表示されていません。ただし、StudentFieldsのみで動作します/

ありがとうございます。

+0

を学生モデルが一つだけのModelFormを必要とするユーザー・モデルを継承している場合。 –

+0

@KevinL。答えでこれを詳述するといいでしょう:-) – cel

+0

@cel AFAIK、Djangoのコアでこれについて述べるような開発はありませんでした。ここの「自動」解決策は、自明なものではなく、独自のカスタムモデルフォームクラスまたはミックスインを作成することになります。これは、提案された方法を使用するよりもはるかに複雑です(そしておそらくは壊れやすくなります)。 1つの可能な解決策が、[この回答](https://stackoverflow.com/a/41559015/5747944)に含まれています。これは、2番目の「子」モデルを定義することができ、ジェネリックビューと互換性があると主張されているModelFormミックスインを記述します。 – sytech

答えて

7

を見てみることができます:インラインフォームセットは、この簡単にやって作ります。

ただし、インラインは、外部キーを持つモデルから一方向にしか移動できないことに注意してください。両方に主キーを持たずに(悪い場合はA→B、B→A2)、related_toモデルでインラインformsetを使用することはできません。

たとえば、UserProfileクラスがあり、これを表示できるようにするには、関連するUserオブジェクトがインラインで表示されるようにしたい場合は、不運になります。

ModelFormでカスタムフィールドを使用し、これをより柔軟な方法で使用できますが、標準のModelForm /インラインフォームセットのように '自動'ではなくなったことに注意してください。

+0

私はこの質問とあなたの答えに記述されている問題を正確に打っています。今、何年も経ちました。今すぐ自動解決策があるかどうか知っていますか? – cel

4

一般的な方法は、目標を達成するために2つのフォームを使用することです。

  • Userモデルの形式:

    class UserForm(forms.ModelForm): 
        ... Do stuff if necessary ... 
        class Meta: 
         model = User 
         fields = ('the_fields', 'you_want') 
    
  • フォームStudentモデル用:

    class StudentForm (forms.ModelForm): 
        ... Do other stuff if necessary ... 
        class Meta: 
         model = Student 
         fields = ('the_fields', 'you_want') 
    
  • はあなたのビュー(使用例)で、これらの形態の両方を使用します。

    def register(request): 
        if request.method == 'POST': 
         user_form = UserForm(request.POST) 
         student_form = StudentForm(request.POST) 
         if user_form.is_valid() and student_form.is_valid(): 
          user_form.save() 
          student_form.save() 
    
  • が一緒にあなたのテンプレートでフォームをレンダリングします

    <form action="." method="post"> 
        {% csrf_token %} 
        {{ user_form.as_p }} 
        {{ student_form.as_p }} 
        <input type="submit" value="Submit"> 
    </form> 
    

あなたは、これは完全にあなた次第(ForeignKeyからOneToOneから関係を変更するために、私はちょうどそれを言及するために別のオプションは次のようになり、推奨しません)、希望の結果を得るにはinline_formsetsを使用してください。

+1

@cel "自動"な方法についてはわかりませんが(私が書いたように)、この回答には手作業による解決策があります。見てください:) –

2

代替方法として、one-to-one linkをProfileモデル(この場合はStudentモデル)を使用するのではなく、AbstractUserまたはAbstractBaseUserモデルを拡張してカスタムユーザーモデルを作成する方法があります。これにより、単一のModelFormを作成するために使用できる単一の拡張Userモデルが作成されます。あなたの管理者でモデル、settings.pyファイルで

from django.contrib.auth.models import AbstractUser 

class Student(AbstractUser): 

    phone = models.CharField(max_length = 25) 
    birthdate = models.DateField(null=True) 
    gender = models.CharField(max_length=1,choices = GENDER_CHOICES) 
    city = models.CharField(max_length = 50) 
    personalInfo = models.TextField() 
    # user = models.OneToOneField(User,unique=True) <= no longer required 

AUTH_USER_MODEL

AUTH_USER_MODEL = 'appname.models.Student' 

更新を更新:

例えばこれを行うための一つの方法は、AbstractUser modelを延長するだろう

from django.contrib import admin 
from django.contrib.auth.admin import UserAdmin 
from .models import Student 

admin.site.register(Student, UserAdmin) 

次に、両方の追加フィールドyoを持つ単一のModelFormを使用できます元のユーザーモデルのフィールドと同様に必要です。 forms.py

from .models import Student  

class StudentForm (forms.ModelForm): 
    class Meta: 
     model = Student 
     fields = ['personalInfo', 'username'] 

にAbstractBaseUserを拡張することで、より複雑な方法は、これを詳細in the docsに記載されています。

しかし、便利な単一のModelFormを使用するために、カスタムユーザーモデルをこのように作成するかどうかは、あなたのユースケースには意味がありません。これは、カスタムのユーザーモデルを作成することが難しい場合があるため、設計上の決定事項です。

1

あなたは多くの副作用を持っていAUTH_USER_MODELを変更したくない場合は、Multi-table inheritanceを使用して、代わりにAbstractUserユーザーモデルをサブクラス化することができます。これは、ユーザーテーブルを指すOneToOneFieldという名前user_ptr学生テーブルを作成します。ここで

は今、あなたはあなたがまた、この

from django.contrib.auth.forms import UserChangeForm 

class StudentForm(UserChangeForm): 
    class Meta: 
     model = Student 
     fields = ('first_name', 'last_name', 'username', 
       'personalInfo', 'phone', 'birthdate', 'city') 

のようなDjangoのユーザフォームで構築拡張することができ

このような
class StudentForm(forms.ModelForm): 
    class Meta: 
     model = Student 
     fields = ('first_name', 'last_name', 'username', 
        'personalInfo', 'phone', 'birthdate', 'city') 

あなたのModelFormを定義することができます例

from django.contrib.auth.models import User 
from django.db import models 
from django.utils.translation import gettext_lazy as _ 


class Student(User): 
    phone = models.CharField(max_length=25) 
    birthdate = models.DateField(null=True) 
    city = models.CharField(max_length=50) 
    personalInfo = models.TextField() 

    class Meta: 
     verbose_name = _('student') 
     verbose_name_plural = _('students') 

ですdjango adminでフォームを使用するには、tを追加します彼はadmin.pyに次

from django.contrib import admin 
from .views import StudentForm 
from .models import Student 


class StudentAdmin(admin.ModelAdmin): 
    form = StudentForm 

admin.site.register(Student, StudentAdmin) 

自動的に他の方法で回避新しいユーザーインスタンスを作成しませんが学生インスタンスを作成し、ユーザーモデルをクラス分けサブことで。したがって、ユーザーインスタンスは、生徒のインスタンスに関連付けられていなくても存在できます。あなたがあるauth.Userのユーザ名フィールドを更新したい私の理解から

from django.contrib.auth.models import User 
from django.db.models.signals import post_save 
from django.dispatch import receiver 

from .models import Student 


@receiver(post_save, sender=User) 
def create_student(sender, instance, created, **kwargs): 
    if created: 
     student = Student(user_ptr_id=instance.pk) 
     student.__dict__.update(instance.__dict__) 
     student.save() 
1

:あなたが学生のインスタンスは、システム内のすべてのユーザーのために作成されていることを確認したい場合は、以下の信号を使用することができますStudentOneToOne関係、これは私が何をするのかである...

class StudentForm (forms.ModelForm): 

username = forms.Charfield(label=_('Username')) 
class Meta: 
    model = Student 
    fields = ('personalInfo',) 

def clean_username(self): 
    # using clean method change the value 
    # you can put your logic here to update auth.User 
    username = self.cleaned_data('username') 
    # get AUTH USER MODEL 
    in_db = get_user_model()._default_manager.update_or_create(username=username) 

希望このことができます:)

関連する問題