首页 文章

Django模型多态性和外键

提问于
浏览
0

我的应用程序中有3种不同的用户 .

  • 继续,查找约会和预约约会的客户 .

  • 可以为客户创建约会的个人注册并收取约会付款

  • 可以为客户创建约会以进行注册,收集约会付款以及提供组织中雇用的各个提供商的链接的组织(即上面第2组中的用户)

我看到类型1和类型2有一些重叠,因为它们都是个体,并且具有性别和出生日期等字段,而3则没有,而2和3有重叠,因为它们能够创建约会并收取付款 .

我已经构建了我的模型类:

class BaseProfileModel(models.Model):
    user = models.OneToOneField(User, related_name="profile", primary_key=True)
    phone = PhoneNumberField(verbose_name="Phone Number")
    pic = models.ImageField(upload_to=get_upload_file_name,
                            width_field="width_field",
                            height_field="height_field",
                            null=True,
                            blank=True,
                            verbose_name="Profile Picture"
                           )
    height_field = models.PositiveIntegerField(null=True, default=0)
    width_field = models.PositiveIntegerField(null=True, default=0)
    thumbnail = ImageSpecField(source='pic',
                                   processors=[ResizeToFill(180,180)],
                                   format='JPEG',
                                   options={'quality': 100})
    bio = models.TextField(
        verbose_name="About",
        default="",
        blank=True,
        max_length=800
    )
    is_provider=False

    class Meta:
        abstract = True

    def __str__(self):
        if self.user.email:
            return self.user.email
        else:
            return self.user.username

    @property
    def thumbnail_url(self):
        """
        Returns the URL of the image associated with this Object.
        If an image hasn't been uploaded yet, it returns a stock image

        :returns: str -- the image url

        """
        if self.pic and hasattr(self.pic, 'url'):
            return self.thumbnail.url
        else:
            # Return url for default thumbnail
            # Make it the size of a thumbnail
            return '/media/StockImage.png'

    @property 
    def image_url(self):
        if self.pic and hasattr(self.pic, 'url'):
            return self.pic.url
        else:
            # Return url for full sized stock image
            return '/media/StockImage.png'

    def get_absolute_url(self):
        return reverse_lazy(self.profile_url_name, kwargs={'pk': self.pk})

class BaseHumanUserModel(BaseProfileModel):
    birth_date = models.DateField(verbose_name="Date of Birth", null=True, blank=True)
    GENDER_CHOICES = (
        ('M', 'Male'),
        ('F', 'Female'),
        ('N', 'Not Specified'),
    )
    gender = models.CharField(
        max_length=1, choices=GENDER_CHOICES, blank=False, default='N', verbose_name='Gender')

    class Meta:
        abstract = True

class BaseProviderModel(models.Model):
    stripe_access_token = models.TextField(blank=True, default='')
    is_provider=True

    class Meta:
        abstract = True

    def rating(self):
        avg = self.reviews.aggregate(Avg('rating'))
        return avg['rating__avg']

    def rounded_rating(self):
        avg = self.rating()
        return round(avg * 2) / 2

    # More methods...


class IndividualProviderProfile(BaseProviderModel, BaseHumanUserModel):
    locations = models.ManyToManyField(Location, null=True, blank=True, related_name='providers')
    specialties = models.CharField(
        verbose_name = "Specialties",
        max_length=200,
        blank=True,
    )
    certifications = models.CharField(
        verbose_name = "Certifications", max_length=200,
        blank=True, null=True
    )
    self.profile_url_name = 'profiles:individual_provider_profile'

    def certifications_as_list(self):
        return ''.join(self.certifications.split()).split(',')

    def specialties_as_list(self):
        return ''.join(self.specialties.split()).split(',')


class CustomerProfile(BaseHumanUserModel):
    home_location = models.OneToOneField(
        Location,
        related_name='customer',
        null=True,
        blank=True,
        on_delete=models.SET_NULL
        )
    self.profile_url_name = 'profiles:customer_profile'

    # More methods...

