2
2

Hi,

I want to install OSQA in a Django site with an existing user base. OSQA's (or its predecessor's) decision to inherit from django.contrib.auth.models.User makes this a bit of a hassle. How did others solve this?

The ExtendedUser middleware simply bails out if there isn't an OSQA-ified user instance:

try:
    request.user = request.user.user
    # ...
except Exception, e:
    import traceback
    logging.error("Unable to convert auth_user %s to forum_user: \\n%s" % (
        request.user.id, traceback.format_exc()
    ))

I'm thinking about modifying the ExtendedUser middleware to create an OSQA-User if none exists for the request.user:

except OSQAUser.DoesNotExist:
    osqa_user = OSQAUser(user_ptr_id=request.user.pk)
    osqa_user.save()
    request.user = osqa_user

Are there any unwanted side-effects to be expected from this? What solutions have others come up with to integrate OSQA with an existing user base?

asked 31 Oct '10, 05:41

piquadrat's gravatar image

piquadrat
51127
accept rate: 0%


If you trust the users in the existing user base, then it is a perfect solution.

link

answered 31 Oct '10, 10:41

Hernani%20Cerqueira's gravatar image

Hernani Cerq... ♦♦
16.8k65975
accept rate: 52%

We'll use OSQA as an internal support forum and only employees have access. Trust is not an issue :-) thanks!

(31 Oct '10, 11:47) piquadrat

Well, that didn't work so good. This solution has all kind of nasty side-effects, like the LDAP authentication backend creating new users all the time instead of authenticating existing ones... I don't want to appear dickish as a new user, but there's a reason that several Django core devs are on record advising against inheriting from User.

/edit: I think I managed to hack my way around this problem:

except OSQAUser.DoesNotExist:
    data = request.user.__dict__
    data['pk'] = data['id']
    data['user_ptr_id'] = data['id']
    for field in ('id', '_state', 'ldap_user', 'ldap_username',):
        if field in data:
            del data[field]
    u = OSQAUser(**data)
    u.save()
    SubscriptionSettings.objects.get_or_create(user=u)
    request.user = u
    return None
link

answered 31 Oct '10, 15:52

piquadrat's gravatar image

piquadrat
51127
accept rate: 0%

edited 31 Oct '10, 17:37

Although all that is true, there's a reason for us to do that. We inherited code that was monkeypatching the User model (even worst), and this was the easy workaround without huge refactorings, cause there was already several active OSQA sites. And your LDAp problem has nothing to do with it. If you browse around this site a bit, you'll see several threads explaining the easiest way to create authentication backends and connecting existing user bases with OSQA, without duplicating users. piquadrat thing is a bit different, and he'll hardly have that duplicated users problem.

(31 Oct '10, 20:52) Hernani Cerq... ♦♦

my LDAP problem was a symptom of my incorrect code from the original post: OSQAUser(user_ptr_id=42).save() overwrites all the fields of the original user with empty/default values. Next time the LDAP backend sees the user (which has now a username of ''), it creates a new User.

I understand that OSQA inherited this problem from CNProg. But that doesn't change the fact that inheriting from User opens a huge can of worms.

(01 Nov '10, 02:47) piquadrat

Can you give an example of such "worms"?

(01 Nov '10, 08:20) Hernani Cerq... ♦♦
  • you can't use two 3rd party apps that both extend Django's User
  • you have to use dirty hacks like the above one to "downcast" existing users
  • code that expects request.user to be an instance of Django's User may fail in interesting ways

It's simply common practice to use something akin to a profile model to persist custom data that relates to the User model. Apps that deviate from that common practice are hard to integrate into existing Django installs.

(01 Nov '10, 09:42) piquadrat
  • So you can't use two "badly" behaved apps, seems fair.
  • In your "dirty hack" you were not downcasting a user, rather "upgrading" it if you will, which wouldn't be necessary, if you're not trying to integrate OSQA with other django apps. OSQA is not meant to follow the philosophy of reusable django apps. So I guess you shouldn't expect to make that integration seamlessly.
  • Code that expects a auth.User, or a request.useras you call it and fails if it finds a forum.user is pure weirdness, it goes against a bunch of "philosophies" since everyone seems to care so much about that:

(continues in the next comment)

(01 Nov '10, 11:56) Hernani Cerq... ♦♦
  • The so beloved python "duck typing" phylosophy, used intensively throughout the python core.
  • The "object oriented" philosophy, where something that expects an object of class A, fails if it receives an object of a class that extends A.
  • Finally, to verify that an object is of type auth.User and only auth.User and not inherited, you would have to compare the class name, and the class module, such as if user.__class__.__name__ == 'User' and <code to verify the module here>. Talking about ugly hacks.

Bottom line, these kind of "recommendations" are cool, but they are also meant to be broken sometimes, don't follow them dogmatically or you will catch yourself stuck sometimes.

(01 Nov '10, 11:57) Hernani Cerq... ♦♦

Well, Hernâni - what is your recommendation then to the original question? What is the best way to integrate with existing users?

(02 Nov '10, 10:14) Snaky Love

Its specific to each problem. I don't even have a clue of what are you trying to accomplish here.

(02 Nov '10, 10:20) Hernani Cerq... ♦♦

I'd be curious too,cause we're interested in rolling out OSQA to an existing user base.

Do you guys have any tips or advice on the best way to proceed ?

Our current set-up does not extend User but has a FK to User and set as AUTH_PROFILE_MODULE

(11 May '11, 06:48) philgo20
showing 5 of 9 show 4 more comments
Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "title")
  • image?![alt text](/path/img.jpg "title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Tags:

×45
×14

Asked: 31 Oct '10, 05:41

Seen: 887 times

Last updated: 11 May '11, 06:48

powered by OSQA