Дизайн моделей Django: отношения «многие ко многим» с учетом конкретных потребностей

#python #django #database-design

#python #django #проектирование базы данных

Вопрос:

Я нахожусь в процессе разработки пары новых моделей для моего приложения django, и это то, что мне нужно:

 class Bookmaker(models.Model):
  name = models.CharField(max_length=50)
  accepted_countries = ?
  restricted_countries = ?

class Country(models.Model):
  name = models.CharField(max_length=50)
  bookmakers = ?
  

Итак, мне нужна модель букмекера и модель страны, и они должны быть связаны, НО у каждого букмекера должен быть список стран, которые принимаются, и список стран, которые исключены.
Вопросительные знаки находятся как в моделях Country, так и в моделях букмекера, поскольку я не уверен, в какую сторону следует устанавливать отношение.

Не уверен, что я на правильном пути, но я думаю, что мне нужна пара отношений «многие ко многим».. И какой правильный способ (если таковой имеется) использовать одну и ту же модель страны (это будут разные экземпляры) как в accepted_countries, так и в restricted_countries?

Спасибо.

Комментарии:

1. Являются ли restricted_countries и accepted_countries списки исчерпывающими? Если это так, вам нужно будет отслеживать только один из них, а затем вычислять другой на основе того, какие страны отсутствуют.

2. Какова цель bookmakers поля в Country модели? В дополнение к принятым / ограниченным странам, Bookmaker нужно ли каким-либо другим образом связывать a с одной страной или несколькими странами? Если нет, нет необходимости включать поле букмекеров в модель страны.

3. Привет @jimijimjim Да, вы правы, нет необходимости включать букмекерские конторы в модель страны; Я написал это только для того, чтобы подчеркнуть, что я не знал, в какую сторону идет отношение… Что касается исчерпывающей информации о списках, если страна принята, она не может быть ограничена наоборот, но если у меня нет информации о конкретной стране, которая может не входить ни в одну из двух.

Ответ №1:

Вы должны использовать два отношения «многие ко многим» с related_name , чтобы разделить их:

 class Bookmaker(models.Model):
    name = models.CharField(max_length=50)
    accepted_countries = models.ManyToManyField(Country, related_name="accepted_for")
    restricted_countries = models.ManyToManyField(Country, related_name="restricted_for")
  

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

 bookmakers_for_which_county_is_accepted = Country.objects.values('accepted_for').distinct()
bookmakers_for_which_county_is_restricted = Country.objects.values('restricted_for').distinct()

  

Документы

Комментарии:

1. Спасибо, я думаю, что попробую этот подход.

Ответ №2:

Вам действительно нужно несколько «многие ко многим»:

 class Bookmaker(models.Model):
  name = models.CharField(max_length=50)
  accepted_countries = models.ManyToMany('Country',related_name='accepted')
  restricted_countries = models.ManyToMany('Country', related_name= 'restricted')

class Country(models.Model):
  name = models.CharField(max_length=50)
  bookmakers = models.ManyToMany(Bookmaker)
  

Затем, если вы создадите форму для редактирования букмекерской конторы, вы сможете добавить название, принятые и ограниченные страны:

forms.py

 class BookmakerForm(models.ModelForm):
    class Meta:
        model = Bookmaker
        fields = ['name', 'accepted_countries', 'restricted_countries']

    #for having a better default display you can change the widget:
    self __init__(self, *args, **kwargs):
        super(BookmakerForm, self).__init__(*args, **kwargs)
        self.fields['accepted_countries'].widget = CheckboxSelectMultiple()
        self.fields['restricted_countries'].widget = CheckboxSelectMultiple()
  

В представлении по умолчанию, если вам просто нужно проверить, form.is_valid() и сохранить. django modelform выполнит промежуточный шаг за вас.

Поле букмекерские конторы в Country позволяет вам получить все букмекерские конторы, связанные со страной, без необходимости проверять как принятые, так и ограниченные (это больше для удобства).

Но вам нужно будет добавить букмекера в этот список на вашем представлении, например:

 class CreateBookmakerView(CreateView):
    model = Bookmaker
    form_class = BookmakerForm
    success_url = reverse_lazy('your success url name here')

    def form_valid(self,form):
        bookmaker = form.save()
        bookmaker.country_set.add(bookmaker)
        bookmaker.save()
        return HttpResponseRedirect(self.get_success_url())