Django-allauth retrieve avatar profile pictures - django

I use django-rest-auth and django-allauth about user registration/login using user's Facebook profile.
Now, I can take some standard information from Facebook (default for all auth).
Is possible to retrieve also list of avatar-pictures?
How can make it in allAuth?

If you want to get avatar pictures in a django template:
<img src="{{ user.socialaccount_set.all.0.get_avatar_url }}" />
Is that what you were trying to do?

Let me quickly described how i did it (using all_auth and rest_auth).
Basically, 'allauth => socialaccount' provide user_signed_up
and user_logged_in signals. So you need to catch them and get
sociallogin object's extra data and populate your avatar_url.
Step-1: Create a UserProfile model: (to store avatar_url)
#models.py
try:
from django.utils.encoding import force_text
except ImportError:
from django.utils.encoding import force_unicode as force_text
class UserProfile(models.Model):
user = models.OneToOneField(User, primary_key=True, verbose_name='user', related_name='profile')
avatar_url = models.CharField(max_length=256, blank=True, null=True)
def __str__(self):
return force_text(self.user.email)
class Meta():
db_table = 'user_profile'
Step-2: Catch 'user_signed_up' signal and populate `avatar_url'
# signals.py
from allauth.account.signals import user_signed_up, user_logged_in
#receiver(user_signed_up)
def social_login_fname_lname_profilepic(sociallogin, user):
preferred_avatar_size_pixels=256
picture_url = "http://www.gravatar.com/avatar/{0}?s={1}".format(
hashlib.md5(user.email.encode('UTF-8')).hexdigest(),
preferred_avatar_size_pixels
)
if sociallogin:
# Extract first / last names from social nets and store on User record
if sociallogin.account.provider == 'twitter':
name = sociallogin.account.extra_data['name']
user.first_name = name.split()[0]
user.last_name = name.split()[1]
if sociallogin.account.provider == 'facebook':
f_name = sociallogin.account.extra_data['first_name']
l_name = sociallogin.account.extra_data['last_name']
if f_name:
user.first_name = f_name
if l_name:
user.last_name = l_name
#verified = sociallogin.account.extra_data['verified']
picture_url = "http://graph.facebook.com/{0}/picture?width={1}&height={1}".format(
sociallogin.account.uid, preferred_avatar_size_pixels)
if sociallogin.account.provider == 'google':
f_name = sociallogin.account.extra_data['given_name']
l_name = sociallogin.account.extra_data['family_name']
if f_name:
user.first_name = f_name
if l_name:
user.last_name = l_name
#verified = sociallogin.account.extra_data['verified_email']
picture_url = sociallogin.account.extra_data['picture']
user.save()
profile = UserProfile(user=user, avatar_url=picture_url)
profile.save()
Hope this will help you.

In case you don't want to use Django Signals, you can extend DefaultSocialAccountAdapter from allauth.socialaccount.adapter and override populate_user:
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.account.utils import user_field
class CustomSocialAccountAdapter(DefaultSocialAccountAdapter):
def populate_user(self, request, sociallogin, data):
user = super().populate_user(request, sociallogin, data)
try:
picture = sociallogin.account.extra_data['picture']
user_field(user, "profile_photo", picture)
except (KeyError, AttributeError):
pass
return user
Note you should also change DefaultSocialAccountAdapter in settings.py:
SOCIALACCOUNT_ADAPTER = 'some_app.path.to.CustomSocialAccountAdapter'

Related

I am unable to login as an organization in django views

I have requirement to build a crm . In that i have 3 things 1 is super user who is there by default.
Second organization in which I use a foreign key of user because I don't want to create a custom user and re write a lot of things third agent who is user as foreign key and connected to an organization no I want to login as organization in the dashboard if I am using the super user as login credential it is telling me required organization instance if I am login using organization account it is giving error NoReverseMatch at /leads/login_handle
Here is my views.py
login and sign up handle code
def signup_handle(request):
if request.method == "POST":
name = request.POST.get('name')
email = request.POST.get('email')
pass1 = request.POST.get('pass')
pass2 = request.POST.get('re_pass')
pass2 = request.POST.get('re_pass')
check = request.POST.get('agree-term')
if(pass1 != pass2):
return HttpResponse("Babe your passwod does not matches please try again")
else:
x = User.objects.create(email = email,username = email,first_name = name,is_staff = False)
# x = User.objects.create(name,email,pass1)
x.set_password(pass1)
x.save()
y = Organization(user = x,name = name)
y.save()
# print(f"lets verify the data name = {name},{check}")
return HttpResponse("Babe you have successfully created your account")
else:
return HttpResponse("Babe something goes wrong")
def login_handle(request):
if request.method == "POST":
username = request.POST.get('your_name')
password = request.POST.get('your_pass')
# username = email
# print(f"{username} and password is {password}")
user = authenticate(request,username=username,password=password)
if user is not None:
login(request, user)
return redirect('')
else:
return HttpResponse("Babe try again you are not authenticated")
else:
return HttpResponse("babe only post method applicable")
here is my complete models.py file
from ckeditor.fields import RichTextField
from django.db import models
from django.contrib.auth.models import User
from ckeditor.fields import RichTextField
# Create your models here.
class Source(models.Model):
name = models.CharField(max_length=50,blank=True)
def __str__(self):
return self.name
class Followup(models.Model):
created_by = models.CharField(max_length=20,blank=True,null=True)
body = RichTextField(blank = True,null = True)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now_add=True)
class Organization(models.Model):
name = models.CharField(max_length=50,blank=True)
user = models.ForeignKey(User,on_delete=models.PROTECT,blank=True)
def __str__(self):
return self.name
class Agent(models.Model):
name = models.CharField(max_length=20,blank=True)
user = models.ForeignKey(User,on_delete=models.PROTECT,blank=True)
image = models.ImageField(upload_to="Agents/images",blank = True)
organization = models.ForeignKey(Organization,on_delete=models.PROTECT,blank=True,default="")
def __str__(self):
return self.name
class Lead(models.Model):
status = (
("fresh","Fresh"),
("open","Open"),
("closed","Closed"),
("pending","Pending"),
)
closed_by = (
("low_budget","Low Budget"),
("we_cant_do","We Cant Do"),
("client","Client Converted"),
)
pending_by = (
("with_customer","With Customer"),
("with_process","With Process"),
("pending_on_us","Pending On Us"),
)
name = models.CharField(max_length=20,blank=True)
email = models.CharField(max_length=30,default="")
assign_to = models.CharField(max_length=30,default="")
mobile_no = models.IntegerField(blank=True)
subject = models.CharField(max_length=100,blank=True)
message = models.TextField(blank=True)
source = models.CharField(max_length=30,default="")
# source = models.ForeignKey(Source,blank=True,on_delete=models.PROTECT,null=True)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now_add=True)
state = models.CharField(choices=status,max_length=20,blank=True,default="fresh")
closed_by = models.CharField(max_length=15,choices=closed_by,blank=True)
pending_by = models.CharField(max_length=15,choices=pending_by,blank=True)
image=models.ImageField(upload_to="lead/images",blank = True)
def __str__(self):
return self.name
As the first answer says i added a path in redirect now it logged in but not rendering the page
def login_handle(request):
if request.method == "POST":
username = request.POST.get('your_name')
password = request.POST.get('your_pass')
# username = email
# print(f"{username} and pasword is {password}")
user = authenticate(request,username=username,password=password)
if user is not None:
login(request, user)
return redirect('/')
else:
return HttpResponse("Babe try again you are not authenticated")
else:
return HttpResponse("babe only post method applicable")
I am getting the error
Here is my app name home urls.py
urls.py
from django.contrib import admin
from django.urls import path
from home import views
urlpatterns = [
path('',views.index,name="index"),
# create agent
path('create_agent_page',views.create_agent_page,name="create_agent_page"),
path('create_agent',views.create_agent,name="create_agent"),
path('signup_page',views.signup_page,name="signup_page"),
path('login_page',views.login_page,name="login_page"),
path('signup_handle',views.signup_handle,name="signup_handle"),
path('login_handle',views.login_handle,name="login_handle"),
#Lead handleing
path('create_lead',views.create_lead_page,name="create_lead"),
path('follow_up/<int:id>',views.follow_up,name="follow_up"),
path('update_lead/<int:id>',views.update_lead,name="update_lead"),
# path('update_lead',views.update_lead,name="update_lead"),
path('creat_handle_lead',views.creat_handle_lead,name="creat_handle_lead"),
path('lead_list',views.lead_list,name="lead_list"),
]
here is my project urls.py
from django.contrib import admin
from django.urls import path
from django.urls.conf import include
urlpatterns = [
path('admin/', admin.site.urls),
path('leads/', include('home.urls')),
]
return redirect('')
This is wrong. You must do
from django.urls import reverse
return HttpResponseRedirect(reverse('app_name:url_pattern_name'))
or you can specify your url pattern manually
from django.urls import reverse
return HttpResponseRedirect('/dashboard/')

How to associate data sent by a user to his own account in Django

I have a model called KeyFormModel which has 2 fields "secret_key" and "primary_key", I pointed this model towards a form and called this form to a view and template. each user has exactly one primary_key and one secret_key, when I send this to model they are mixing with other keysets
this is my model
class KeyFormModel(models.Model):
username = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
primary_key = models.CharField(max_length=200)
secret_key = models.CharField(max_length=200)
def __str__(self):
return username+"_keys"
class Meta:
verbose_name_plural = 'Keys'
this is my form
from ..models import KeyFormModel
from django import forms
from django.conf import settings
class KeyForm(forms.ModelForm):
primary_key = forms.CharField(required=True)
secret_key = forms.CharField(required=True,widget = forms.PasswordInput)
class Meta:
model = KeyFormModel
fields = ("username","primary_key","secret_key")
this is my view
#cache_control(no_cache=True, must_revalidate=True)
#login_required(login_url='../login')
def AccountView(request):
if(request.method == 'POST'):
form =KeyForm(request.POST)
if(form.is_valid()):
form.save()
else:
for msg in form.error_messages:
messages.error(request,f"{msg}")
form = KeyForm
return(render(request, 'accountView.html',context={"form":form}))
as you can see I am trying to add username from AUTH_USER_MODEL after logging into that account but failing miserably. please hlp
What worked out for me:
import User to models:
from django.contrib.auth.models import User
and in the specific model add user field:
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
)
i found the answer
#cache_control(no_cache=True, must_revalidate=True)
#login_required(login_url='../login')
def AccountView(request):
keyforce=KeyFormModel.objects.filter(user=request.user)
if(keyforce):
return(render(request,'keyView.html',{"keys":keyforce}))
else:
if(request.method == 'POST'):
form = KeyForm(request.POST)
if(form.is_valid()):
primary_key = request.POST['primary_key']
secret_key = request.POST['secret_key']
new = KeyFormModel(primary_key=primary_key,
secret_key=secret_key, user=request.user)
new.save()
return(redirect("main:Account"))
else:
for msg in form.error_messages:
messages.error(request, f'{msg}')
else:
form = KeyForm
return(render(request, 'accountView.html', context={"form": form}))
I learned that the values to the models can be added through views itself,
all I did was something like this
after adding User to your model
in view create
form = yourModel(user = request.user)
voila its done

I cannot save a picture link from a facebook account

I am trying get a picture link from a facebook account but get this message:
django.db.utils.IntegrityError: UNIQUE constraint failed:
user_profile.user_id
I can see a picture link in console, but I cannot save it in user profile.
here is my model.py when I'm trying to do that.
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from allauth.account.signals import user_signed_up, user_logged_in
from allauth.socialaccount.models import SocialAccount
import hashlib
try:
from django.utils.encoding import force_text
except ImportError:
from django.utils.encoding import force_unicode as force_text
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,
related_name='userprofile')
city = models.CharField(max_length=30, blank=True)
about = models.TextField(blank=True)
avatar = models.ImageField(upload_to='avatars/', verbose_name='Images',
blank=True)
sound = models.BooleanField(default=False)
points = models.DecimalField(max_digits=4, decimal_places=2, default=0.00)
energy = models.IntegerField(default=0)
avatar_url = models.URLField(max_length=500, blank=True, null=True)
class Meta:
db_table = 'user_profile'
verbose_name = 'Profile'
verbose_name_plural = 'Profiles'
def __str__(self):
return str(self.user)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.userprofile.save()
##receiver(user_logged_in)
#receiver(user_signed_up)
def set_initial_user_names(request, user, sociallogin=None, **kwargs):
preferred_avatar_size_pixels = 25
if sociallogin:
if sociallogin.account.provider == 'facebook':
picture_url = "http://graph.facebook.com/{0}/picture?width={1}&height={1}".format(
sociallogin.account.uid, preferred_avatar_size_pixels)
profile = UserProfile(user=user, avatar_url=picture_url)
#profile = UserProfile.objects.get(user=user)
#profile.avatar_url = picture_url
profile.save()
If I am doing like that at the end:
#profile = UserProfile(user=user, avatar_url=picture_url)
profile = UserProfile.objects.get(user=user)
profile.avatar_url = picture_url
profile.save()
I am not gettin any message in the console, but user profile doesn't save.
This line profile = UserProfile(user=user, avatar_url=picture_url) is causing the problem as you are trying to create a new instance of profile which already exists. The profile becomes unique because of OneToOne field in your UserProfile model.
And you don't need to get the user from the database because set_initial_user_names function is already passing the registered user to you as a parameter. So just do user.userprofile. Then you can just update the user with new information.
Also I would suggest you to download the picture from the url provided and then save it in your image field of your model like this:
import urllib
from django.core.files import File
# for python 2: result = urllib.urlretrieve(picture_url)[0]
result = urllib.request.urlretrieve(picture_url)[0] # for python 3
user.userprofile.avatar.save('test.jpg', File(open(result, 'rb')))
user.userprofile.save()

Flask_wtf - UnmappedInstanceError: Class is not mapped

I'm building a relatively simple Flask application with a not so simple database. I've a lot of models to handle and relate all the needed information in the DB.
For some reason I'm getting the title error.
I'm starting to think is some how related with my DB models/relationships.
So, the implementation of the models goes as the follow:
from app import db, login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
import datetime
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password = db.Column(db.String(128))
def set_password(self, password):
self.password = generate_password_hash(password)
def check_password(self, passwd):
return check_password_hash(self.password, passwd)
def __repr__(self):
return '<User {}>'.format(self.username)
class airFeedVariator(db.Model):
variatorID = db.Column(db.Integer, db.ForeignKey('variator.id',onupdate='RESTRICT',ondelete='RESTRICT'), primary_key=True)
airFeedID = db.Column(db.Integer, db.ForeignKey('air_feed.id',onupdate='RESTRICT',ondelete='RESTRICT'), primary_key=True)
variatorRel = db.relationship('Variator', backref='variators',lazy='joined')
freq = db.Column(db.Integer)
class Variator(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30))
machineID = db.Column(db.Integer)
baudrate = db.Column(db.Integer)
addedAt = db.Column(db.DateTime, default=datetime.datetime.utcnow) # the current timestamp
class Air_feed(db.Model):
id = db.Column(db.Integer, primary_key=True)
timeOn = db.Column(db.Integer)
timeOff = db.Column(db.Integer)
desc = db.Column(db.String)
digital = db.relationship('Pin_function', backref='analog_or_digital', lazy=True)
airFeedTypeId = db.relationship('Air_feed_type', backref='air_feed_type_id', lazy=True, uselist=False) #This allow the usage for a single element. 1-1 Rel.
#variators = db.relationship('Variator', secondary=airFeedVariator, lazy='subquery',backref=backref('airfeedvariators', lazy=True))
variators = db.relationship('airFeedVariator', lazy='dynamic')
And the forms goes as:
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField, IntegerField, DateTimeField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
from flask_babel import lazy_gettext as _l #compile in runtime only.
#Utilizado para converter directamente os modelos em forms.
#from wtforms_alchemy import ModelForm
from app import models
from wtforms_alchemy import model_form_factory
BaseModelForm = model_form_factory(FlaskForm)
class ModelForm(BaseModelForm):
#classmethod
def get_session(self):
print('Session: ', db.session)
return db.session
class LoginForm(FlaskForm):
username = StringField(_l('Utilizador'), validators=[DataRequired()])
password = PasswordField(_l('Password'), validators=[DataRequired()])
remember_me = BooleanField(_l('Lembrar-me'))
submit = SubmitField(_l('Submeter'))
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
password2 = PasswordField(
'Repetir Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField(l_('Registo'))
#Validate on submit check for this. The rise allow to write a message directly on the webpage!
def validate_username(self, username):
user = models.User.query.filter_by(username=username.data).first()
if user is not None:
raise ValidationError(_l('Utilizador já existente!'))
def validate_email(self, email):
user = models.User.query.filter_by(email=email.data).first()
if user is not None:
raise ValidationError(_l('Email já existente!'))
class VariatorForm(FlaskForm):
name = StringField(_l('Nome'), validators=[DataRequired()])
machineID = IntegerField(_l('Identificador'), validators=[DataRequired()])
baudrate = IntegerField(_l('Valocidade Comm'), validators=[DataRequired()])
addedAt = DateTimeField(_l('Preenchimento automatico')) # the current timestamp
def validate_machineID(self, machineID):
user = models.Variator.query.filter_by(machineID=machineID.data).first()
if user is not None:
raise ValidationError(_l('Já existente um variador registado neste endereço!'))
I do realize that I have a FlaskForm form and ModelForm on the others, I was just testing.
My problem is the following:
File "c:\app\routes.py", line 49, in SaveVariator
db.session.add(var) File "c:\gburner\lib\site-packages\sqlalchemy\orm\scoping.py", line 153, in do
return getattr(self.registry(), name)(*args, **kwargs) File "c:\gburner\lib\site-packages\sqlalchemy\orm\session.py", line 1833, in add
raise exc.UnmappedInstanceError(instance) sqlalchemy.orm.exc.UnmappedInstanceError: Class 'app.forms.VariatorForm' is not mapped
* Added Problatic route.py part *
#app.route('/savevariator', methods=['POST'])
def SaveVariator():
var = VariatorForm(request.form)
if var.validate_on_submit():
print('Variator form submit accepted!')
### I was doing this ### Trying to add the FORM to the session!
db.session.add(var)
db.session.commit()
#############################
### INSTEAD I Should be doing this: ######
variator = Variator(name=var.name, machineID=var.machineID, baudrate=var.baudrate)
db.session.add(variator)
db.session.commit()
##############################
resp = jsonify(success=True)
else:
print('Variator form submit NOT accepted!')
resp = jsonify(success=False)
return resp
I think html code would not be necessary since everything works fine until the moment where the call to save information on database happens.
Am I missing something regarding the mapping relationship in database because I have 3 tables for a many to many relationship?
Any help solve the problem would greatly appreciated.
Thank you.
* EDIT *
Thanks to Joost for point me this simple yet difficult to realize point! (I probably should pause more often).
The problem was in the route section:
#app.route('/savevariator', methods=['POST'])
def SaveVariator():
var = VariatorForm(request.form)
if var.validate_on_submit():
print('Variator form submit accepted!')
### I was doing this ### Trying to add the FORM to the session!
db.session.add(var)
db.session.commit()
#############################
### INSTEAD I Should be doing this: ######
variator = Variator(name=var.name, machineID=var.machineID, baudrate=var.baudrate)
db.session.add(variator)
db.session.commit()
##############################
resp = jsonify(success=True)
else:
print('Variator form submit NOT accepted!')
resp = jsonify(success=False)
return resp
Thanks to Joost I was able to understand where the problem was. Thanks again!
I realize it's a simple mistake, but I couldn't find much information regarding the error and solution. However if the admins decide it's not worth to keep, feel free to remove it.
Thank you.

Django: text-input instead selection on foreignkey

I want to create a messaging function in ma django app. User should be able to write other users a textmessage.
models.py
from django.contrib.auth.models import User
class Message(models.Model):
recipient = models.ForeignKey(User, null=True)
contentDescription = models.CharField(max_length=1000, null=True)
By default, with no forms.py entry I get a selection, which will be unuseful with many users. I want the message sender to type in the user name, or in the first step the user id (which I could resolve with ajax from the name) .
Integer
But with forms.py
recipient = forms.IntegerField( widget=forms.NumberInput , required=False,)
I get:
Cannot assign "11": "Transport.recipient" must be a "User" instance.
ChoiceField and NumberInput
with:
recipient = forms.ChoiceField( widget=forms.NumberInput, required=False,)
I get the error message "not valid"
Is it possible to write the foreignkey 'manually' at all?
Try this:
recipient = forms.ModelChoiceField(queryset=User.objects.all(), widget=forms.Select, required=False)
considering your
models.py -
from django.contrib.auth.models import User
class Message(models.Model):
recipient = models.ManytoMany(User, null=True)
contentDescription = models.TextField()
forms.py
from .models import Message
from django import forms
from django.contrib.auth.models import User
class MailForm(forms.ModelForm):
recipient = forms.Charfield()
class Meta:
model = Message
fields = ('contentDescription',)
def clean_recipient(self):
user_list = self.cleaned_data.get('recipient')
# considering you post user_list of usernames as 'username1,username2,username3'
if user_list is not None:
user_list = user_list.split(',')
user_qs = User.objects.filter(username__in=userlist)
else:
raise forms.ValidationError('Error in this field')
return user_qs
def save(self, user_qs):
self.instance.user = user_qs
return super().save()
in views.py -
from .forms import MailForm
def your_view(request):
form = MailForm(request.POST or None)
if form.is_valid():
user_qs=form.cleaned_data.get('recipient')
form.save(user_qs)
#return render here
else:
#create your context here and return render
This is not perfect but can give you an idea how to implement. With the details you gave this is the best I can do for now.