1

I am relatively new to Django and I'm trying to achieve something that is not quite clear in the documentation. My application requires multiple types of users. So, I have extended django User, creating a Profile model that contains additional fields common in all User types:

USER_TYPES = (
    ('A', 'UserTypeA'),
    ('B', 'UserTypeB'),
    ('C', 'UserTypeC'),
)

class Profile(models.Model):
    user = models.OneToOneField(User, unique=True)
    about = models.TextField(blank=True)
    user_type = models.CharField(max_length=3, choices=USER_TYPES, default='A')

    def save(self, *args, **kwargs):
        try:
           existing = Profile.objects.get(user=self.user)
           self.id = existing.id #force update instead of insert
        except Profile.DoesNotExist:
           print "Profile not created yet"
        models.Model.save(self, *args, **kwargs) 

def create_user(sender, instance, created, **kwargs):
    print "User Profile Creation: False"
    if created:
        print "User Profile Creation: ", created
        Profile.objects.create(user=instance)

post_save.connect(create_user, sender=Profile)

In settings.py I have set:

AUTH_PROFILE_MODULE = 'users.Profile'

After that i have defined my UserTypeX models deriving from Profile models like this:

class UserTypeA(Profile):
    phone_number = models.CharField(max_length=13,blank=False)

class UserTypeB(Profile):
    company_name = models.CharField(max_length=30,blank=False)
    phone_number = models.CharField(max_length=13,blank=False)

    def __init__(self, *args, **kwargs):
        kwargs['user_type'] = 'B'
        super(UserTypeB, self).__init__(*args, **kwargs)

...

I've registered those user models to admin so that I could manage my users independently.

The default admin behavior displays correctly all the Profile and UserTypeX fields and there is a select box (with a plus button next to it) for the User field - due to the OneToOneField relationship between Profile and User models. So whenever I want to create a new UserTypeX, I have to press the plus button and fill in a new popup window all the default User django defined fields.

What I am struggling to do now is display those User fields, not in a new popup window but inline in my UserTypeX add/edit page. I've read the documentation about StackedInlines and TabularInlines but those doesn't fit my case because I want to inline parent fields in an ancestor's add/edit page and not vice versa.

Is there any suggested solution with example code (please!) for that problem? Thank's in advance!


So, to make things short, is there a way to display User fields (instead of the select/add functionality due to OneToOneField relationship) in Profile add/edit screen in admin?


Update: A related question (unanswered though...) that briefly addresses the problem is:

Reverse Inlines in Django Admin

Community
  • 1
  • 1
  • 1
    Any reason you are not defining `Profile` as an abstract model? – miki725 Oct 10 '12 at 11:21
  • @miki725 not really, I was just experimenting with registering Profile model in admin and trying to display User fields in that too, to see if it works. Thank's for noticing! Any idea about the answer to my question? – Jack Sparrow Oct 10 '12 at 11:30

2 Answers2

1

No, you cannot. But you can make B inline in A if you want. Or maybe you can manipulate how django display it in

def unicode(self):

models.py

class A(models.Model):
    name = models.CharField(max_length=50)
    def __unicode__(self):
        return self.name

class B(models.Model):
    name = models.CharField(max_length=50)
    a = models.ForeignKey(A)

admin.py

class B_Inline(admin.TabularInline):  
    model = B
class A_Admin(admin.ModelAdmin):
    inlines = [
        B_Inline,
    ]
admin.site.register(A, A_Admin)
admin.site.register(B)

Or maybe you want to use many-to-many relationship?

models.py

class C(models.Model):
    name = models.CharField(max_length=50)
    def __unicode__(self):
        return self.name
class D(models.Model):
    name = models.CharField(max_length=50)
    cs = models.ManyToManyField(C)

admin.py

class C_Inline(admin.TabularInline):  
    model = D.cs.through
class D_Admin(admin.ModelAdmin):
    exclude = ("cs",)
    inlines = [
        C_Inline,
    ]
admin.site.register(C)
admin.site.register(D, D_Admin)
wanjijul
  • 252
  • 3
  • 7
0

I don't see how this is going to work - you have told django to use users.Profile as your profile model but you actually want to use it's children. Plus as you say you're wanting to use the inline forms the "wrong way around". Without knowing more about what exactly you're trying to achieve I'd suggest that you could fix the inline form issue by defining a custom view to edit the user details rather than using django admin. As for the different profile types - I'd suggest just defining a profile type field in the model and then hiding/showing different fields/properties depending on its value

scytale
  • 12,346
  • 3
  • 32
  • 46
  • If i don't miss something really important I can't have multiple profiles specified in AUTH_PROFILE_MODULE in settings.py. If you know a way around I would be really pleased to know. Inline forms is not a solution, I just mentioned them as a way to write down what I've already tried. I thought there was a simple way to achieve what I want with django admin without having to implement a whole new admin interface, because there are othel models also used in my application and their management is easy there. – Jack Sparrow Oct 10 '12 at 11:44
  • Also, the idea with having a profile type field has been already taken into consideration (user_type field in Profile model). But I don't want to have all my users listed under "Profile" in admin. I need them to be different registered models for easy management. Thank's for your quick response though! – Jack Sparrow Oct 10 '12 at 11:48
  • you don't need to implement a whole new admin interface. you can still use django's admin interface for most of your models - but if you want the control you desire over Users/Profiles you'll need to write a custom view just for that. – scytale Oct 10 '12 at 12:09
  • I'm currently trying to add my custom template by extending default django change_form.html template. I thought it would be easy to achieve the default functionality by defining ModelForms for my UserTypeX models and maybe using formsets to have all the fields inline. To no success until now. I think that either I am missing something or there are many extra variables that should be passed to my custom template. Is there any good example implementation that you could recommend? Thank's again for your effort! – Jack Sparrow Oct 10 '12 at 16:23
  • Um... not off the top of my head - every project is too different... you should just ask a new question about your formset problem. oh and please accept my answer if it's been of use to you. – scytale Oct 10 '12 at 20:46
  • No I don't believe that there is a way to display the User objects in inline formsets in the Profile page. At least without some hacking of the admin site internals. It looks like someone has tried it - http://stackoverflow.com/a/3459436/473285 - this will probably need modification for your case. If you're hoping for input from others i'd suggest asking a new question about the general case (and don't introduce the side issue of different types of child model) since this question is now somewhat old. – scytale Oct 11 '12 at 10:28