Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fk_name 'user' is not a ForeignKey to <class 'satchmo_store.contact.models.Contact'>

I am using django 1.3.1 and satchmo 0.9.2. I used the default model that ships with Satchmo called Contact. I created a satchmo_mod app, and an admin.py file.

pip install django==1.3.1
pip install -r http://bitbucket.org/chris1610/satchmo/raw/tip/scripts/requirements.txt
pip install satchmo 0.9.2

django-admin.py startproject fk_test
cd fk_test
python manage.py startapp satchmo_mod

then create admin.py:

from satchmo_store.contact.models import Contact
admin.site.unregister(Contact)
admin.site.register(Contact)

I then run:

python manage.py runserver

Go to:

127.0.0.1:8000

Get this error:

fk_name 'user' is not a ForeignKey to <class 'satchmo_store.contact.models.Contact'>

I see this error in the stack trace and start to go exploring:

/home/cody/work/martin-instruments/virtual-envs/mi-prod-copy/lib/python2.6/site-packages/django/contrib/admin/validation.py in validate_inline
    fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True) ...
▼ Local vars
Variable    Value
parent_model    
<class 'satchmo_store.contact.models.Contact'>
cls 
<class 'satchmo_mod.admin.UserTaxExemptInline'>
parent  
<class 'django.contrib.admin.options.ModelAdmin'>
f   
<django.db.models.fields.related.OneToOneField object at 0x2ec2250>

Long story short, when the Contact model gets registered back, all of it's _meta options aren't being regenerated as far as I can tell. See the 'manage.py shell' session below:

envs/mi2.0/mi$ ./manage.py shell
Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from satchmo_mod.admin import UserTaxExemptInline
>>> from satchmo_mod.admin import MyContactOptions
>>> from django.db.models.fields.related import OneToOneField
>>> from satchmo_store.contact.models import Contact
>>> cls = UserTaxExemptInline
>>> parent_model = Contact
>>> parent = MyContactOptions
>>> from django.contrib.admin.validation import get_field
>>> f = get_field(cls, cls.model, cls.model._meta, 'fk_name', cls.fk_name)
>>> print f
<django.db.models.fields.related.OneToOneField object at 0x2c358d0>
>>> dir(f)
['__class__', '__cmp__', '__deepcopy__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__metaclass__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slotnames__', '__str__', '__subclasshook__', '__weakref__', '_choices', '_description', '_get_choices', '_get_flatchoices', '_get_val_from_obj', '_pk_trace', '_unique', 'attname', 'auto_created', 'auto_creation_counter', 'bind', 'blank', 'choices', 'clean', 'column', 'contribute_to_class', 'contribute_to_related_class', 'creation_counter', 'db_column', 'db_index', 'db_tablespace', 'db_type', 'default', 'default_error_messages', 'default_validators', 'description', 'do_related_class', 'editable', 'empty_strings_allowed', 'error_messages', 'flatchoices', 'formfield', 'get_attname', 'get_attname_column', 'get_cache_name', 'get_choices', 'get_choices_default', 'get_db_prep_lookup', 'get_db_prep_save', 'get_db_prep_value', 'get_default', 'get_flatchoices', 'get_internal_type', 'get_prep_lookup', 'get_prep_value', 'get_validator_unique_lookup_type', 'has_default', 'help_text', 'max_length', 'model', 'name', 'null', 'opts', 'pre_save', 'primary_key', 'rel', 'related', 'related_query_name', 'run_validators', 'save_form_data', 'serialize', 'set_attributes_from_name', 'set_attributes_from_rel', 'to_python', 'unique', 'unique_for_date', 'unique_for_month', 'unique_for_year', 'validate', 'validators', 'value_from_object', 'value_to_string', 'verbose_name']
>>> from django.db import models
>>> isinstance(f, models.ForeignKey)
True
>>> from django.forms.models import _get_foreign_key
>>> fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/cody/work/martin-instruments/virtual-envs/mi2.0/lib/python2.6/site-packages/django/forms/models.py", line 770, in _get_foreign_key
    raise Exception("fk_name '%s' is not a ForeignKey to %s" % (fk_name, parent_model))
