2017-06-29 44 views
7

Ktoś wie, jak utworzyć pole z kluczem obcym i sprawić, by zawsze wskazywał na ten sam model, do tej pory je otrzymałem.Niestandardowe django foreignfield

class PanMachineTimeUnitField(models.ForeignKey): 
    def __init__(self, **kwargs): 
     to = 'panbas.PanBasTimeUnit' 
     kwargs['verbose_name'] = _('Machine Unit') 
     kwargs['related_name'] = 'machine_unit' 
     super(PanMachineTimeUnitField, self).__init__(to, **kwargs) 

Ale mam błędy, gdy na starcie. Dążę do jak go używać,

machine_unit = PanMachineTimeUnitField() 

Brak dalszych deklaracji potrzebne.

Edytuj: Chcę tego, ponieważ będę miał ten cudzoziemski w ciszy kilka miejsc. Jeśli chcę zmienić pełną nazwę pola, chcę, aby ta zmiana dotyczyła wszystkich moich pól. Dokładna nazwa była przykładem, może to być inny atrybut.

Nie chcę używać ustawień py do deklarowania wartości domyślnych.

+0

Umieścić swoje błędy? – Todor

Odpowiedz

8

I zaleca, aby stosować tylko prostą funkcję stworzyć podobnie wstępnie skonfigurowane wystąpienie ForeignKey: (nie instancję podklasy ForeignKey)

def pan_machine_time_unit_field(**kwargs): 
    othermodel = 'panbas.PanBasTimeUnit' 
    on_delete = models.DO_NOTHING # or what you need 
    kwargs['verbose_name'] = 'Machine Unit' 
    kwargs.setdefault('related_name', '+') 
    # or: kwargs.setdefault('related_name', "%(app_label)s_%(class)s_related", 
    return models.ForeignKey(othermodel, on_delete, **kwargs) 

class C(models.Model): 
    machine_unit = pan_machine_time_unit_field() 
    # or: 
    # machine_unit = pan_machine_time_unit_field(related_name='klass_c_children') 

Atrybut related_name to nazwa używana dla relacja wstecz od obiektu docelowego z othermodel do wszystkich obiektów, które go odwołują. Ta nazwa musi być unikatowa w othermodel ("panbas.PanBasTimeUnit", zwykle z nazwą aplikacji i klasy, która jest wystarczająco unikatowa) lub ta nazwa może być '+', jeśli nie chcesz tworzyć zestawu zapytań o relacje wstecz. Oba warianty są podane w przykładzie. Pamiętaj także o on_delete.

Jeśli naprawdę trzeba utworzyć podklasę (co ma sens, jeśli trzeba będzie dostosować więcej metod), należy również zdefiniować metodę migracji dla metody deconstruct. Byłoby to skomplikowane, gdybyś później musiał zmodyfikować taką podklasę. Nie można go nigdy usunąć, zmienić jego nazwy itp. Z powodu migrations on a custom field. Z drugiej strony, jeśli utworzysz proste wystąpienie ForeignKey bezpośrednio przez funkcję, wszystko na temat migracji można zignorować.


EDIT

Alternatywnie można utworzyć abstract base model z tej dziedziny i tworzyć nowe modele w drodze dziedziczenia lub multiple inheritance:

class WithPanBasTimeUnit(models.Model): 
    machine_unit = models.ForeignKey(
     'panbas.PanBasTimeUnit', 
     models.DO_NOTHING, 
     verbose_name=_('Machine Unit'), 
     related_name='%(app_label)s_%(class)s_related' 
    ) 

    class Meta: 
     abstract = True 

class ExampleModel(WithPanBasTimeUnit, ...or more possible base models...): 
    ... other fields 

tego rozwiązania (inspirowane przez nieprawidłową soution YKH) użyteczne, jeśli chcesz dodać metodę do modeli z tym polem lub dodać więcej pól razem, w przeciwnym razie oryginalne rozwiązanie jest łatwe r.

6
class PanBasTimeUnit(models.Model): 
    machine_unit = models.ForeignKey('self', blank=True, null=True, 
           verbose_name=u'parent') 

użycie 'self' lub 'panbas.PanBasTimeUnit' będzie w porządku.

+1

Nie chcę podawać żadnego parametru do klucza obcego "Brak dalszych wymaganych deklaracji.". – durdenk

+0

Spowoduje to dodanie niepożądanego pola odwołania z jednego obiektu PanBasTimeUnit do innego obiektu PanBasTimeUnit i nie rozwiąże niczego użytecznego dla pytania. Naprawiam twoje rozwiązanie i dodam je do końca mojej odpowiedzi, ponieważ jest za długo w komentarzu. – hynekcer

1

dlaczego nie korzystać bezpośrednio machine_unit = models.ForeignKey(panbas.PanBasTimeUnit, verbose_name=_('Machine Unit'), related_name='machine_unit')) ?

+0

Będę miał ten cudzysłów w cichych miejscach, więc chcę, żeby był on zarządzany w miejscu, w którym jeśli zmienię pełną nazwę, chcę, aby wszystkie zmienne zostały zmienione. – durdenk

+0

co do ustawiania pełnej nazwy w settings.py, a następnie: MY_VERBOSE_NAME = _ ('Machine Unit'), aw modelu: machine_unit = models.ForeignKey (panbas.PanBasTimeUnit, verbose_name = settings.MY_VERBOSE_NAME, related_name = 'machine_unit')) – Yom86

3

niewielkimi zmianami w swojej próbie powinien wykonywać swoją pracę.

class PanMachineTimeUnitField(models.ForeignKey): 
    def __init__(self, **kwargs): 
     kwargs["to"] = 'panbas.PanBasTimeUnit' 
     kwargs['verbose_name'] = _('Machine Unit') 
     kwargs['related_name'] = 'machine_unit' 
     super(PanMachineTimeUnitField, self).__init__(**kwargs) 
4

Nie możesz mieć kilku kluczy obcych dla modelu z tym samym related_name.

Rzeczywiście, na instancji PanBasTimeUnit, który menedżer powinien zwracać Django podczas wywoływania <instance>.machine_unit? Właśnie dlatego musisz być ostrożny przy related models and abstract classes.

Powinno działać poprawnie, jeśli usuniesz kod kwargs['related_name'] = 'machine_unit' i zastąpisz go numerem kwargs['related_name'] = "%(app_label)s_%(class)s_related" lub podobnym.