class OrganizationProviderProfile(BaseProviderModel):
    website = models.URLField(blank=True)
    location = models.ForeignKey(Location)
    employees = models.ManyToManyField(IndividualProviderProfile)
    self.profile_url_name = 'profiles:organization_provider_profile'

    # More methods

我想知道一些事情:

模型与不同类别的分离是否有意义?或者更好地做一些事情,比如将提供者分成一个模型,个体与否,只是将某些字段留空并指定提供者类型的字段?这对我来说似乎很乱 .

但是,当涉及到ForeignKey关系时,我看到了我想要做的事情的问题 . 我希望用户能够在提供商上留下评论,这需要提供商的外键 . 如果它们是不同的模型类,那么一个ForeignKey不会削减它,除非我使用django contenttypes框架,我还没有真正考虑过 . GenericForeignKeys似乎是要走的路,除非这是使用GenericForeignKey的不好的做法,GenericForeignKey实际上只适用于两个类 . 所以我的问题是,对于曾经使用过contenttypes框架的人(或者有过类似困境的人),这是不好的做法,并且/或者我的代码最终会变得混乱,如果我设置这样的模型和使用通用外键为提供者分配关系?

EDIT

重新考虑,也许这将是一个更好的结构:让我知道你对上述的看法:

保留BaseProfileModel,BaseHumanUserModel和CustomerProfileModel与上面相同,并更改以下内容以获得OneToOne关系

class ProviderDetails(models.Model):
    stripe_access_token = models.TextField(blank=True, default='')

    def rating(self):
        avg = self.reviews.aggregate(Avg('rating'))
        return avg['rating__avg']

    def rounded_rating(self):
        avg = self.rating()
        return round(avg * 2) / 2

    # More methods...


class IndividualProviderProfile(BaseHumanUserModel):
    provider_details = models.OneToOneField(ProviderDetails, related_name='profile')
    locations = models.ManyToManyField(Location, null=True, blank=True, related_name='providers')
    specialties = models.CharField(
        verbose_name = "Specialties",
        max_length=200,
        blank=True,
    )
    certifications = models.CharField(
        verbose_name = "Certifications", max_length=200,
        blank=True, null=True
    )
    self.profile_url_name = 'profiles:individual_provider_profile'

    def certifications_as_list(self):
        return ''.join(self.certifications.split()).split(',')

    def specialties_as_list(self):
        return ''.join(self.specialties.split()).split(',')


class OrganizationProviderProfile(BaseProfileModel):
    provider_details = models.OneToOneField(ProviderDetails, related_name='profile')
    website = models.URLField(blank=True)
    location = models.ForeignKey(Location)
    employees = models.ManyToManyField(IndividualProviderProfile)
    self.profile_url_name = 'profiles:organization_provider_profile'

    # More methods

1 回答

  • 2

    我认为这非常复杂 . 您没有客户,用户和组织 . 您拥有 Users ,具有不同的权限或访问权限,属于不同的组织(或帐户) . 你'll probably also have at least one other type of user. Site administrators. Doesn' t表示他们应该是一个不同的阶级 . 你实现它是这样的:

    class User(models.Model):
        role = models.TextField()
    
        def is_administrator(self):
            return self.role == "admin"
    
        def can_create_appointment(self):
            return self.role == "publisher"
    

    这个角色也可能在组织上?这样一个帐户的所有成员都具有相同的权限 . 但是你可以看到它是如何工作的 .

    EDIT, to clarify my reasoning:

    当您有人登录时,Django将授予您访问用户的权限 . 您是否真的想要创建一种情况,您必须不断考虑您可以使用哪种类型的用户?或者您只是希望能够使用登录用户并根据一些简单的规则修改可访问的URL和可用的操作 . 后者则不那么复杂 .

相关问题