2012-01-15 8 views
9

Все,путать о Джанго ForeignKey, ManyToManyField, inlineformset_factories

Я что-то фундаментальное о базовой модели для ForeingKeys Джанго против ManyToManyFields отсутствует.

Предположим, я создаю заявку на автомобили. Я мог бы иметь следующие классы:

class Car(models.Model): 
    carName = models.CharField() 

class Manufacturer(models.Model): 
    manufacturerName = models.CharField() 

class Wheel(models.Model): 
    radius = models.IntegerField() 

Пока все хорошо. Теперь между этими классами существуют некоторые отношения. Автомобиль имеет производителя и имеет (четыре) шины. Понятно, что есть разница. Изготовитель связан посредством «агрегации»; производитель может быть связан с несколькими автомобилями; удаление экземпляра Car не должно приводить к удалению производителя автомобиля. Колеса связаны посредством «композиции»; каждые четыре колеса, связанные с автомобилем, связаны с этим и только с этим автомобилем; удалите автомобиль, и колеса также должны быть удалены.

Таким образом, интуитивно, что означает, что я должен сделать следующее:

class Car(models.Model): 
    carName = models.CharField() 
    manufacturer = models.ManyToManyField("Manufacturer") 
    wheels = models.ForeignKey("Wheel") 

В конце концов, я хочу использовать inlineformset_factories, так что пользователи могут заполнить подробную информацию о машине, его производитель и колеса все на в то же время. Что-то вроде этого:

class CarForm(ModelForm): 
    class Meta: 
    model = Car 

class ManufacturerForm(ModelForm): 
    class Meta: 
    model = Manufacturer 

class WheelForm(ModelForm): 
    class Meta: 
    model = Wheel 

Manufacturer_formset = inlineformset_factory(Car,Manufacturer,formset=ManufacturerForm) 
Wheel_formset = inlineformset_factory(Car,Wheel,formset=WheelForm) 

Но большая часть документации, которую я нахожу, предполагает, что ForiegnKey должна идти от колеса к автомобилю. Это кажется мне обратным, поскольку Wheel_formset затем предоставил пользователю все поля для автомобиля («carName»), а не «Wheel» («радиус»).

Просто поступок ввода этого вопроса меня смущает. Кто-нибудь может пролить свет на то, как я могу создать форму, в которой есть все поля для автомобилей, а затем все поля изготовителя, а затем все поля колес.

Благодаря

ответ

15

Если каждый автомобиль имеет один производитель, то вы должны использовать внешний ключ от Car к Manufacturer. Это позволит нескольким автомобилям иметь одного и того же производителя, и производители не будут удалены при удалении автомобилей. Многое поле позволяет предположить, что один автомобиль может иметь несколько производителей.

Wheel должен иметь внешний ключ до Car. Это позволит нескольким колесам иметь один и тот же автомобиль, а поведение Django по умолчанию при удалении автомобиля - это удаление колес.

Так что ваши модели должны выглядеть следующим образом:

class Manufacturer(models.Model): 
    name = models.CharField() 

class Car(models.Model): 
    name = models.CharField() 
    manufacturer = models.ForeignKey("Manufacturer") 

class Wheel(models.Model): 
    radius = models.IntegerField() 
    car = models.ForeignKey("Car") 

Для вашей точки зрения, я бы сначала попытаться написать представления для форм и FormSets индивидуально, и убедитесь, что вы понимаете отношения между вашими моделями перед вами объединить их в одном взгляде.

В этом Stack Overflow question объясняется, как использовать форму и встроенный набор форм вместе в одно и то же время (что эквивалентно моделям и Wheel в вашем случае). Для производителя вы, вероятно, захотите exclude поле manufacturer с вашего CarForm, а затем установите его на ваш взгляд перед сохранением.

... 
manufacturer = ManufacturerForm.save() 
car = CarForm.save(commit=False) 
car.manufacturer = manufacturer 
car.save() 
... 
+0

Благодарим за этот ответ.Могу ли я подтвердить, что если у автомобиля может быть более одного производителя (скажем, оно построено командой), то я должен использовать ManyToManyField? – trubliphone

+0

Да, если автомобиль может иметь более одного производителя (и производитель может построить больше, чем один автомобиль), используйте «ManyToManyField». – Alasdair

+3

Бит опоздал на вечеринку, но не был бы иностранным ключом для многих отношений? –