Как присвоить атрибуту несколько строковых значений в моделях Django

class Customer(models.Model):
    user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE,
                                related_name="Customer", limit_choices_to={'is_staff': False})
    employee = models.ForeignKey(
        Employee, null=True, blank=True, on_delete=models.SET_NULL)
    # locations =  What should go here?
    business_name = models.CharField(max_length=200, null=True, blank=True)
    phone_no = models.CharField(max_length=200, null=True, blank=True)
    address = models.CharField(max_length=500, null=True, blank=True)
    website_url = models.URLField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

Как вы можете видеть здесь, у меня есть поле locations. Это поле должно хранить не более 5 мест, в которых расположен бизнес. Как мне лучше всего этого добиться?

Я читал об использовании поля Many2Many, но это нежелательно, поскольку местоположения должны быть сначала созданы в администраторе, а затем добавлены в бизнес.

Я не понимаю, почему местоположения должны быть сначала добавлены в панели администратора. ManyToManyField действительно является подходящим способом.

class Location(models.Model):
    location = models.CharField(max_length=200)

class Customer(models.Model):
    user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE,
                                related_name="Customer", limit_choices_to={'is_staff': False})
    employee = models.ForeignKey(
        Employee, null=True, blank=True, on_delete=models.SET_NULL)
    locations =  models.ManyToManyField(Location)
    business_name = models.CharField(max_length=200, null=True, blank=True)
    phone_no = models.CharField(max_length=200, null=True, blank=True)
    address = models.CharField(max_length=500, null=True, blank=True)
    website_url = models.URLField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

Затем вы можете добавить местоположения к клиенту в вашем представлении:

def home(request):
    # First create the customer
    customer = Customer.objects.create_user(user=request.user)
    
    # Then get the locations
    # I'm assuming you'll get this from a form post request
    locations = request.POST.getlist('locations')

    for location in locations:
        Location.objects.create(location=location)
        customer.add(location)

Посмотрите docs для получения дополнительной информации.

Если вы не хотите ManyToManyField, вы можете наложить синтаксис на то, что является допустимым местоположением, и хранить местоположения в одном поле CharField с некоторым символом-разделителем. Вы можете использовать validators, чтобы убедиться, что все остается в порядке. Если вы используете PostgreSQL в качестве БД, вы можете сделать местоположение в JSONField или ArrayField, но если вы не можете сделать это, не так уж сложно использовать простое CharField

MAX_LOCATIONS = 5
LOCATIONS_SEPARATOR = '||'
MAX_LOCATION_LENGTH = 200

locations = models.CharField( max_length= MAX_LOCATIONS*(MAX_LOCATION_LENGTH + len(LOCATIONS_SEPARATOR) ), 
   validators = [LocationsValidator, ],
   ...
)
...

def LocationsValidator( value):
if len( value.split( LOCATION_SEPARATOR )) > MAX_LOCATIONS
    raise ValidationError(
        f'Location value represents more than maximum {MAX_LOCATIONS} locations'
    )

Используйте методы Python string .split и .join для преобразования из одной строки расположения и списка до 5 значений расположения. Не забывайте проверять значения местоположения в формах

valid = ( len( location) <= Customer.MAX_LOCATION_LENGTH and 
    Customer.LOCATIONS_SEPARATOR not in location )

ManyToMany принесет дивиденды, если вы когда-нибудь захотите начать связывать другие данные со значениями местоположения. Поэтому лично я бы не рекомендовал использовать вышеописанное в любых обычных обстоятельствах.

Вернуться на верх