Exception: fk_name 'user' is not a ForeignKey to <class 'satchmo_store.contact.models.Contact'>
>>> print parent_model, cls.model, cls.fk_name
<class 'satchmo_store.contact.models.Contact'> <class 'satchmo_mod.models.UserTaxExempt'> user
>>> fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/cody/work/martin-instruments/virtual-envs/mi2.0/lib/python2.6/site-packages/django/forms/models.py", line 770, in _get_foreign_key
    raise Exception("fk_name '%s' is not a ForeignKey to %s" % (fk_name, parent_model))
Exception: fk_name 'user' is not a ForeignKey to <class 'satchmo_store.contact.models.Contact'>
>>> print model
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'model' is not defined
>>> print parent_model
<class 'satchmo_store.contact.models.Contact'>
>>> cls.model
<class 'satchmo_mod.models.UserTaxExempt'>
>>> model = cls.model
>>> opts = model._meta
>>> fk_name
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'fk_name' is not defined
>>> fk_name = cls.fk_name
>>> fk_name
'user'
>>> fks_to_parent = [f for f in opts.fields if f.name == fk_name]
>>> print fks_to_parent
[<django.db.models.fields.related.OneToOneField object at 0x2c358d0>]
>>> not isinstance(fk, ForeignKey)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'fk' is not defined
>>> fk = fks_to_parent[0]
>>> not isinstance(fk, ForeignKey)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'ForeignKey' is not defined
>>> from django.db.models import ForeignKey
>>> not isinstance(fk, ForeignKey)
False
>>> len(fks_to_parent) == 1
True
>>> not isinstance(fk, ForeignKey) or \
...  768                     (fk.rel.to != parent_model and
... fk.rel.to not in parent_model._meta.get_parent_list())
Traceback (most recent call last):
  File "<console>", line 3, in <module>
TypeError: 'int' object is not callable
>>> not isinstance(fk, ForeignKey) or (fk.rel.to != parent_model and fk.rel.to not in parent_model._meta.get_parent_list())
True
>>> parent_model
<class 'satchmo_store.contact.models.Contact'>
>>> parent_model._meta.get_parent_list()
set([])
>>> fk.rel.to
<class 'django.contrib.auth.models.User'>
>>> fk.rel.to != parent_model
True
>>> fk.rel.to not in parent_model._meta.get_parent_list()
True
>>> fk.rel.to
<class 'django.contrib.auth.models.User'>
>>> fk.rel.to == parent_model
False
>>> parent_model
<class 'satchmo_store.contact.models.Contact'>
>>> fk
<django.db.models.fields.related.OneToOneField object at 0x2c358d0>
>>> fk.rel.to
<class 'django.contrib.auth.models.User'>
>>> # User has to be not equal to Contact
>>> # and fk.rel.to can't be in the parent model's parent list
>>> fk.rel.to
<class 'django.contrib.auth.models.User'>
>>> fk.rel
<django.db.models.fields.related.OneToOneRel object at 0x2c35990>
>>> fk.rel.to != parent_model
True
>>> # OneToOneRel can't be equal to parent_model(Contact) nor can OneToOneRel be in the parent_model(Contact) parent list
>>> Contact._meta.get_parent_list()
set([])
>>> parent_model is Contact
True
>>> fk.rel.to in parent_model._meta.get_parent_list()
False
>>> fk.rel.to != parent_model
True
>>> (fk.rel.to != parent_model and fk.rel.to not in parent_model._meta.get_parent_list())
True
>>> (fk.rel.to != parent_model and fk.rel.to not in parent_model._meta.get_parent_list())
True
>>> (True and False)
False
>>> fk.rel.to != parent_model
True
>>> fk.rel.to.not in parent_model._meta.get_parent_list()
  File "<console>", line 1
    fk.rel.to.not in parent_model._meta.get_parent_list()
                ^
