Jess
Jess

Reputation: 1849

Using twython-django to authenticate a user when they submit a form

I'm building a Django app and am trying to use twython-django to authenticate a Twitter user when they submit a form. I have tried to edit my views.py, urls.py and models.py files as suggested by this example https://github.com/ryanmcgrath/twython-django/tree/master/twython_django_oauth but I'm simply guessing at it so I'm sure that's why it isn't working.

Could you please help me out with how to get this working? I'm completely new to Twitter wrappers so any help would very much be appreciated.

The flow I'm trying to achieve:

  1. User submits a message through the form
  2. User is asked to authenticate their Twitter account on hitting "Submit" button
  3. User's message, Twitter name, Twitter screen_name, profile_image_url and followers_count are saved in the database (I'm using Heroku Postgres)
  4. User's profile image, name, screen_name and message are printed to index.html in a (Twitter-like) feed.

My views.py:

 def logout(request, redirect_url=settings.LOGOUT_REDIRECT_URL):
     django_logout(request)
     return HttpResponseRedirect(request.build_absolute_uri(redirect_url))

 def submit(request):
     twitter = Twython(
         twitter_token=settings.TWITTER_KEY,
         twitter_secret=settings.TWITTER_SECRET,
         callback_url=request.build_absolute_uri(reverse('alpha.views.submit'))
)

auth_props = twitter.get_authentication_tokens()

request.session['request_token'] = auth_props
return HttpResponseRedirect(auth_props['auth_url'])

form = MessageForm(request.session.get('message'))
if form.is_valid():
    new_message = form.save()
    return HttpResponseRedirect('/')
else:
    request.session['message'] = request.POST

twitter = Twython(
        twitter_token = settings.TWITTER_KEY,
        twitter_secret = settings.TWITTER_SECRET,
        oauth_token = request.session['request_token']['oauth_token'],
        oauth_token_secret = request.session['request_token']['oauth_token_secret'],
)

authorized_tokens = twitter.get_authentication_tokens()

try:
    user = User.objects.get(username = authorized_tokens['screen_name'])
except User.DoesNotExist:
        user = User.objects.create_user(authorized_tokens['screen_name'], authorized_tokens['oauth_token_secret'])
        profile = Message()
        profile.user = user
        profile.name = name
        profile.profile_image_url = profile_image_url
        profile.oauth_token = authorized_tokens['oauth_token']
        profile.oauth_secret = authorized_tokens['oauth_token_secret']
        profile.save()

user = authenticate(
        username = authorized_tokens['screen_name'],
        password = authorized_tokens['oauth_token_secret']

)
login(request, user)
return HttpResponseRedirect(redirect_url)

Disclaimer: I'm a newbie so the above code is probably a complete mess!

Upvotes: 1

Views: 693

Answers (1)

Andee
Andee

Reputation: 793

Yes, your use-case is different from that intended by twython-django, but that doesn't mean it's not going to work in your case, and you can use the library as it stands with your flow. After setting up everything as described on the main page, you'll need something like this for your views.py:

from django.shortcuts import redirect, reverse

def submit(request):
    # initial form submission, first check if we're authenticated
    # if we are, process as normal, otherwise redirect to the login
    # page. If you've set up twython-django correctly, it'll redirect
    # to twitter for the actual login.
    if request.method == "POST":
        if request.user.is_authenticated():
            form = MessageForm(request.POST)
            if form.is_valid():
                form.save()
                return redirect('/')
            else:
                # Modify this to display validation errors
                pass
        else:
            request.session['message'] = request.POST
            # the reverse(submit) resolves this view for redirection
            # back from the twitter authentication
            return redirect(settings.LOGIN_URL, next=reverse(submit))

    # A Get request, where we should first check for the message stored
    # We then process the form and remove it from session to prevent
    # accidental re-use.
    else:
        if 'message' in request.session and request.user.is_authenticated():
            form = MessageForm(request.session['message'])
            del request.session['message']
            if form.is_valid():
                form.save()
                return redirect('/')
            else:
                # Modify this to display validation errors
                pass
        else:
            # handle the case where this is a get request and the variable
            # isn't in session
            pass

As for loading their profile image and follower count, those are not currently handled at all by twython django. You can either fork it on github and add them to the TwitterProfile model and add the appropriate code to the thanks view to load those too, or you can add a new model to your code which extends TwitterProfile.

from twython_django_oauth.models import TwitterProfile
from django import models

class ExtendedTwitterProfile(models.Model)
    profile = models.OneToOne(TwitterProfile, related_name="extended")
    avatar = models.CharField(max_length=255)
    followers = models.IntegerField()

And add the code into the submit view to add/update the profile as needed.

extended_profile = ExtendedTwitterProfile.objects.get_or_create(profile=request.user.twitterprofile)
extended_profile.avatar = avatarurl
extended_profile.followers = followercount

extended_profile.save()

You should be able to access those details via

user.twitterprofile.extended.avatar

Although, I have in the past used a url to get the avatar, for example:

# avatar redirection urls
url(r'^avatar/(?P<userid>[0-9A-Za-z_]+)$', redirect_to,
    { 'url' : 'http://api.twitter.com/1/users/profile_image/%(userid)s.json' }, name='avatar' ),    
url(r'^avatar/(?P<userid>[0-9A-Za-z_]+)/(?P<size>[a-z]+)$', redirect_to, 
    { 'url' : 'http://api.twitter.com/1/users/profile_image?screen_name=%(userid)s&size=%(size)s' } ),

In a template where you want to display the avatar, you simply use and img tag using the url template tag to do the reverse url resolution, like so:

<img src="{% url avatar userid=request.user.username %}" />

As a further pointer, you can also request all of the users' basic details via Twitter's json API

https://twitter.com/users/zandeez.json

For example, will get you my public profile in a form you can use either in python using urllib or even javascript/ajax depending on what you want to do with the follower count.

Hopefully that should get you sorted, if you need any more help fell free to ask.

Upvotes: 1

Related Questions