Django Models Polymorphism and Foreign Keys
我的应用程序中有3种不同的用户。
我看到类型1和类型2有一些重叠,因为它们都是个人,并且具有诸如性别和出生日期之类的字段,而类型2和类型3有重叠,因为它们能够创建约会和收取付款。
我的模型类结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | 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就不会剪切它,除非我使用django contenttypes框架,我还没有深入研究过这个框架。GenericForeignKeys似乎是一种可行的方法,除非这是一种糟糕的做法,即使用一个只适用于两个类的GenericForeignKey。所以我的问题是,对于以前使用过ContentTypes框架的人(或者有过类似困境的人),这是一个糟糕的实践,和/或如果我建立这样的模型并使用通用外键将关系分配给提供者,我的代码最终会变得混乱吗?
编辑
重新考虑后,也许这将是一个更好的结构:让我知道你对上述的看法:
保持baseProfileModel、baseHumanUserModel和customerProfileModel与上面相同,并将以下内容更改为具有一对一关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 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 3 4 5 6 7 8 | class User(models.Model): role = models.TextField() def is_administrator(self): return self.role =="admin" def can_create_appointment(self): return self.role =="publisher" |
也有可能是组织中的角色?这样一个帐户的所有成员都具有相同的权限。但你可以看到它是如何工作的。
编辑,澄清我的理由:
当您有人登录时,Django将为您提供访问用户的权限。你真的想创造一个你必须经常考虑你有哪些类型的用户的情况吗?或者,您只是希望能够使用登录的用户,并根据一些简单的规则修改可访问的URL和可用的操作。后者要复杂得多。