python - many - Forma del modelo django. Incluir campos de modelos relacionados
many to many django (5)
A mi entender, usted desea actualizar el campo de nombre de usuario de auth.User, que es OneToOne
relación de OneToOne
con Student
, esto es lo que haría ...
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)
espero que esto ayude :)
Tengo un modelo, llamado Estudiante, que tiene algunos campos, y una relación OneToOne con un usuario (django.contrib.auth.User).
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)
Entonces, tengo un ModelForm para ese modelo
class StudentForm (forms.ModelForm):
class Meta:
model = Student
Usando el atributo de campos en la clase Meta, logré mostrar solo algunos campos en una plantilla. Sin embargo, ¿puedo indicar qué campos de usuario mostrar?
Algo como:
fields =(''personalInfo'',''user.username'')
Actualmente no está mostrando nada. Funciona solo con StudentFields aunque
Gracias por adelantado.
Ambas respuestas son correctas: los formularios en línea hacen que esto sea fácil.
Sin embargo, tenga en cuenta que la línea solo puede ir en una dirección: desde el modelo que tiene la clave externa. Sin tener claves primarias en ambas (mala, ya que podría tener A -> B y luego B -> A2), no puede tener el formato en línea en el modelo related_to.
Por ejemplo, si tiene una clase de perfil de usuario y desea poder tener estos, cuando se muestre, el objeto de usuario relacionado se muestre como en línea, no tendrá suerte.
Puede tener campos personalizados en un ModelForm, y usar esto como una forma más flexible, pero tenga en cuenta que ya no es "automático" como un ModelForm estándar / en línea.
Si no desea cambiar el AUTH_USER_MODEL que tiene muchos efectos secundarios, puede usar la herencia de tablas múltiples y subclase del modelo de usuario en lugar de AbstractUser . Esto creará una tabla de Estudiante con un OneToOneField llamado user_ptr que apunta a la tabla de Usuario .
Aquí un ejemplo
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'')
Ahora puedes definir tu ModelForm así
class StudentForm(forms.ModelForm):
class Meta:
model = Student
fields = (''first_name'', ''last_name'', ''username'',
''personalInfo'', ''phone'', ''birthdate'', ''city'')
También puede ampliar los formularios de usuario de django incorporados como este
from django.contrib.auth.forms import UserChangeForm
class StudentForm(UserChangeForm):
class Meta:
model = Student
fields = (''first_name'', ''last_name'', ''username'',
''personalInfo'', ''phone'', ''birthdate'', ''city'')
Para usar su formulario en el administrador de django, agregue lo siguiente a 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)
Al subclasificar el modelo de Usuario , la creación de una instancia de Estudiante creará automáticamente una nueva instancia de usuario pero no al revés. Por lo tanto, una instancia de usuario puede existir sin estar asociada con una instancia de estudiante . Si desea asegurarse de que se crea una instancia de Estudiante para cada Usuario en el sistema, puede usar la siguiente señal:
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()
Un método alternativo que podría considerar es crear un modelo de usuario personalizado extendiendo los modelos AbstractUser o AbstractBaseUser en lugar de usar un enlace uno a uno con un modelo de perfil (en este caso, el modelo de Estudiante). Esto crearía un único modelo de usuario extendido que puede usar para crear un único ModelForm.
Por ejemplo, una forma de hacerlo sería extender el modelo AbstractUser :
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
En el archivo settings.py, actualice AUTH_USER_MODEL
AUTH_USER_MODEL = ''appname.models.Student''
actualiza el modelo en tu administrador:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Student
admin.site.register(Student, UserAdmin)
Luego, puede usar un único ModelForm que tenga tanto los campos adicionales que necesita como los campos en el modelo de usuario original. En forms.py
from .models import Student
class StudentForm (forms.ModelForm):
class Meta:
model = Student
fields = [''personalInfo'', ''username'']
Una forma más complicada sería extender el AbstractBaseUser, esto se describe detalladamente en los documentos .
Sin embargo, no estoy seguro de que crear un modelo de usuario personalizado de esta manera para tener un ModelForm único y conveniente tenga sentido para su caso de uso. Esta es una decisión de diseño que debe tomar ya que crear modelos de usuario personalizados puede ser un ejercicio difícil.
Una práctica común es utilizar 2 formas para lograr su objetivo.
Un formulario para el Modelo de
User
:class UserForm(forms.ModelForm): ... Do stuff if necessary ... class Meta: model = User fields = (''the_fields'', ''you_want'')
Un formulario para el modelo de
Student
:class StudentForm (forms.ModelForm): ... Do other stuff if necessary ... class Meta: model = Student fields = (''the_fields'', ''you_want'')
Use ambos formularios en su vista (ejemplo de uso):
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()
Renderiza los formularios juntos en tu plantilla:
<form action="." method="post"> {% csrf_token %} {{ user_form.as_p }} {{ student_form.as_p }} <input type="submit" value="Submit"> </form>
Otra opción sería que cambie la relación de OneToOne
a ForeignKey
(esto depende completamente de usted y solo lo menciono, no lo recomiendo) y use inline_formsets
para lograr el resultado deseado.