Django AbstractUsers create_user not working properly - django

I have my models defined as:
class MyUser(AbstractUser):
created = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=256)
phone = models.IntegerField()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'name', 'phone']
MyUser._meta.get_field_by_name('email')[0]._unique=True
now when I am calling create_user by sending all the arguments in the form
my view.py looks like
def new_user(request):
email = request.POST.get('email','')
phone = request.POST.get('phone','')
name = request.POST.get('name','')
password = request.POST.get('password','')
confirm_pass = request.POST.get('confirm_password','')
if password and confirm_pass and password == confirm_pass:
try:
user = MyUser.objects.get(email=email)
except MyUser.DoesNotExist:
user = None
if user:
message = 'User with the following email id already exists'
return render(request, 'signup.html', {'message':message})
else:
user = My.objects.create_user(email, email, name, phone, password)
user.save()
login(request, user)
return render(request, 'details.html', {'username':request.user.username})
else:
message = 'Paaswords does not match each other'
return render(request, 'signup.html', {'message':message})
Now each time this function executes it shows me the following error
create_user() takes at most 4 arguments (6 given)
I could'nt understand why is create_user not working.

create_user function takes the parameters as *args, so you need to call the function like that:
create_user(email = email, name = name, phone = phone, password = password)
or easily pass your request.POST:
create_user(request.POST)
I'm seeing that your view is a little bit complex, have you ever try Class Based Views?
With class based views you can create method do deal with get querysets and form rendering.
That a look https://docs.djangoproject.com/en/dev/topics/class-based-views/
At last advice, you can create a register_form to deal with data validation:
https://docs.djangoproject.com/en/dev/topics/forms/

You're sending 6 arguments from your views.py where as you have only 4 required.
Note that password and confirm pass count as your 2 additional arguments. That's what I think anyway
Take a look at THIS example. It helped me with creating my abstract user.
If you'd like some code examples, HERE is a good breakdown (if you're on Django 1.5 that is)

Related

Slugfield URL implementation in Django

So, I am having some difficulty trying to slugify a title field in my model and still have it return the proper information.
Currently, a user can follow the url, if the list in their account exists under this regular expression:
url(r'^user/(?P<username>\w+)/list/(?P<listname>\w+)/$', mylistpage, name='lists'),
The issue I face is that the user can have a list containing spaces, but the regex bases their url off their list name. I am wanting to implement a slug url, but still have it retrieve the correct model/object information.
I am trying to have a slug field and then pre-populate it based on the list name, but I am lost at how this implementation is supposed to work. Much appreciation in advance from any insight.
Model
class newlist(models.Model):
user = models.ForeignKey(User)
list_name = models.CharField(max_length = 100,)
picture = models.ImageField(upload_to='profiles/', default = "/media/profiles/default.jpg")
slugurl = models.SlugField(default = slugurl(self))
def __str__(self):
return self.list_name
def slugurl(self):
return slugify(self.list_name)
Views
def mylistpage(request, username, listname):
context = RequestContext(request)
#make sure that the user is authenticated
if username == request.user.username:
#If the user is authenticated, then perform the following functions to the page
if request.user.is_authenticated():
#Store the current user request object into a variable
user = User.objects.get(username=username)
#Store the list name to the item that starts with the url input
listname = request.user.newlist_set.filter(list_name__iexact=listname)
listitems = request.user.newlist_set.all()
if not listname:
return redirect('/notfound')
else:
return redirect('/notfound')
return render_to_response('listview.html', {'lista': listname}, context)
I have used django-autoslug to great success. You can find a live example here.
SlugField is just a char field with a little syntactic sugar.
You will want to name your slug just slug so django can find it automatically in the URL resolution and passes the right parameter to views.
Your amended code would look like:
from autoslug import AutoSlugField
from django.db import models
class Newlist(models.Model): # Classes start with uppercase names by default
user = models.ForeignKey(User)
list_name = models.CharField(max_length = 100,)
picture = models.ImageField(upload_to='profiles/', default = "/media/profiles/default.jpg")
slug = AutoSlugField(populate_from='list_name')
def __str__(self):
return self.list_name
Your View:
def mylistpage(request,username, slug):
context = RequestContext(request)
#make sure that the user is authenticated
if username == request.user.username:
#If the user is authenticated, then perform the following functions to the page
if request.user.is_authenticated():
#Store the current user request object into a variable
user = User.objects.get(username=username)
#Store the list name to the item that starts with the url input
listname = request.user.newlist_set.filter(slug=slug)
listitems = request.user.newlist_set.all()
if not listname:
return redirect('/notfound')
else:
return redirect('/notfound')
return render_to_response('listview.html', {'lista': listname}, context)
urls.py
url(r'^user/(?P<username>\w+)/list/(?P<slug>[\w-]+)/$', mylistpage, name='lists'),

