31π
A common practice is to use 2 forms to achieve your goal.
-
A form for the
User
Model:class UserForm(forms.ModelForm): ... Do stuff if necessary ... class Meta: model = User fields = ('the_fields', 'you_want')
-
A form for the
Student
Model:class StudentForm (forms.ModelForm): ... Do other stuff if necessary ... class Meta: model = Student fields = ('the_fields', 'you_want')
-
Use both those forms in your view (example of usage):
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()
-
Render the forms together in your template:
<form action="." method="post"> {% csrf_token %} {{ user_form.as_p }} {{ student_form.as_p }} <input type="submit" value="Submit"> </form>
Another option would be for you to change the relationship from OneToOne
to ForeignKey
(this completely depends on you and I just mention it, not recommend it) and use the inline_formsets
to achieve the desired outcome.
8π
Both answers are correct: Inline Formsets make doing this easy.
Be aware, however, that the inline can only go one way: from the model that has the foreign key in it. Without having primary keys in both (bad, since you could then have A -> B and then B -> A2), you cannot have the inline formset in the related_to model.
For instance, if you have a UserProfile class, and want to be able to have these, when shown, have the User object that is related shown as in inline, you will be out of luck.
You can have custom fields on a ModelForm, and use this as a more flexible way, but be aware that it is no longer βautomaticβ like a standard ModelForm/inline formset.
- [Django]-Change model class name in Django admin interface
- [Django]-Django Rest Framework with ChoiceField
- [Django]-How to copy modules from one virtualenv to another
4π
An alternative method that you could consider is to create a custom user model by extending the AbstractUser or AbstractBaseUser models rather than using a one-to-one link with a Profile model (in this case the Student model). This would create a single extended User model that you can use to create a single ModelForm.
For instance one way to do this would be to extend the AbstractUser model:
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
In settings.py file, update the AUTH_USER_MODEL
AUTH_USER_MODEL = 'appname.models.Student'
update the model in your Admin:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Student
admin.site.register(Student, UserAdmin)
Then you can use a single ModelForm that has both the additional fields you require as well as the fields in the original User model. In forms.py
from .models import Student
class StudentForm (forms.ModelForm):
class Meta:
model = Student
fields = ['personalInfo', 'username']
A more complicated way would be to extend the AbstractBaseUser, this is described in detail in the docs.
However, Iβm not sure whether creating a custom user model this way in order to have a convenient single ModelForm makes sense for your use case. This is a design decision you have to make since creating custom User models can be a tricky exercise.
- [Django]-Cannot resolve 'django.utils.log.NullHandler' in Django 1.9+
- [Django]-Django: Admin: changing the widget of the field in Admin
- [Django]-Django rest framework: query parameters in detail_route
1π
From my understanding you want to update the username field of auth.User which is OneToOne
relation with Student
, this is what I would doβ¦
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)
hope this helps π
- [Django]-How to store empty value as an Integerfield
- [Django]-Programmatically using Django's loaddata
- [Django]-Django: best practice for splitting up project into apps