Django中如何将数据保存到两个相关的表中?

问题描述 投票:0回答:1

我是 Django 新手,我正在按照教程创建学校系统。我有一个

CustomUser
,通过
OneToOneField()
与三个不同的表相关,在注册用户时,根据类型(HOD、教师、学生),我使用
@receiver
创建两个信号来创建一个实例
POST
请求,然后将其保存在各自的表中。

问题:

  • 当我尝试保存数据时,我使用
    CustomUser
    对象并调用我保存在用户变量中的
    create_user()
    类,但是当我使用该对象保存我需要的表中的其他数据时(此中的教师)情况)用户未创建:
def create_teachers(request):
    if auth_user(request) == True:
        # Do something for authenticated users.
        if request.method == 'GET':
            return render(request, 'create_teachers.html')
        else:
            try:
                user = CustomUser.objects.create_user(
                    password='defaultPass',
                    first_name=request.POST.get('first_name'),
                    last_name=request.POST.get('last_name'),
                    email=request.POST.get('email'),
                    user_type=2,
                )
                user.Teachers.address=request.POST.get('address')
                user.save()
                print('Professor created successfully')
                return redirect('/auth/create_teachers')
            except:
                print('Error creating teacher')
                return redirect('/auth/create_teachers')
    else:
        return redirect('../login')
Error creating teacher
[27/Sep/2024 13:46:14] "POST /auth/create_teachers HTTP/1.1" 302 0
[27/Sep/2024 13:46:14] "GET /auth/create_teachers HTTP/1.1" 200 34724
[27/Sep/2024 13:46:14] "GET /static/css/dist/styles.css?v=1727459174 HTTP/1.1" 200 54543
# admin.py
class UserAdmin(BaseUserAdmin):
    ordering = ('email',)

admin.site.register(CustomUser, UserAdmin)
# managers.py
class CustomUserManager(BaseUserManager):
    """
    Custom user model manager where email is the unique identifiers
    for authentication instead of usernames.
    """
    def create_user(self, email, password, **extra_fields):
        """
        Create and save a user with the given email and password.
        """
        if not email:
            raise ValueError(_("The Email must be set"))
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, **extra_fields):
        """
        Create and save a SuperUser with the given email and password.
        """
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)
        extra_fields.setdefault("is_active", True)

        if extra_fields.get("is_staff") is not True:
            raise ValueError(_("Superuser must have is_staff=True."))
        if extra_fields.get("is_superuser") is not True:
            raise ValueError(_("Superuser must have is_superuser=True."))
        return self.create_user(email, password, **extra_fields)
# models.py
class CustomUser(AbstractUser):
    username = None
    email = models.EmailField(_("email address"), unique=True)
    user_type_data=((1,'HOD'),(2,'staff'),(3,'users'))
    user_type=models.CharField(default=1,choices=user_type_data,max_length=10)

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []

    objects = CustomUserManager()

    def __str__(self):
        return self.email

class AdminHOD(models.Model):
    id=models.AutoField(primary_key=True)
    admin=models.OneToOneField(CustomUser,on_delete=models.CASCADE)
    created_at=models.DateTimeField(auto_now_add=True)
    updated_at=models.DateTimeField(auto_now_add=True)
    objects=models.Manager()

class Teachers(models.Model):
    id=models.AutoField(primary_key=True)
    admin=models.OneToOneField(CustomUser,on_delete=models.CASCADE)
    phone=PhoneNumberField()
    address=models.TextField()
    course_id=models.ManyToManyField(Courses)
    subject_id=models.ManyToManyField(Subjects)
    section_id=models.ManyToManyField(Sections)
    created_at=models.DateTimeField(auto_now_add=True)
    updated_at=models.DateTimeField(auto_now_add=True)

class Students(models.Model):
    id=models.AutoField(primary_key=True)
    admin=models.OneToOneField(CustomUser,on_delete=models.CASCADE)
    idCard=models.PositiveIntegerField(unique=True)
    age=models.PositiveSmallIntegerField()
    gender=models.CharField(max_length=255,)
    phone=PhoneNumberField()
    address=models.TextField()
    profile_pic=models.FileField()
    session_start=models.DateField()
    session_end=models.DateField()
    course_id=models.ForeignKey(Courses,on_delete=models.SET_DEFAULT, default=1)
    sections_id=models.ForeignKey(Sections,on_delete=models.SET_DEFAULT, default=1)
    created_at=models.DateTimeField(auto_now_add=True)
    updated_at=models.DateTimeField(auto_now_add=True)

# Receive a signal to create a new user with certain type
@receiver(post_save,sender=CustomUser)
def create_user_profile(sender,instance,created,**kwargs):
    if created:
        if instance.user_type == 1:
            AdminHOD.objects.create(admin=instance)

        if instance.user_type == 2:
            Teachers.objects.create(admin=instance)
            
        if instance.user_type == 3:
            Students.objects.create(admin=instance)

# Save the user
@receiver(post_save,sender=CustomUser)
def save_user_profile(sender,instance,**kwargs):
    if instance.user_type == 1:
        instance.adminhod.save()

    if instance.user_type == 2:
        instance.teachers.save()

    if instance.user_type == 3:
        instance.students.save()

如果我注释掉行

user.Teachers.address=request.POST.get('address')
,则创建用户不会出现任何问题,并且创建
Teachers
表中的实例,且地址字段为空。

我需要的是了解错误发生的原因以及如何修复它。我曾考虑过为每个表创建一个自定义模型,而不是使用

CustomUser
并随后引用其他表,但我不知道该解决方案有多优化。也欢迎任何改进代码的建议。谢谢

编辑:回溯。

Traceback

python django django-models
1个回答
0
投票

对于我的回答,我将

Teachers
模型重命名为
Teacher
,因为在这种情况下使用复数表名称会变得非常混乱。

要访问相关模型字段,您需要使用该字段的

related_name
:

# the default related name for a `OneToOneField` is the lowercase name of the model

class Teacher(models.Model):
    id=models.AutoField(primary_key=True)
    admin=models.OneToOneField(
        CustomUser,
        on_delete=models.CASCADE,
        related_name='teacher'
    )
    ...

现在在您的视图中,您可以使用

Teacher
:
 创建相关的 
related_name

对象
user.teacher.address=request.POST.get('address')
© www.soinside.com 2019 - 2024. All rights reserved.