【发布时间】:2014-11-15 23:59:03
【问题描述】:
我的应用程序中有 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 是不好的做法。 所以我的问题是,对于以前使用过 contenttypes 框架的人(或遇到过类似困境的人),这是不好的做法,和/或我的代码最终会变得混乱,如果我这样设置我的模型并且使用通用外键将关系分配给提供者?
编辑
重新考虑后,也许这会是一个更好的结构:让我知道您对上述内容的看法:
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
【问题讨论】:
标签: python django django-models django-contenttypes