Pre-filled user info in Django Comments? - django

The site I'm building uses the standard user management framework and
the standard comments framework.
What I'd like to see happen is the comments form rendered with the
user's name and email address pre-filled if they are already signed in
(or have the fields hidden entirely - kinda like theregister's comments system!).
Easy enough?

If you want to use django-comments with logged-in users, the post_comment does already populate some fields right when being authenticated, you just need to make some tweaks. There are some instructions on how to do that!

If user are signed in, you can use something like this in your view:
user = request.user
profile = user.get_profile()
if request.method == 'POST':
edit_form = YourForm(data = request.POST, user = user)
if edit_form.is_valid():
...
else:
dict = {'email':user.email, 'username':user.username}
form = YourForm(user = user, data = dict)
tpl_dict = {'form' : form,}
return render_to_response('template.html', tpl_dict)
it will fill the form fields 'username' and 'email'

When I'm signed into my django site it automatically loads my username and email address.

Related

How to update user profile in django properly

i created a form to update a django profile, i use the default user model, when i submit the form and logout and i tried to login again, the new password is not working, but the old one is.
this is my update view :
def edit_profil_to_base(request):
if not request.user.is_authenticated:
return redirect('authentification')
else:
nom_profil_new = request.POST.get('nom_profil')
nom_profil_old = request.user.username
old_mdp = request.POST.get('old_mdp') # type: object
new_mdp = request.POST.get('new_mdp')
final_mdp = request.POST.get('final_mdp')
mdp = request.user.set_password(new_mdp)
if request.user.check_password(old_mdp) and new_mdp == final_mdp:
User.objects.filter(username=nom_profil_old).update(username=nom_profil_new, password=mdp)
logout(request)
return redirect('authentification')
the new_mdp and final_mdp are the new password and the confirmation of the password
You need to use set_password. You can't do this via update, but you don't need to: you already have the actual object, request.user.
user = request.user
if user.check_password(old_mdp) and new_mdp == final_mdp:
user.username = nom_profil_new
user.set_password(mdp)
user.save()
However, you really should be using a ModelForm for all of this.

Many to many - proper usage

I have models like this:
User:
#somefields
apps = models.ManyToManyField(App)
Here, User is created initially during registration. He links apps using many to many in a separate page where user selects(multiple) only apps, no other fields.
What is the best way to populate apps in Django ?
For example, if we can create User also, we can simply use modelform where .save(commit=False) will create user and .save_m2m() will link apps. But here we dont need to create User. We will be having user already, we only need to add apps. How ?
Newly added details:
I know how to do with normal "form" and normal web way. But I want to write quality code so want to know. If there is nothing wrong in using normal form then its fine.
There are multiple ways to do it, but for example:
class UserAppForm(ModelForm):
class Meta:
model = User
fields = ['apps']
And in your view, you configure the routing so that you can:
Get the ID of the user to select
Raise an error if you do not find the ID (Instead of creating a new one)
Initialize the form with the user
For example:
def user_add_app(request, pk):
user = get_object_or_404(User, pk=pk)
if request.method == "POST":
form = UserAppForm(request.POST, instance=user)
if form.is_valid():
user = form.save()
return HttpResponseRedirect(<some redirect>)
else:
form = EmployeeForm(instance=user)
return render(request, "<some html file>", {'form': form})
Maybe I did not fully understand the question (Please clarify if it's not the case), but there is no problem having two forms on the same model:
One form to create the User, without selecting apps (Which will be empty)
One form to add Apps to the User, taking into account that it already exists (And is not created at this time).
Does it answer the question ?
You can create a ModelForm form with model = App and a User field. Now when creating the form set an initial value for User :
form = AppForm(initial={'user': 1})

django session key error for my simple captcha form

I just write a simple captcha for my login form.
I just add a simple session data.request.session['captcha'].
This is the login views function:
login (request):
if request.method =='GET':
form = LoginForm(auto_id=True)
a = random.randrange(1,10,1)
b = random.randrange(10,20.1)
request.session['captcha1']=a
request.session['captcha2']=b
return render_to_response('login.html',locals(),context_instance=RequestContext(request))
if request.method =='POST':
form = LoginForm(data=request.POST)
if form.is_valid():
captcha= request.POST.get('captcha','')
result = request.session.get('captcha1') + request.session.get('captcha2')
if captcha==result:
data = form.clean()
user=authenticate(username= data['username'],password = data['password'])
if user is not None:
auth_login(request,user)
return HttpResponseRedirect('/')
else:
form = LoginForm(auto_id=True)
return render_to_response('login.html',locals(),context_instance=RequestContext(request))
This is the login form
class LoginForm (forms.Form):
username = forms.CharField(
label='username')
password =forms.CharField(
label='password',widget = forms.PasswordInput())
captcha = forms.CharField(label='spam chercker')
I get keyerror for captcha1, captcha2, and when I add print request.session['captcha1'], it shows None. That means, when POST, I do not get the django session data, there is no data captcha1 and captcha2
How can I store the data in django session, and pass it to the POST method, and in other views function?
thanks
Instead of taking this approach, you might also want to look at existing Django captcha packages:
https://www.djangopackages.com/grids/g/captcha/
If you're looking for something simple, Django-Simple-Captcha is a great option.

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:
User submits a message through the form
User is asked to authenticate their Twitter account on hitting "Submit" button
User's message, Twitter name, Twitter screen_name, profile_image_url and followers_count are saved in the database (I'm using Heroku Postgres)
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!
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.

Force a form field to be populated in Django

I'm using Django 1.4 with Python 2.7 and Ubunutu 12.04.
I have a form that will update a user's profile. The last item in the form is the password. I pre-populate the form with the existing user's data. The password field does not get pre-populated - and that's fine.
The problem is that when I "save" the data it overwrites the password to be a null or empty field (I can't tell which). Bad.
What can I do to prevent this?
I've tried to make it a required field (forms.py):
password = forms.CharField(widget = forms.PasswordInput(), required = True)
Didn't work.
I've tried to check that the password is not None before updating it (views.py):
if (request.POST.get('password') is not None):
user.set_password(request.POST.get('password'))
Didn't work.
Does an empty form value come back as None? If not, what does it come back as and how can I check if it's empty?
EDIT 1:
I updated my one of my views to check for validation - maybe I did this wrong?
#login_required
def profile(request):
"""
.. function:: profile()
Provide the profile page, where it can be updated
:param request: Django Request object
"""
if request.user.is_authenticated():
user = User.objects.get(username = request.user.username)
user_dict = createUserProfileDict(user)
form = ProfileForm(initial = user_dict);
data = { 'user' : request.user }
data.update({ 'form' : form })
data.update(csrf(request))
if form.is_valid():
return render_to_response("profile.html", data)
Now I receive the following error:
The view rsb.views.profile didn't return an HttpResponse object.
So, it appears my form is not valid? How can I find out why?
Here is the update_profile view:
#login_required
def update_profile(request):
"""
.. function:: profile()
provide the profile page
:param request: Django Request object
"""
if request.user.is_authenticated():
user = User.objects.get(username = request.user)
user.first_name = request.POST.get('first_name')
user.last_name = request.POST.get('last_name')
user.email = request.POST.get('email')
if (request.POST.get('password') is not None):
user.set_password(request.POST.get('password'))
user.save()
# Update the additional user information tied to the user
user_info = UserProfile.objects.get(user_id = user.id)
user_info.company_name = request.POST.get('company_name')
user_info.client_type = request.POST.get('client_type')
user_info.address1 = request.POST.get('address1')
user_info.address2 = request.POST.get('address2')
user_info.city = request.POST.get('city')
user_info.state = request.POST.get('state')
user_info.country = request.POST.get('country')
user_info.zip_code = request.POST.get('zip_code')
user_info.phone_number = request.POST.get('phone_number')
user_info.save()
return profile(request)
First of all, remember to control if your form "is_valid()"
To theck if your form has been submitted with empty values or not, use
MyForm.has_changed()
too bad this is not a documented functionality :(
If you want a default password, i suggest you check if the field is valid then use something like
''.join([choice(string.letters + string.digits) for i in range(7)])
to generate a new password for the user (range(7) is the length you want). Then use an opt-in method (see: send a user an email with his temporary password)
edit based on new context:
from the django docs:
If a Field has required=False and you pass clean() an empty value,
then clean() will return a normalized empty value
rather than raising ValidationError.
For CharField, this will be a Unicode empty string.
For other Field classes, it might be None. (This varies from field to field.)
That's it, your password field should have required=False, so you can treat that as an empty string
Then in your view you could do:
if input_password != '' and input_password != saved_password:
saved_password = input_password
It's just pseudocode, but it should give you a clear idea