bennylope / django-organizations

:couple: Multi-user accounts for Django projects

Home Page:http://django-organizations.readthedocs.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

version 2 stable?

specialorange opened this issue · comments

I updated all pip packages ( https://stackoverflow.com/questions/2720014/how-to-upgrade-all-python-packages-with-pip [oops] ) which uses this package, and I've run into problems. Everything was working on v 1.1.1, and I am now getting some weird errors:

  • some dealing with having to include empty Meta classes on the Account/Organization/User models
  • some dealing with having to include empty raw_id_fields = () admin models for Account/Organization/User
  • here are some errors that the runserver prevented from running, migrating, or making migrations
<class 'accounts.admin.AccountOwnerAdmin'>: (admin.E002) The value of 'raw_id_fields[0]' refers to 'organization_user', which is not an attribute of 'accounts.AccountOwner'.
<class 'accounts.admin.AccountOwnerAdmin'>: (admin.E002) The value of 'raw_id_fields[1]' refers to 'organization', which is not an attribute of 'accounts.AccountOwner'.
<class 'accounts.admin.AccountOwnerAdmin'>: (admin.E108) The value of 'list_display[0]' refers to 'organization', which is not a callable, an attribute of 'AccountOwnerAdmin', or an attribute or method on 'accounts.AccountOwner'.
<class 'accounts.admin.AccountUserAdmin'>: (admin.E002) The value of 'raw_id_fields[0]' refers to 'user', which is not an attribute of 'accounts.AccountUser'.
<class 'accounts.admin.AccountUserAdmin'>: (admin.E002) The value of 'raw_id_fields[1]' refers to 'organization', which is not an attribute of 'accounts.AccountUser'.
<class 'accounts.admin.AccountUserAdmin'>: (admin.E108) The value of 'list_display[0]' refers to 'user', which is not a callable, an attribute of 'AccountUserAdmin', or an attribute or method on 'accounts.AccountUser'.
<class 'accounts.admin.AccountUserAdmin'>: (admin.E108) The value of 'list_display[1]' refers to 'organization', which is not a callable, an attribute of 'AccountUserAdmin', or an attribute or method on 'accounts.AccountUser'.
accounts.AccountUser: (models.E012) 'unique_together' refers to the nonexistent field 'organization'.
accounts.AccountUser: (models.E012) 'unique_together' refers to the nonexistent field 'user'.
accounts.AccountUser: (models.E015) 'ordering' refers to the nonexistent field, related field, or lookup 'organization'.
accounts.AccountUser: (models.E015) 'ordering' refers to the nonexistent field, related field, or lookup 'user'.

Notes

  • My code is based using the Abstract classes.
  • rolling back to 1.1.1 and everything works
  • up to date Django and Python

From what I can tell, and based on it working in 1.1.1, my models are set up correctly (I'm happy to show you if you'd like to see them). Is 2.0.0 only partially ready for use or is there some upgrade step I might have missed?

Is 2.0.0 only partially ready for use or is there some upgrade step I might have missed?

More likely that it is ready but that I missed something with regard to upgrade.

I think what you've shared here is sufficient (thank you for the detail) to start investigating. I've used a precursor to the final 2.0.0 release for quite a while now, but it was not an upgrade from 1.x.

Actually I'll walk that back a bit @specialorange:

(I'm happy to show you if you'd like to see them).

If you want to share your models here or via email that'd make it easier for me!

Yes I would like it a lot. I plan on fixing some of the issues I think I can tackle in the coming weeks. You have helped me in the past, and I think I can finally contribute! :)

Current working v1

# admin.py
from organizations.base_admin import (BaseOwnerInline,
                                      BaseOrganizationAdmin,
                                      BaseOrganizationUserAdmin,
                                      BaseOrganizationOwnerAdmin)

class OwnerInline(BaseOwnerInline):
    model = AccountOwner
    # raw_id_fields = ()
@admin.register(Account)
class AccountAdmin(BaseOrganizationAdmin):
    list_display = ['slug', 'is_active', 'name', 'mgr', 'labor_rate',
                    'number_of_vendors', 'vendors_names', 'number_of_clients',
                    'clients_names', ]
    inlines = [OwnerInline, ServiceInline]
    inlines = [ServiceInline]
    formfield_overrides = {models.ManyToManyField: {'widget': SelectMultiple(attrs={'size': '10'})}, }
@admin.register(AccountUser)
class AccountUserAdmin(BaseOrganizationUserAdmin):
    list_display = ['user', 'organization', 'user_type', ]
    # list_display = ['user_type', ]
    # raw_id_fields = ()
@admin.register(AccountOwner)
class AccountOwnerAdmin(BaseOrganizationOwnerAdmin):
    # raw_id_fields = ("organization_user", "organization")
    list_display = ['organization', ]
    # raw_id_fields = ()

# models.py
from organizations.abstract import (AbstractOrganization,
                                    AbstractOrganizationUser,
                                    AbstractOrganizationOwner)

class AccountUser(AbstractOrganizationUser):
    user_type = models.CharField(max_length=1, default='', blank=True, null=True)
    def __str__(self):
        return str(self.user)
    # class Meta(object):
        # pass
class Account(AbstractOrganization):
    mgr = models.ForeignKey(AccountUser, on_delete=models.DO_NOTHING, blank=True, null=True)
    …
    # Several unrelated methods
    # def number_of_clients(self):
        # return self.vendor_to.filter(vendor=self.pk).count()
class AccountOwner(AbstractOrganizationOwner):
    # acct = models.ForeignKey(Account, on_delete=models.CASCADE, related_name='owner')
    def __str__(self):
        return str(self.organization_user)

    # class Meta(object):
        # pass

The v2 code is most of the commented out lines

