Custom django foreignfield

Does anyone know how to create a foreignkey field and always point to the same model, so far I got them.

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) 

But when I started, I got errors. I try to use it as

 machine_unit = PanMachineTimeUnitField() 

No further declarations are required.

Edit: I want this because I will have this foreign key in silence in several places. If I want to change the verbose_name of a field, I want all my fields to be affected by this change. The detailed name was an example; it could be a different attribute.

I do not want to use py settings to declare default values.

+6
django django-models
source share
5 answers

I recommend using only a simple function to create a similarly pre-configured instance of ForeignKey: (and not an instance of a subclass of 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') 

The related_name attribute is the name used to inverse relationship from the othermodel target to all objects that reference it. This name must be unique to othermodel ("panbas.PanBasTimeUnit", usually something with a unique name for the application and class), or this name can be '+' if you do not want to create a set of feedback requests. Both options are implied in this example. Also remember on_delete .

If you really need to create a subclass (which makes sense if you need to configure additional methods), you must also define a deconstruct method for the transfer. It would be difficult if you subsequently had to modify such a subclass. It cannot be deleted, renamed, etc. Due to migration in a custom field . On the other hand, if you create a simple ForeignKey instance directly using a function, you can ignore everything about migration.


EDIT

Alternatively, you can create an abstract base model with this field and create new models for inheritance or 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 

This solution (inspired by the invalid soution Ykh) is useful if you want to add a method to models with this field or add more fields together, otherwise the original solution will be simpler.

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

using 'self' or 'panbas.PanBasTimeUnit' would be great.

+6
source share

You cannot have multiple foreign keys to the model with the same related_name .

Indeed, in a PanBasTimeUnit instance, which manager should Django return when calling <instance>.machine_unit ? This is why you have to be careful about related models and abstract classes .

It should work fine if you remove kwargs['related_name'] = 'machine_unit' in your code and replace it with kwargs['related_name'] = "%(app_label)s_%(class)s_related" or something similar.

+4
source share

A small change in your attempt should do your job.

 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) 
+3
source share

why not use machine_unit = models.ForeignKey(panbas.PanBasTimeUnit, verbose_name=_('Machine Unit'), related_name='machine_unit')) ?

+1
source share

All Articles