balu
balu

Reputation: 3821

How to find out whether a model's column is a foreign key?

I'm dynamically storing information in the database depending on the request:

// table, id and column are provided by the request
table_obj = getattr(models, table)
record = table_obj.objects.get(pk=id)

setattr(record, column, request.POST['value'])

The problem is that request.POST['value'] sometimes contains a foreign record's primary key (i.e. an integer) whereas Django expects the column's value to be an object of type ForeignModel:

Cannot assign "u'122'": "ModelA.b" must be a "ModelB" instance.

Now, is there an elegant way to dynamically check whether b is a column containing foreign keys and what model these keys are linked to? (So that I can load the foreign record by it's primary key and assign it to ModelA?) Or doesn't Django provide information like this to the programmer so I really have to get my hands dirty and use isinstance() on the foreign-key column?

Upvotes: 18

Views: 11667

Answers (5)

augustomen
augustomen

Reputation: 9739

You can use the property is_relation of a model's Field to determine whether it's a ForeignKey, ManyToManyField, or OneToOneField. This is set to True in all these classes. All other field types are False.

You can obtain the field class by calling Model._meta.get_field(). Example:

field = table_obj._meta.get_field(column)
if field.is_relation:
    ...

Upvotes: 1

John Montgomery
John Montgomery

Reputation: 9058

You can use get_field_by_name on the models _meta object:


from django.db.models import ForeignKey

def get_fk_model(model, fieldname):
    """Returns None if not foreignkey, otherswise the relevant model"""
    field_object, model, direct, m2m = model._meta.get_field_by_name(fieldname)
    if not m2m and direct and isinstance(field_object, ForeignKey):
        return field_object.rel.to
    return None

Assuming you had a model class MyModel you would use this thus:


fk_model = get_fk_model(MyModel, 'fieldname')

Upvotes: 15

Parag Tyagi
Parag Tyagi

Reputation: 8960

Simple one liner to find all the relations to other models that exist in a model:

In [8]: relations = [f for f in Model._meta.get_fields() if (f.many_to_one or f.one_to_one) and f.auto_created]

Above will give a list of all the models with their relations.

Example:

In [9]: relations
Out[9]:
[<ManyToOneRel: app1.model1>,
 <ManyToOneRel: app2.model1>,
 <OneToOneRel: app1.model2>,
 <OneToOneRel: app3.model5>,
 <OneToOneRel: app5.model1>]

Upvotes: 6

ultrajohn
ultrajohn

Reputation: 2597

I encountered the same use case, and the accepted answer did not work for me directly. I am using Django 1.2 if it's relevant. Instead, I used the get_field_by_name method as follows.

def get_foreign_keys(self):
        foreign_keys = []
        for field in self._meta.fields:
            if isinstance(self._meta.get_field_by_name(field.name)[0], models.ForeignKey):
                foreign_keys.append(field.name)

        if not foreign_keys:
            return None
        return foreign_keys

This is a method define inside a class. For my case, what I needed are the names of the ForeignKey fields. Cheers!

Upvotes: 1

John Mee
John Mee

Reputation: 52233

Explore the "ModelChoiceField" fields. Can they solve your problem putting foreign keys into forms for you; rather than doing that yourself.

http://docs.djangoproject.com/en/1.1/ref/forms/fields/#fields-which-handle-relationships

record = forms.ModelChoiceField(queryset=table_obj.objects.all())

Upvotes: 0

Related Questions