Django: Избегайте гоночных условий, дублирующих объекты в сложных отношениях
У меня есть две модели, Company и Customer, которые связаны через промежуточную таблицу Contact. Никогда не должно быть более одного объекта Contact, который связывает объект Company с объектом Customer. Сложность заключается в том, что отношение "Компания - Клиент" не является обычным ManyToMany. Компания и Contact связаны с помощью ForeignKey, но Customer и Contact связаны через ManyToMany. Вот упрощенные модели
class Company(Model):
# Unrelated fields
class Customer(Model):
# Unrelated fields
class Contact(Model):
company = ForeignKey(Company, related_name="contact")
customer = ManyToMany(Customer, related_name="contact")
# Unrelated fields
Когда поступают данные о клиенте, связанном с компанией, я создаю клиента или нахожу существующего клиента с соответствующими данными. Затем я создаю контакт, чтобы связать клиента с компанией. Вот код, который я использую для проверки того, существует ли уже контакт, связывающий компанию и клиента:
try:
contact = customer.contact.get(company=company)
except Contact.DoesNotExist:
contact = customer.contact.create(company=company)
Но это позволяет иногда создавать дубликаты контактов из-за условий гонки. Использование встроенной в Django функции get_or_create здесь не работает из-за M2M отношений между Клиентом и Контактом. Как я могу обеспечить, чтобы Контакты были уникальными связями между компаниями и клиентами, избегая при этом условий гонки?
--В случае, если вам интересно, зачем мне нужна эта конфигурация--
Клиенты могут взаимодействовать с несколькими компаниями, и все действия, которые они совершают с компанией (связываются, покупают и т.д.), хранятся в базе данных. Модель Contact является промежуточным звеном между компанией и клиентом, позволяя изменять его данные (например, контактную информацию) на объекте Contact без влияния на данные других компаний об этом клиенте. Причина, по которой Customer и Contact связаны M2M, заключается в том, что источник данных о взаимодействии является сторонним и не всегда содержит достаточно информации, чтобы связать взаимодействие с Клиентом. Например, клиент Джон звонит в компанию (мы получаем номер телефона), а затем совершает покупку (мы получаем адрес электронной почты). Два разных объекта Customer будут созданы из-за недостатка данных, чтобы связать их вместе. Но компания может распознать, что оба взаимодействия были с Джоном, и объединить их Контакты вместе. Это объединение фактически удаляет один из Контактов и добавляет связанного с ним Клиента в M2M-отношения другого. Таким образом, данные о взаимодействии третьих лиц не подвергаются никакому вмешательству, но компания получает возможность объединить Контакты.