django中的独特约束

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

我在django有一个包含人员和角色的数据库。人与角色有一对多的关系。问题是角色没有唯一约束,例如人adam和david可以是角色中的艺术家,但django创建两个相同的艺术家条目,但我想要相同的条目,即adam和david应该指向一个条目。如果我为我的角色字段添加唯一性,那么django说它应该是一对一的。有任何想法吗?

model.py的一部分:

from django.db import models
from phonenumber_field.modelfields import PhoneNumberField

# Create your models here.
# possibillitas models here

class Person(models.Model):

    mail=models.EmailField(default='[email protected]')
    firstName=models.CharField(max_length=200,default='firstname')
    lastName=models.CharField(max_length=200,default='lastname')
    phoneNumber=PhoneNumberField()
    streetAdress=models.CharField(max_length=200,default='streetAdress')
    zipcode=models.CharField(max_length=200)
    city=models.CharField(max_length=200,default='Göteborg')
    country=models.CharField(max_length=200,default='Sweden')

    def __str__(self):
        return "%s %s" % (self.firstName,self.lastName)

    class Meta:
        ordering = ('firstName','lastName')

class Role(models.Model):

    role=models.CharField(max_length=200)
#    person=models.ManyToManyField(Person)
    person=models.ForeignKey(Person,on_delete=models.CASCADE)

    def __str__(self):
        return self.role

    class Meta:
        ordering = ('role',)

class Name(models.Model):

    name=models.CharField(max_length=200)
    role=models.ForeignKey(Role,on_delete=models.CASCADE)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ('name',)

修改了admin.py以获得以下答案:

from django.contrib import admin
from .models import Role,Alias,Address,Date,Person,Name

from django.conf.urls import url, include

# Register your models here.

admin.site.register(Role)
admin.site.register(Address)
admin.site.register(Date)
admin.site.register(Name)
admin.site.register(Alias)
admin.site.register(Person)

class AliasInline(admin.TabularInline):

#    model=Role.person.through
    model=Alias
    extra=2

class RoleInline(admin.TabularInline):

#    model=Role.person.through
    model=Role
    extra=2

class NameInline(admin.TabularInline): # nested inlines doesn't work

#class NameInline(admin.ModelAdmin): # nested inlines doesn't work

    model=Name
    extra=3

class PersonInline(admin.ModelAdmin):

    fieldsets=[
        (None,{'fields': ['mail','firstName','lastName','phoneNumber','streetAdress','zipcode','city','country']}),
    ]
    inlines = [RoleInline]
    search_fields = ['firstName']
django database one-to-many
1个回答
1
投票

简而言之:我认为uniqness约束应该放在role模型的Role属性上,以防止创建具有相同Role属性的多个roles。

Modeling this as a many-to-many relation

在我看来,你想在这里使用多对多关系,因为这意味着Person可以有许多Roles,而Role可以与许多Persons相关联。

你可能应该使role字段(虽然这里name可能更好)是唯一的,这样就不能创建两个具有相同名称的角色:

class Role(models.Model):
    role = models.CharField(max_length=200, unique=True)
    persons = models.ManyToManyField(Person, related_name='roles')

    def __str__(self):
        return self.role

    class Meta:
        ordering = ('role',)

我们可以创建两个艺术家的Persons:

role_artist, __ = Role.objects.get_or_create(role='artist')

adam = Person.objects.create(firstName='Adam')
david = Person.objects.create(firstName='David')

adam.roles.add(role_artist)
david.roles.add(role_artist)

Name as a through model

您定义的Name模型似乎可以作为Through模型使用:它为关系添加了额外的数据。例如,一个人可能有两个Names:一个作为歌手,一个作为电影明星。这通常是through model [Django-doc]的用例,其中可以编码关系中的额外数据,尽管将这个Alias(或至少更具描述性的名称)命名可能更好。

我们可以将其重塑为:

class Role(models.Model):
    role = models.CharField(max_length=200, unique=True)
    persons = models.ManyToManyField(Person, through='Alias', related_name='roles')

    def __str__(self):
        return self.role

    class Meta:
        ordering = ('role',)

class Alias(models.Model):

    name = models.CharField(max_length=200)
    role = models.ForeignKey(Role, on_delete=models.CASCADE)
    person = models.ForeignKey(Person, on_delete=models.CASCADE)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ('name',)

然后我们可以制作两个艺术家的Persons adamdavid,每个都有他们的艺术家名字:

role_artist, __ = Role.objects.get_or_create(role='artist')

adam = Person.objects.create(firstName='Adam')
david = Person.objects.create(firstName='David')

Alias.objects.create(name='Adam the magician', role=role_artist, person=adam)
Alias.objects.create(name='David the lion tamer', role=role_artist, person=david)

对于同样的角色,Person甚至有可能有多个Aliasses。

Concluding remarks

注意:根据PEP 8,命名约定是属性为小写,单词用下划线分隔。所以这意味着它应该是first_name而不是firstName

© www.soinside.com 2019 - 2024. All rights reserved.