SyntaxError: invalid syntax
>>> fk.rel.to not in parent_model._meta.get_parent_list()
True
>>> fk.rel.to != parent_model
True
>>> fk.rel.to not in parent_model._meta.get_parent_list()
True
>>> fk.rel.to
<class 'django.contrib.auth.models.User'>
>>> parent-model
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'MediaDefiningClass' and 'ModelBase'
>>> parent_model
<class 'satchmo_store.contact.models.Contact'>
>>> fk.rel.to
<class 'django.contrib.auth.models.User'>
>>> parent_model
<class 'satchmo_store.contact.models.Contact'>
>>> parent_model._meta.get_parent_list()
set([])
>>> parent_model.parents
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: type object 'Contact' has no attribute 'parents'
>>> parent_model.options
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: type object 'Contact' has no attribute 'options'
>>> opts
<Options for UserTaxExempt>
>>> parent_model._meta
<Options for Contact>
>>> parent_model._meta.parents
{}
>>> User._meta.parents
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'User' is not defined
>>> from django.contrib.auth.models import User
>>> User._meta.parents
{}
>>> from martin.models import CreditApplication
>>> CreditApplication._meta.parents
{}
>>> User._meta.fields
[<django.db.models.fields.AutoField object at 0x21d45d0>, <django.db.models.fields.CharField object at 0x21d2450>, <django.db.models.fields.CharField object at 0x21d25d0>, <django.db.models.fields.CharField object at 0x21d26d0>, <django.db.models.fields.EmailField object at 0x21d27d0>, <django.db.models.fields.CharField object at 0x21d2950>, <django.db.models.fields.BooleanField object at 0x21d2a90>, <django.db.models.fields.BooleanField object at 0x21d2bd0>, <django.db.models.fields.BooleanField object at 0x21d2d10>, <django.db.models.fields.DateTimeField object at 0x21d2e10>, <django.db.models.fields.DateTimeField object at 0x21d2e90>]
>>> Contact._meta.fields
[<django.db.models.fields.AutoField object at 0x289a510>, <django.db.models.fields.CharField object at 0x2899a90>, <django.db.models.fields.CharField object at 0x2899c10>, <django.db.models.fields.CharField object at 0x2899d10>, <django.db.models.fields.related.ForeignKey object at 0x2899dd0>, <django.db.models.fields.related.ForeignKey object at 0x2899e90>, <django.db.models.fields.related.ForeignKey object at 0x2899f90>, <django.db.models.fields.DateField object at 0x289a0d0>, <django.db.models.fields.EmailField object at 0x289a150>, <django.db.models.fields.TextField object at 0x289a2d0>, <django.db.models.fields.DateField object at 0x289a350>]
>>> Contact._meta.fields[0]
<django.db.models.fields.AutoField object at 0x289a510>
>>> dir(Contact._meta.fields[0])
['__class__', '__cmp__', '__deepcopy__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__metaclass__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_choices', '_description', '_get_choices', '_get_flatchoices', '_get_val_from_obj', '_unique', 'attname', 'auto_created', 'auto_creation_counter', 'bind', 'blank', 'choices', 'clean', 'column', 'contribute_to_class', 'creation_counter', 'db_column', 'db_index', 'db_tablespace', 'db_type', 'default', 'default_error_messages', 'default_validators', 'description', 'editable', 'empty_strings_allowed', 'error_messages', 'flatchoices', 'formfield', 'get_attname', 'get_attname_column', 'get_cache_name', 'get_choices', 'get_choices_default', 'get_db_prep_lookup', 'get_db_prep_save', 'get_db_prep_value', 'get_default', 'get_flatchoices', 'get_internal_type', 'get_prep_lookup', 'get_prep_value', 'get_validator_unique_lookup_type', 'has_default', 'help_text', 'max_length', 'model', 'name', 'null', 'pre_save', 'primary_key', 'rel', 'run_validators', 'save_form_data', 'serialize', 'set_attributes_from_name', 'to_python', 'unique', 'unique_for_date', 'unique_for_month', 'unique_for_year', 'validate', 'validators', 'value_from_object', 'value_to_string', 'verbose_name']
>>> Contact._meta.fields[0].model
<class 'satchmo_store.contact.models.Contact'>
>>> Contact._meta.fields[1].model
<class 'satchmo_store.contact.models.Contact'>