Django Custom User Email Account Verification

I am looking to add email account verification in Django. I have attempted using the django-registration app to do so, but it doesn't appear that it has been updated to be fully compatible with custom user models which causes too many problems. Is there another reliable and well-documented app out there which will allow me to send a verification email on user registration in django?
How I handle the email registration personally:
First of all, my Profile extending Django Users (models.py):
class Profile(models.Model):
user = models.OneToOneField(User, related_name='profile') #1 to 1 link with Django User
activation_key = models.CharField(max_length=40)
key_expires = models.DateTimeField()
In forms.py, the Registration class :
class RegistrationForm(forms.Form):
username = forms.CharField(label="",widget=forms.TextInput(attrs={'placeholder': 'Nom d\'utilisateur','class':'form-control input-perso'}),max_length=30,min_length=3,validators=[isValidUsername, validators.validate_slug])
email = forms.EmailField(label="",widget=forms.EmailInput(attrs={'placeholder': 'Email','class':'form-control input-perso'}),max_length=100,error_messages={'invalid': ("Email invalide.")},validators=[isValidEmail])
password1 = forms.CharField(label="",max_length=50,min_length=6,
widget=forms.PasswordInput(attrs={'placeholder': 'Mot de passe','class':'form-control input-perso'}))
password2 = forms.CharField(label="",max_length=50,min_length=6,
widget=forms.PasswordInput(attrs={'placeholder': 'Confirmer mot de passe','class':'form-control input-perso'}))
#recaptcha = ReCaptchaField()
#Override clean method to check password match
def clean(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 and password1 != password2:
self._errors['password2'] = ErrorList([u"Le mot de passe ne correspond pas."])
return self.cleaned_data
#Override of save method for saving both User and Profile objects
def save(self, datas):
u = User.objects.create_user(datas['username'],
datas['email'],
datas['password1'])
u.is_active = False
u.save()
profile=Profile()
profile.user=u
profile.activation_key=datas['activation_key']
profile.key_expires=datetime.datetime.strftime(datetime.datetime.now() + datetime.timedelta(days=2), "%Y-%m-%d %H:%M:%S")
profile.save()
return u
#Sending activation email ------>>>!! Warning : Domain name is hardcoded below !!<<<------
#The email is written in a text file (it contains templatetags which are populated by the method below)
def sendEmail(self, datas):
link="http://yourdomain.com/activate/"+datas['activation_key']
c=Context({'activation_link':link,'username':datas['username']})
f = open(MEDIA_ROOT+datas['email_path'], 'r')
t = Template(f.read())
f.close()
message=t.render(c)
#print unicode(message).encode('utf8')
send_mail(datas['email_subject'], message, 'yourdomain <no-reply#yourdomain.com>', [datas['email']], fail_silently=False)
Now, in views.py, we need to handle all that, let's go :
The register view:
def register(request):
if request.user.is_authenticated():
return redirect(home)
registration_form = RegistrationForm()
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
datas={}
datas['username']=form.cleaned_data['username']
datas['email']=form.cleaned_data['email']
datas['password1']=form.cleaned_data['password1']
#We generate a random activation key
salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
usernamesalt = datas['username']
if isinstance(usernamesalt, unicode):
usernamesalt = usernamesalt.encode('utf8')
datas['activation_key']= hashlib.sha1(salt+usernamesalt).hexdigest()
datas['email_path']="/ActivationEmail.txt"
datas['email_subject']="Activation de votre compte yourdomain"
form.sendEmail(datas)
form.save(datas) #Save the user and his profile
request.session['registered']=True #For display purposes
return redirect(home)
else:
registration_form = form #Display form with error messages (incorrect fields, etc)
return render(request, 'siteApp/register.html', locals())
The activation views :
#View called from activation email. Activate user if link didn't expire (48h default), or offer to
#send a second link if the first expired.
def activation(request, key):
activation_expired = False
already_active = False
profile = get_object_or_404(Profile, activation_key=key)
if profile.user.is_active == False:
if timezone.now() > profile.key_expires:
activation_expired = True #Display: offer the user to send a new activation link
id_user = profile.user.id
else: #Activation successful
profile.user.is_active = True
profile.user.save()
#If user is already active, simply display error message
else:
already_active = True #Display : error message
return render(request, 'siteApp/activation.html', locals())
def new_activation_link(request, user_id):
form = RegistrationForm()
datas={}
user = User.objects.get(id=user_id)
if user is not None and not user.is_active:
datas['username']=user.username
datas['email']=user.email
datas['email_path']="/ResendEmail.txt"
datas['email_subject']="Nouveau lien d'activation yourdomain"
salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
usernamesalt = datas['username']
if isinstance(usernamesalt, unicode):
usernamesalt = usernamesalt.encode('utf8')
datas['activation_key']= hashlib.sha1(salt+usernamesalt).hexdigest()
profile = Profile.objects.get(user=user)
profile.activation_key = datas['activation_key']
profile.key_expires = datetime.datetime.strftime(datetime.datetime.now() + datetime.timedelta(days=2), "%Y-%m-%d %H:%M:%S")
profile.save()
form.sendEmail(datas)
request.session['new_link']=True #Display: new link sent
return redirect(home)
Finally, in urls.py:
url(r'^register/$', 'register'),
url(r'^activate/(?P<key>.+)$', 'activation'),
url(r'^new-activation-link/(?P<user_id>\d+)/$', 'new_activation_link'),
With all that you should have something to start with, use the appropriate templatetags in the .txt emails and HTML and it should work.
NB: This code isn't perfect, there is duplication (for instance, the generation of the random key could be defined in a function), but it does the job. Also: the activation key is not generated using proper cryptographic functions. An alternative is to use a function like the following to generate the keys:
from django.utils.crypto import get_random_string
def generate_activation_key(username):
chars = 'abcdefghijklmnopqrstuvwxyz0123456789!##$%^&*(-_=+)'
secret_key = get_random_string(20, chars)
return hashlib.sha256((secret_key + username).encode('utf-8')).hexdigest()
NB2: Django send_mail doesn't provide any tools to authenticate your emails. If you want to authenticate your emails (DKIM, SPF), I advise you to look into this: https://djangosnippets.org/snippets/1995/
NB3: There is a security issue with the view new_activation_link: it should check if the user requesting the re-send is the right one and also if he isn't already authenticated. I let you correct that.
You may also be interested in the simple but powerful django-verified-email-field.
Simply use VerifiedEmailField in Your forms:
from django import forms
from verified_email_field.forms import VerifiedEmailField
class RegistrationForm(forms.ModelForm):
email = VerifiedEmailField(label='email', required=True)
Or in Your models:
from django.db import models
from verified_email_field.models import VerifiedEmailField
class User(models.Model):
email = VerifiedEmailField('e-mail')
It renders two input fields: e-mail and verification code. The verification code is sent to the e-mail address using AJAX or during field's clean if there is no valid code for given e-mail, so it works even without javascript.

django form use excluded field

with django 1.5.1 I try to use the django form for one of my models.
I dont want to add the "user" field (Foreignkey) somewhere in the code instead of letting the user deceide whoes new character it is.
My Code:
Model:
class Character(models.Model):
user = models.ForeignKey(User)
creation = models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')
name = models.CharField(max_length=32)
portrait = models.ForeignKey(Portrait)
faction = models.ForeignKey(Faction)
origin = models.ForeignKey(Origin)
The form:
class CreateCharacterForm(forms.ModelForm):
class Meta:
model = Character
fields = ['name', 'portrait', 'faction', 'origin']
The view:
def create_character(request, user_id):
user = User.objects.get(id=user_id)
if request.POST:
new_char_form = CreateCharacterForm(request.POST)
if new_char_form.is_valid():
new_char_form.save()
return HttpResponseRedirect('%s/characters/' % user_id)
else:
return render_to_response('create.html',
{'user': user, 'create_char':new_char_form},
context_instance=RequestContext(request))
else:
create_char = CreateCharacterForm
return render_to_response('create.html',
{'user': user, 'create_char': create_char},
context_instance=RequestContext(request))
I have tried to use a instance to incluse the userid already. i've tried to save the userid to the form before saving it, or changing the save() from my form.
I keep getting the error that character.user cant be null
I have to tell that im pretty new to django and im sure one way or another it should be possible
Can someone please help me out?
Its explained well in document model form selecting fields to use
You have to do something like this in your view
...
if request.POST:
new_char_form = CreateCharacterForm(request.POST)
if new_char_form.is_valid():
#save form with commit=False
new_char_obj = new_char_form.save(commit=False)
#set user and save
new_char_obj.user = user
new_char_obj.save()
return HttpResponseRedirect('%s/characters/' % user_id)
else:
...

Django 1.4 Modifying Custom Account Model for Uniqueness of E-mail Addresses

I've already defined a custom user account that utilizes several built in's from the auth User model and, using the user link, links these with some additional fields that I needed to register a user on the database.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
relevant from my models.py
# additional model to incorporate our custom fields to the auth user model
class Account(models.Model):
user = models.OneToOneField(User) #link (pointer) to the users other information in User model
birthdate = models.DateField(blank = True, ) # True makes this field optional
gender = models.CharField(max_length = 1, choices = GENDER_CHOICE, null = True, blank = True)
def __unicode__(self): # define a unicode for the user to access
return u'%s %s' % (self.user.first_name, self.user.last_name) # return first and last name in shell
# custom form to gather information from the user for a new account
class UserRegistration(UserCreationForm):
#class RegistrationForm(forms.ModelForm):
class Meta:
model = User
fields = ("first_name", "last_name", "email", "username", "password1", "password2",)
# ensures uniqueness of user email addresses when registering
def clean_email(self):
print "In custom creation"
email = self.cleaned_data.get(email = 'email')
username = self.cleaned_data.get(username = 'username')
# checks if email address already exists
if User.objects.filter(email__iexact = self.cleaned_data['email']):
print "Email exists"
# if email and User.objects.filter(email__iexact = email).exclude(username=username).exists():
raise forms.ValidationError(u'Email Address is currently used by another user.')
return email
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
relevant from views.py
def Main(request):
if request.user.is_authenticated():
latest_events = Event.objects.all().order_by('-created')[:10] # Returns latest 10 events
my_events = Event.objects.filter(creator=request.user)[:10] # Returns up to 10 events created by current User
my_calendars = Calendar.objects.filter(creator=request.user) # Returns all calendars created by the user
authForm = None
loginForm = None
headerType = "header.html"
else:
latest_events = None
my_events = None
my_calendars = None
headerType = "header_main.html"
authForm = UserRegistration(request.POST or None)
print "Creating account UserRegistration" # TESTING PRINT
print "User email = %s " %(User._meta.get_field('email'))
if request.method == 'POST':
if authForm.is_valid():
newUser = authForm.save(commit=False)
newUser.save()
newUser = authenticate(username=request.POST['username'], password=request.POST['password1'])
login(request, newUser)
return HttpResponseRedirect('/signup/')
....
....
more code on success redirection
....
....
~~~~~~~~~~~~~~~~~~~~~~~~~~~
(I hope I didn't post too much code, just wanted to be thorough)
As you can see there are a few commented out attempts I've made recently. I tried using thee built in RegistrationFormUniqueForm() by downloading 'registration' but I don't actually want to make a new registration form since I already have a working one.
I moved on to trying another suggestion, the code under the comment
# custom form to display additional sign up information
When I tried registering a new user with an already registered email it did not throw any error and allowed the registration. I also tried changing the users email and it allowed the change to an already taken email with no objection.
Can anyone suggest a method for making user registration maintain a unique lock on each individual attempting to register with an email address that may already be taken? As well as preventing them from changing their email to one that is taken by a current user?
Thanks in advance.
EDIT: I made changes to the Models registration form def clean_email() and the def in views to reflect what I currently have that still does not work.
The indentation of your clean_email methods is wrong for both forms. At the moment, they are methods of the Meta class, so will never be called. For example, the registration form should be:
class RegistrationForm(UserCreationForm):
#class RegistrationForm(forms.ModelForm):
class Meta:
model = User
fields = ("first_name", "last_name", "email", "username", "password1", "password2",)
def clean_email(self):
"""ensures uniqueness of user email addresses when registering"""
email = self.cleaned_data.get('email')
This might not be the real problem -- it's easy to get the indentation wrong when pasting code into stack overflow. If that's the case, I'll delete the answer.

Django submit optional forms

I need to create registration form for an event. Each person that register can bring guests. I want to register everything in one page. To do that I use a view with 1 RegistrationForm and X GuestForms. In my models, I have a Registration and Guest class I used to create the two forms with ModelForm.
The problem is that a GuestForm is not required to be filled (you don't have to bring guests).
def register_form(request):
error = False
if request.method == 'POST':
register = RegistrationForm(request.POST, instance=Registration() )
guests = [GuestForm(request.POST, prefix=str(x), instance=Guest()) for x in range(MAXGUESTS)]
if register.is_valid():
print("register is valid")
for guest in guests:
if guest.is_valid():
print("guest is valid")
else:
print("guest is not valid") # always when empty form
error = True
else:
print("register is not valid")
error = True
if not error:
... # save the form in the database
register = RegistrationForm(instance=Registration())
guests = [GuestForm(prefix=str(x), instance=Guest()) for x in range(MAXGUESTS)]
return render_to_response('register.html',{
'form': register,
'max_guests': MAXGUESTS,
'guests': guests,
'error': error,
})
So I need to set a form as optional and be able to differentiate when the whole form is empty and when there is an error. Any idea how ?
Thank you
Solution
def register_form(request):
GuestFormSet = modelformset_factory(Guest, exclude=('register',))
error = False
if request.method == 'POST':
register = RegistrationForm(request.POST, instance=Registration() )
guests = GuestFormSet(request.POST)
if register.is_valid():
print("register is valid")
for guest in guests:
if guest.is_valid():
print("guest is valid") # even if some forms are empty
else:
print("guest is not valid")
error = True
else:
print("register is not valid")
error = True
if not error:
...
# save the form in the database
return something
else:
register = RegistrationForm(instance=Registration())
guests = GuestFormSet(queryset=Guest.objects.none())
return render_to_response('register.html',{
'form': register,
'max_guests': MAXGUESTS,
'guests': guests,
'error': error,
})
You can use a model formset for your guest forms. It can distinguish between empty and invalid forms.
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#model-formsets
I guess you will need some way to determine if a submitted guest form was actually filled in. When an empty form was submitted, ignore it:
forms_to_save =[]
for form in guest_forms:
if guest_form.is_valid()
forms_to_save.append( form )
else:
if form.contains_data(): # you'll have to implement this
error = True
if not error:
for form in forms_to_save():
form.save()
I have a similar problem in a wedding RSVP application that I'm building. In my case, each Guest has an 'attending' checkbox, and if it is not checked (i.e. the guest isn't attending) then I don't want any errors to be reported to the user.
My Guest model (slimmed down for brevity):
class Guest(models.Model):
email = models.EmailField(max_length=50, unique=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
attending = models.BooleanField(default=False)
I have a ModelForm class called RsvpForm that creates a form based on the Guest model. It looks like this:
class RsvpForm(ModelForm):
class Meta:
model = Guest
fields = ('attending', 'email', 'first_name', 'last_name')
def clean(self):
cleaned_data = self.cleaned_data
attending = cleaned_data.get('attending')
if not attending:
#clear the error collection
self._errors['email'] = {}
return cleaned_data
The solution to this problem lies in the clean() method that I've overriden in my RsvpForm class. In it, I check whether or not the guest is attending. If they aren't, then I clear the error messages for each of the other fields.
Originally, I had cleared the errors for the entire form like this:
if not attending:
#clear the error collection
self._errors['email'] = ''
self._errors['first_name'] = ''
self._errors['last_name'] = ''
But for some reason, modifying the values of any of these keys caused the form to fail validation, which in turn prevented Guest data from being saved if they had indicated that they were not attending. A small bug that most would never find, but annoying nonetheless.
At some point along the line, I had also tried to clear the errors collection by calling .clear() on the self._errors dictionary:
if not attending:
#clear the error collection
self._errors.clear()
But for some reason, the errors were still shown, even though I could verify that the dictionary was empty.
The end result is that form validation errors are only shown to my user if the 'attending' checkbox is selected, which is ideal because Guests might want to update their own contact information prior to deciding on who they will bring as a plus one.
There is a simpler solution than Alasdair's: using the empty_permitted keyword argument.
>>> f = MyForm(data={}, empty_permitted=True)
>>> f.is_valid()
True