+1 seems like the module registry thingy here not working properly. On my case the relationship not created.
CustomOrganization doesnt have attribute owner

I'm seeing the following when running makemigrations

3c3732bc1d26:/app$ ./manage.py makemigrations
SystemCheckError: System check identified some issues:

ERRORS:
core.User: (models.E012) 'unique_together' refers to the nonexistent field 'organization'.
core.User: (models.E012) 'unique_together' refers to the nonexistent field 'user'.
core.User: (models.E015) 'ordering' refers to the nonexistent field, related field, or lookup 'organization'.
core.User: (models.E015) 'ordering' refers to the nonexistent field, related field, or lookup 'user'.

Update:
I was able to get around this issue by changing the order of classes in multiple inheritance.

class User(AbstractUser, AbstractOrganizationUser):
 pass

@bennylope I was trying to upgrade to django-organizations 2.0 for the openwisp-users project but I'm having the same issue as seen above.

Do you have any suggestions on how to fix this? Errors below:

<class 'openwisp_users.admin.OrganizationOwnerAdmin'>: (admin.E002) The value of 'raw_id_fields[0]' refers to 'organization_user', which is not an attribute of 'openwisp_users.OrganizationOwner'.
<class 'openwisp_users.admin.OrganizationOwnerAdmin'>: (admin.E002) The value of 'raw_id_fields[1]' refers to 'organization', which is not an attribute of 'openwisp_users.OrganizationOwner'.
<class 'openwisp_users.admin.OrganizationOwnerAdmin'>: (admin.E108) The value of 'list_display[1]' refers to 'organization', which is not a callable, an attribute of 'OrganizationOwnerAdmin', or an attribute or method on 'openwisp_users.OrganizationOwner'.
<class 'openwisp_users.admin.OrganizationOwnerInline'>: (admin.E202) 'openwisp_users.OrganizationOwner' has no ForeignKey to 'openwisp_users.Organization'.
<class 'openwisp_users.admin.OrganizationUserAdmin'>: (admin.E002) The value of 'raw_id_fields[0]' refers to 'user', which is not an attribute of 'openwisp_users.OrganizationUser'.
<class 'openwisp_users.admin.OrganizationUserAdmin'>: (admin.E002) The value of 'raw_id_fields[1]' refers to 'organization', which is not an attribute of 'openwisp_users.OrganizationUser'.
<class 'openwisp_users.admin.OrganizationUserAdmin'>: (admin.E108) The value of 'list_display[0]' refers to 'user', which is not a callable, an attribute of 'OrganizationUserAdmin', or an attribute or method on 'openwisp_users.OrganizationUser'.
<class 'openwisp_users.admin.OrganizationUserAdmin'>: (admin.E108) The value of 'list_display[1]' refers to 'organization', which is not a callable, an attribute of 'OrganizationUserAdmin', or an attribute or method on 'openwisp_users.OrganizationUser'.
<class 'openwisp_users.admin.OrganizationUserInline'>: (admin.E202) 'openwisp_users.OrganizationUser' has no ForeignKey to 'openwisp_users.User'.
openwisp_users.OrganizationUser: (models.E012) 'unique_together' refers to the nonexistent field 'organization'.
openwisp_users.OrganizationUser: (models.E012) 'unique_together' refers to the nonexistent field 'user'.
openwisp_users.OrganizationUser: (models.E015) 'ordering' refers to the nonexistent field, related field, or lookup 'organization'.
openwisp_users.OrganizationUser: (models.E015) 'ordering' refers to the nonexistent field, related field, or lookup 'user'.

The short of the issue (or one of the issues) above is that in version 2.0 some of these field names/related names are dynamically named to be relevant to the underlying model. E.g. for a model named AccountUser the field name is going to be account_user now instead of organization_user.

Going to have to think through how to either (a) make this more configurable or (b) create a smooth upgrade path.

@bennylope We experienced the same unique_together warnings although we did not use a custom model name like @specialorange. However, after looking at organizations/models.py we decided to also implement the OrganizationInvitation class and poof! all errors were gone.

This is our working model config, if anyone interested:

class Organization(AbstractOrganization):
    class Meta(AbstractOrganization.Meta):
        abstract = False

class OrganizationUser(AbstractOrganizationUser):
    # only allow one org per user
    user = models.ForeignKey(
        User, related_name="%(app_label)s_%(class)s", on_delete=models.CASCADE, unique=True
    )

    class Meta(AbstractOrganizationUser.Meta):
        abstract = False

class OrganizationOwner(AbstractOrganizationOwner):
    class Meta(AbstractOrganizationOwner.Meta):
        abstract = False

class OrganizationInvitation(AbstractOrganizationInvitation):
    class Meta(AbstractOrganizationInvitation.Meta):
        abstract = False

Same here, I'm using custom models based on abstract classes and after upgrading to 2.0.0 I started seeing errors mentioning missing foreignkeys on the OrgOwner or OrgUser models.
Adding a concrete model for invitations (based on AbstractOrganizationInvitation) solved it as suggested by @eelkevdbos (thanks!)

Encountered the same problem. After a bit of digging into the source, the problem is line 104 in base.py, the one goes if all([cls.module_...]):

            if key:
                cls.module_registry[module][key] = model

        if all([cls.module_registry[module][klass] for klass in base_classes]):
            model.update_org(module)
            model.update_org_users(module)

which requires that all the abstract models to be overridden if model customization is required. That is, AbstractOrganization, AbstractOrganizationUser, AbstractOrganizationOwner & AbstractOrganizationInvitation. Only then would the dynamic field name injection mechanism would work. In my case I was not overriding the AbstractOrganizationInvitation initially.

The sample code in the docs here omits the AbstractOrganizationInvitation model.