UPDATE: I did the fix recommended by Maccesch. But it seems after unregistering the Contact object, and reregistering it with the new inline, it did something to break Zinnia:

fk_name 'user' is not a ForeignKey to <class 'zinnia.models.Category'>

UPDATE: Might want to start a new question, wasn't sure.

This is the code for the model and modeladmin:

Models.py

class UserTaxExempt(models.Model):
    user = models.OneToOneField(_User, primary_key=True)
    tax_exempted = models.BooleanField("No taxes would be applied to purchases")

    class Meta:
        verbose_name = _('Tax Exemption')
        verbose_name_plural = _('Tax Exemption') 

    def __unicode__(self):
        if self.tax_exempted:
            return unicode("Purchases are exempted from taxes")
        else:
            return unicode("Purchases are taxed")

admin.py

from satchmo_mod.models import ContactTaxExempt
from satchmo_store.contact.admin import PhoneNumber_Inline, AddressBook_Inline
from satchmo_store.contact.models import Contact

class ContactTaxExemptInline(admin.TabularInline):
    model = ContactTaxExempt
    max_num = 1 
    extra = 1 
    can_delete = False
    fk_name = "user"

class ContactOptions(admin.ModelAdmin):
    list_display = ('last_name', 'first_name')
    list_filter = ['create_date']
    ordering = ['last_name']
    search_fields = ('first_name', 'last_name', 'email')
    related_search_fields = {'user': ('username', 'first_name', 'last_name', 'em
    related_string_functions = {'user': lambda u: u"%s (%s)" % (u.username, u.ge
    inlines = [ContactTaxExemptInline, PhoneNumber_Inline, AddressBook_Inline]

admin.site.unregister(Contact)
admin.site.register(Contact, ContactOptions)

So UserTaxExempt has a foreignkey to User, so shouldn't this work just fine? It works on the User page, so I'm not getting why it wouldn't work on the Contact page.

like image 710
codygman Avatar asked Jun 19 '12 05:06

codygman


2 Answers

The problem seems to be in your UserTaxExemptInline. You didn't post how that looks like but I guess it looks like this:

class UserTaxExemptInline(admin.TabularInline):
    model = Contact
    fk_name = "user"

while it should look like this:

class UserTaxExemptInline(admin.TabularInline):
    model = User
like image 79
Maccesch Avatar answered Nov 04 '22 01:11

Maccesch


See _get_foreign_key in django/forms/models.py.

_get_foreign_key description:

Finds and returns the ForeignKey from model to parent if there is one
(returns None if can_fail is True and no such field exists). If fk_name is
provided, assume it is the name of the ForeignKey field. Unles can_fail is
True, an exception is raised if there is no ForeignKey from model to
parent_model.

And now for the exception:

if fk_name:
        fks_to_parent = [f for f in opts.fields if f.name == fk_name]
        if len(fks_to_parent) == 1:
            fk = fks_to_parent[0]
            if not isinstance(fk, ForeignKey) or \
                    (fk.rel.to != parent_model and
                     fk.rel.to not in parent_model._meta.get_parent_list()):
                raise Exception("fk_name '%s' is not a ForeignKey to %s" % (fk_name, parent_model))

I am guessing that you have not setup the fields or relationships in your model correctly.

I did read somewhere about someone solving this problem by adding pass to their class like so:

class Whatever(x.x):
        pass
like image 30
Michael Frederick Avatar answered Nov 04 '22 02:11

Michael Frederick