проблема модели django с M2M и отношениями внешнего ключа

#django #django-models #many-to-many

#django #django-модели #многие ко многим

Вопрос:

У меня есть эта модель «jobs» (показана ниже).

  • Между хостами и местоположениями существует отношение M2M (местоположению назначено несколько хостов).
  • У меня также есть класс Timezone с отношением внешнего ключа, определенным между местоположением и часовым поясом (местоположению присваивается часовой пояс)

Проблема, с которой я сталкиваюсь, заключается в том, что я не могу отменить комментарий к элементу ‘colo’ в классе Host из-за ссылки внешнего ключа на «Местоположение». Класс Location определяется после класса Host. Но я не могу переместить определение местоположения выше класса Host из-за ссылки M2M на «hosts» в классе Location.

Я что-то упускаю концептуально? Любая помощь была бы высоко оценена!

Вот соответствующая часть моей модели:

 class Timezone(models.Model):
    name = models.CharField(max_length=32, unique=True)
    def __unicode__(self):
        return "%s"%(self.name)

class Host(models.Model):
    name = models.CharField(max_length=32, unique=True)
#    colo = models.ForeignKey(Location)
    def __unicode__(self):
        return "%s"%(self.name)

class Location(models.Model):
    name = models.CharField(max_length=3, unique=True)
    hosts = models.ManyToManyField(Host, blank=True) #not required
    tz = models.ForeignKey(Timezone)
    def __unicode__(self):
        return "%s"%(self.name)
  

Ответ №1:

В принципе, вы не можете ссылаться на класс Location до того, как он был определен. Итак, если вы измените порядок классов хоста и местоположения, это поможет. Тогда отношение «многие ко многим» относится к классу хоста, который еще не определен. Но поскольку отношения «многие ко многим» могут быть определены в любой таблице, просто переместите ее в класс Host. Вот измененный код:

 class Timezone(models.Model):
    name = models.CharField(max_length=32, unique=True)
    def __unicode__(self):
        return "%s"%(self.name)

class Location(models.Model):
    name = models.CharField(max_length=3, unique=True)    
    tz = models.ForeignKey(Timezone)
    def __unicode__(self):
        return "%s"%(self.name)

class Host(models.Model):
    name = models.CharField(max_length=32, unique=True)
    colo = models.ForeignKey(Location, related_name='colocation')
    locations = models.ManyToManyField(Location, blank=True) #not required
    def __unicode__(self):
        return "%s"%(self.name)
  

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

1. спасибо за быстрый ответ, но у хоста будет только одно местоположение — местоположение, в котором он находится.

2. Но у вас есть отношение «многие ко многим», определенное в вашем классе Location, к классу Host?

3. Это не имеет отношения к вашему вопросу, но вы можете захотеть проверить django-timezones для вашей модели часового пояса. В нем есть несколько приятных функций, которые могут уменьшить некоторую головную боль, связанную с часовыми поясами. github.com/brosner/django-timezones

Ответ №2:

У вас есть отношения «многие ко многим» между хостами и местоположениями, однако вы хотите, чтобы хосты имели одно и то же местоположение, вы на самом деле хотите отношения «один ко многим» между хостами и местоположениями. Это объявлено с использованием моделей.Внешний ключ, который у вас есть в вашем классе хоста. Вам просто нужно изменить порядок кода, чтобы класс Host отображался после класса Location, позволяя вам ссылаться на него. Также вы можете удалить связь «много-много».

 class Timezone(models.Model):
    name = models.CharField(max_length=32, unique=True)
    def __unicode__(self):
        return "%s"%(self.name)    

class Location(models.Model):
    name = models.CharField(max_length=3, unique=True)
    tz = models.ForeignKey(Timezone)
    def __unicode__(self):
        return "%s"%(self.name)

class Host(models.Model):
    name = models.CharField(max_length=32, unique=True)
    colo = models.ForeignKey(Location)
    def __unicode__(self):
        return "%s"%(self.name)
  

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

Ответ №3:

Поскольку хост всегда будет иметь только одно местоположение, вы можете удалить locations поле из модели хоста или удалить colo и изменить locations на location = models.ForeignKey(Location)

Чтобы получить все хосты из местоположения, вы можете сделать

 location = Location.objects.get(pk=1)
hosts = location.host_set.all() #returns all hosts for the location
  

Вот ссылка на документы Django об обратных отношениях

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

1. Ах ха! Это именно то, что мне было нужно. Я не должен беспокоиться об определении обратных отношений в модели. Я должен использовать наборы запросов и фильтры, чтобы, на мой взгляд, изменить отношения, когда это необходимо. Спасибо!!!