I am following this tutorial
the aim to verify email after users register to the system. here is the code.
serializers.py
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(
max_length=68, min_length=6, write_only=True)
default_error_messages = {
'username': 'The username should only contain alphanumeric characters'}
class Meta:
model = User
fields = ['email', 'username', 'password']
def validate(self, attrs):
email = attrs.get('email', '')
username = attrs.get('username', '')
if not username.isalnum():
raise serializers.ValidationError(
self.default_error_messages)
return attrs
def create(self, validated_data):
return User.objects.create_user(**validated_data)
my view.py
class RegisterView(generics.GenericAPIView):
serializer_class = RegisterSerializer
def post(self, request):
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
user_data = serializer.data
user = User.objects.get(email=user_data['email'])
token = RefreshToken.for_user(user).access_token
current_site = get_current_site(request).domain
relativeLink = reverse('email-verify')
absurl = 'http://' + current_site + relativeLink + "?token=" + str(token)
email_body = 'Hi ' + user.username + \
' Use the link below to verify your email \n' + absurl
data = {
'email_body': email_body ,
'to_email': user.email ,
'email_subject' : 'Verify your email'
}
Util.send_email(data)
return Response(user_data , status=status.HTTP_201_CREATED)
my utils.py
class EmailThread(threading.Thread):
def __init__(self, email):
self.email = email
threading.Thread.__init__(self)
def run(self):
self.email.send()
class Util:
#staticmethod
def send_email(data):
email = EmailMessage(
subject=data['email_subject'], body=data['email_body'] , to=[data['to_email']])
EmailThread(email).start()
and the settings.py
EMAIL_USE_TLS = True
EMAIL_HOSTS = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_HOST_USER = "talibdaryabi#gmail.com"
EMAIL_HOST_PASSWORD = "**********"
when I test the URL http://127.0.0.1:8000/auth/register/
by providing
{
"email":"talibacademic#gmail.com",
"username":"talibacademic",
"password":"aahg786ahg786"
}
I get the
{
"email": "talibacademic#gmail.com",
"username": "talibacademic"
}
which means the user was created but can't receive email.
can anyone help me with the issue, I also have allowed Less secure app access setting for talibdaryabi#gmail.com account.
In your settings.py, you need to define EMAIL_BACKEND,
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = youremail
EMAIL_HOST_PASSWORD = ****
EMAIL_USE_TLS = True
Note:
It's better to store your credentials in environment variables.
Related
I have a CustomUser model, using django's auth for authentication, and a custom signup view. In the signup form I have some validation to check that the email_suffix (domain of the email) matches with the district that they select in the form. I also check that the email is unique.
When running a test on this, I get an error on the form:
raise MultiValueDictKeyError(key)
django.utils.datastructures.MultiValueDictKeyError: 'district'
Model
class CustomUser(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
is_student = models.BooleanField('student status', default=False)
is_teacher = models.BooleanField('teacher status', default=False)
SD23 = 'SD23'
SD39 = 'SD39'
SD67 = 'SD67'
SDISTRICT = [
(SD23, 'Kelowna SD23'),
(SD39, 'Vancouver SD39'),
(SD67, 'Summerland SD67'),
]
district = models.CharField(
max_length=4, choices=SDISTRICT, blank=True, default='SD39')
paper = models.BooleanField(default=False)
def __str__(self):
return self.username
View
def signup(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
to_email = form.cleaned_data.get('email')
# make the username the same as the email
user.username = str(to_email)
user.is_teacher = True
user.is_staff = True
user.is_active = False
user.save()
group = Group.objects.get(name='teacher')
user.groups.add(group)
current_site = get_current_site(request)
print(urlsafe_base64_encode(force_bytes(user.pk)))
sendgrid_client = SendGridAPIClient(
api_key=os.environ.get('SENDGRID_API_KEY'))
from_email = From("doug#smartmark.ca")
to_email = To(to_email)
subject = "Activate your SmartMark Account"
active_link = render_to_string('account/acc_active_email_link.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
html_text = f'Hello {user}<br/><p>Please click on the link below to confirm</p>{active_link}'
html_content = HtmlContent(html_text)
mail = Mail(from_email, to_email, subject,
html_content)
response = sendgrid_client.send(message=mail)
return redirect(reverse('accounts:account_activation_sent'))
else:
form = CustomUserCreationForm()
return render(request, 'account/signup.html', {'form': form})
Form
class CustomUserCreationForm(UserCreationForm):
""" form from class based view """
paper = forms.BooleanField(
label='I agree that keeping a backup paper gradebook is best practice')
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
class Meta:
model = get_user_model()
fields = ('email', 'first_name', 'last_name', 'district', 'paper')
def signup(self, request, user):
user.district = self.cleaned_data['district']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.paper = self.cleaned_data['paper']
user.email = self.cleaned_data['email']
def check_suffix(self, e, d):
email_domain = e.split("#", 2)[1]
t_suffix = email_creation(d)[0] # method which takes the 'district' and creates an email suffix
print(email_domain)
print(t_suffix)
if email_domain == t_suffix:
return True
else:
return False
def clean_email(self):
value = self.cleaned_data["email"]
value_district = self.data["district"]
if not value:
raise forms.ValidationError('An Email address is required.')
check_users = CustomUser.objects.filter(email__iexact=value)
if check_users:
raise forms.ValidationError('This email is already in use.')
if value and not check_users:
if not self.check_suffix(value, value_district):
self.add_error(
"email", "Your email address does not match your school district.")
return value
email_creation method
def email_creation(school_district):
if school_district == "SD23":
teacher_suffix = "sd23.bc.ca"
student_suffix = "learn.sd23.bc.ca"
email_prefix = True
elif school_district == "SD39":
teacher_suffix = "vsb.bc.ca"
student_suffix = "learn.vsb.bc.ca"
email_prefix = True
elif school_district == "SD67":
teacher_suffix = "sd67.bc.ca"
student_suffix = teacher_suffix
email_prefix = True
return(teacher_suffix, student_suffix, email_prefix)
Test
def test_signup_endpoint(self):
email = "foo#vsb.bc.ca"
result = self.client.post('/accounts/signup/', {'email': email})
self.assertEqual(result.status_code, 200)
created_user = get_user_model().objects.get(email=email)
self.assertTrue(created_user.is_active ==
False, created_user.to_dict())
The check_suffix might seem a bit convoluted but the MultiValueDictKeyError is happening before this method is called. The problem seems to be the `self.data['district'], it doesn't like the choice? Do I need to set/define this choice/field in my test? I tried that by adding the following in the test, but it didn't change the error.
email = "foo#vsb.bc.ca"
district = "SD39"
hello i learning about Django rest api, I am learning through someone else's code, but I don't know how to make Login.
my code :
model:
class User(models.Model):
class Meta:
db_table = "users"
created_at = models.DateTimeField(default = timezone.now)
updated_ay = models.DateTimeField(auto_now= True)
email = models.CharField(max_length = 128, unique= True)
password = models.CharField(max_length = 255)
active = models.BooleanField(default=False)
token = models.CharField(max_length= 255, null = True)
nickname = models.CharField(max_length = 255, null = True)
serializer:
class UserSerializer(serializers.ModelSerializer):
email = serializers.EmailField()
class Meta:
model = User
fields = '__all__'
def to_internal_value(self, data):
ret = super(UserSerializer, self).to_internal_value(data)
# cipher = AESSipher()
# ret['password'] = cipher.encrypt_str(ret['password'])
return ret
def to_representation(self, obj):
ret = super(UserSerializer, self).to_representation(obj)
print(ret)
return ret
def validate_email(self, value):
if User.objects.filter(email=value).exists():
raise serializers.ValidationError("Email already exists")
return value
def validate_password(self, value):
if len(value) < 8:
raise serializers.ValidationError("The password must be at least %s characters long. " % 8)
return value
def create(self, validate_data):
user = User.objects.create(
email = validate_data['email'],
password = validate_data['password'],
)
user.active = False
user.save()
message = render_to_string('user/account_activate_email.html', {
'user': user,
'domain' : 'localhost:8000',
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user)
})
mail_subject = 'sign up mail.'
to_email = 'mymail#gmail.com'
email = EmailMessage(mail_subject, message, to=[to_email])
email.send()
return validate_data
views:
class SignUp(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserActivate(APIView):
permission_classes = (permissions.AllowAny,)
def get(self, request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk = uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
try:
if user is not None and account_activation_token.check_token(user, token):
user.active = True
user.token = token
user.save()
return Response(user.email + 'email active', status=status.HTTP_200_OK)
else:
return Response('Expired Link', status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
print(traceback.format_exc())
Since I want to handle log-in status in the Mobile Client section,
I want to get only user model information when I log-in.
When Enter Email and Password in Client and I want to get user information.
How to make log-in? Do you know anyone?
Here is the link to the article: custom user authentication; it should help you
https://wsvincent.com/django-rest-framework-user-authentication-tutorial/
Hi you can use Django packages for this. for example you can use rest-auth package this package have all the things that you need for log in log out and reset password and all you need is that follow the rest auth documentation :
. https://pypi.org/project/django-rest-auth/
. https://django-rest-auth.readthedocs.io/en/latest/
I want to show a different message if user hasn't verified email address.
def post(self, request, *args, **kwargs):
self.request = request
self.serializer = self.get_serializer(data=self.request.data,
context={'request': request})
# print(self.request.data)
# print(self.request.user)
# print(self.request.data.email)
email = self.request.data['email']
# print(email)
# if not request.user.email.verified:
# print("in verification")
# return Response({"message":"Please verify your email"})
from allauth.account import app_settings
if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY:
email_address = self.request.user.emailaddress_set.get(email=self.request.user.email)
print(email_address)
if not email_address.verified:
return Response({"message":"Please verify your email id"})
if self.serializer.is_valid():
# print(self.serializer.errors)
# print(self.serializer.data)
response = super().post(request, *args, **kwargs)
# print(self.request.user)
email = self.request.user.email
# print(email)
if response.status_code == 200:
self.save_header()
return self.get_response()
User Model (I've different table in where I can see if the user have verified it or not (Django-rest-auth provides other model))
class User(AbstractUser):
"""User model."""
username = None
email = models.EmailField(_('email address'), unique=True)
mobile_token = models.CharField(max_length=20,blank=True,null=True)
U_ID = models.CharField(max_length=20,blank=True,null=True)
AI = models.IntegerField(default=0)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
i am beginner and used steps for sending email from https://docs.djangoproject.com/en/2.0/topics/email/
but i didn't accomplished to send email.
i want to send an email automatically using django email after a user submit the form . i am having a booking form and having email field in it after user post the form i want to send a email "Thankyou for your booking / your booking is placed ".
for eg
first name : Abubakar
Last name :Afzal
email : any#gmail.com
i want to take any#gmail.com and send email to it . after user post the form .
settings.py
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'my#gmail.com'
EMAIL_HOST_PASSWORD = 'mypassword'
EMAIL_USE_TLS = True
View.py
class BookingView(FormView):
template_name = 'buggy_app/booking.html'
form_class = BookingForm
models = Booking
def form_valid(self, form):
car_id = self.request.GET.get('car', '')
car = Car.objects.get(id=car_id)
car.is_available_car = False
car.save()
form.save()
return super(BookingView, self).form_valid(form)
success_url = reverse_lazy('index')
Forms.py
class BookingForm(ModelForm):
class Meta:
model = Booking
widgets = {
times_pick': TimePickerInput(), }
fields = ('first_name','last_name','email','book_car','contact_number','times_pick',)
You can define a function called send_emails (or any name). and call taht function from within form_valid method. It will look something like this
def form_valid(self, form):
car_id = self.request.GET.get('car', '')
car = Car.objects.get(id=car_id)
car.is_available_car = False
car.save()
form.save()
form.cleaned_data.get('username')
first_name = form.cleaned_data.get('first_name')
last_name = form.cleaned_data.get('last_name')
to_email = form.cleaned_data.get('email')
#your function here
send_emails(first_name, last_name, to_email)
and then define function something like this.
def send_emails(first_name, last_name, to_email):
#get template
htmly = get_template('email_templates/welcome.html')
#create a context
d = {'first_name':first_name, 'last_name':last_name}
subject, from_email, to = 'Subject line', settings.EMAIL_HOST_USER, to_email
#pass the context to html template
html_content = htmly.render(d)
msg = EmailMultiAlternatives(subject, html_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()
class BookingView(FormView):
template_name = 'buggy_app/booking.html'
form_class = BookingForm
models = Booking
def form_valid(self, form):
car_id = self.request.GET.get('car', '')
car = Car.objects.get(id=car_id)
car.is_available_car = False
car.save()
form.save()
subject = 'Thankyou for your booking / your booking is placed'
message = 'Thankyou for your booking / your booking is placed'
email_from = settings.EMAIL_HOST_USER
recipient_list = [any#gmail.com]
send_mail( subject, message, email_from, recipient_list )
return super(BookingView, self).form_valid(form)
success_url = reverse_lazy('index')
In my project,an email id field is available.
I am collecting the authors email id and while updating the details in database,an email should send to that particular email id,saying that book name is updated.
My views.py is
def addbook(request):
log.debug("test....")
form = BookForm
if request.POST:
form = BookForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(cd['book_name'],cd['author_name'],cd.get(''),['to#example.com'],)
form.save()
return redirect('/index/')
return render_to_response('addbook.html',{ 'form':form },context_instance=RequestContext(request))
I am using this send_mail() method to perform that but it is not working as i expected.
models.py is
class Book(models.Model):
book_id=models.AutoField(primary_key=True,unique=True)
book_name=models.CharField(max_length=30)
author_name=models.CharField(max_length=30)
publisher_name=models.CharField(max_length=40)
email = models.EmailField()
bookref = models.CharField(max_length=10)
class Meta:
db_table = u'Book'
def __unicode__(self):
return "%d %s %s %s %s" % (self.book_id,self.book_name, self.author_name,self.publisher_name,self.email,self.bookref)
forms.py
class BookForm(ModelForm):
log.debug("test....")
class Meta:
model = Book
fields=['book_id','book_name','author_name','publisher_name','email','bookref']
An mail should send to the email id mentioned in the email field.
Thanks
settings.py
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'user'
EMAIL_HOST_PASSWORD = 'password'
DEFAULT_FROM_EMAIL = 'your email'
views.py
if request.POST:
form = BookForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
email_to = cd['email']
subject = "{0} Update".format(
cd['book_name'])
message = "Author: {0}\n\n Your book name is updated".format(
cd['author_name'])
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL,[email_to,])
form.save()
return redirect('/index/')