I presume I have missed something silly, but I can't make the inlineformset to work with me. I have a very similar code in my site, which works fine. The original code was for registration and I have tried to modify it so user-data could be updated/changed.
models.py
class Profiles(AbstractBaseUser):
activation_key = Utils().activationKey()
email = models.EmailField(verbose_name = 'email address', max_length = 255, unique = True)
activation_code = models.CharField(max_length=40, default=activation_key)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = ProfilesManager()
USERNAME_FIELD = 'email'
def get_email(self):
return self.email
def get_full_name(self):
# The user is identified by their email address
userdata = ProfileData.objects.get(uid_id=self.id)
return userdata.full_name
def get_short_name(self):
# The user is identified by their email address
return self.email
def __str__(self): # __unicode__ on Python 2
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
def __unicode__(self):
return u'%d' % self.id
#property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
class ProfileData(models.Model):
profile = models.ForeignKey(Profiles)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
full_name = models.CharField(max_length=100)
image = models.ImageField(upload_to='media/user/avatar', blank=True, null=True)
def get_first_name(self):
return self.first_name
def get_last_name(self):
return self.last_name
def get_full_name(self):
return self.full_name
def get_avatar(self):
return self.image
def save(self, *args, **kwargs):
self.full_name = '{0} {1}'.format(self.first_name, self.last_name)
super(ProfileData, self).save(*args, **kwargs)
views.py
class ProfileView(TemplateView):
template_name = 'profiles/profile.html'
form = ProfileDataForm
formset = ProfileFormset
def get(self, request, user_id):
profile = ProfileData.objects.select_related('Profiles').filter(profile=user_id).first()
if request.user.id and user_id:
if int(request.user.id) is int(user_id):
instance = ProfileData.objects.filter(profile=request.user).first()
return render(request, self.template_name, {'form': self.form(instance=request.user), 'formset': self.formset(), 'profile': profile})
else:
return render(request, self.template_name, {'profile': profile})
#method_decorator(sensitive_post_parameters())
#method_decorator(csrf_protect)
#method_decorator(never_cache)
#method_decorator(api_view(['POST']))
#transaction.non_atomic_requests
def post(self, request, user_id):
form = self.form(request.POST, instance=request.user)
if form.is_valid():
if form.data['password'] == form.data['conf_password']:
transaction.set_autocommit(False)
try:
profile = form.save(commit=False)
profile_formset = self.formset(request.POST, request.FILES, instance=profile)
if profile_formset.is_valid():
print 'formset is valid...'
profile.save()
profile_formset.save()
finally:
transaction.set_autocommit(True)
else:
print 'Passwords doesn\'t match'
else:
print 'Form is not valid...'
user = ProfileData.objects.select_related().filter(profile=user_id).first()
return HttpResponseRedirect('/user/{0}/'.format(user_id))
forms.py
class ProfileDataForm(forms.ModelForm):
email = forms.CharField(max_length=100, label='', widget=forms.TextInput(attrs={'placeholder': 'E-mail', 'class': 'form-control'}), required=False)
password = forms.CharField(max_length=100, label='', widget=forms.PasswordInput(attrs={'placeholder': 'Password', 'class': 'form-control'}), required=False)
conf_password = forms.CharField(max_length=100, label='', widget=forms.PasswordInput(attrs={'placeholder': 'Confirm Password', 'class': 'form-control'}), required=False)
class Meta:
model = Profiles
fields = ['email', 'password', 'conf_password']
exclude = ('full_name', 'image', )
def clean_password2(self):
# Check that the two password entries match
password = self.cleaned_data.get('password')
conf_password = self.cleaned_data.get('conf_password')
if password and conf_password and password != conf_password:
raise forms.ValidationError('Passwords don\'t match')
return conf_password
def save(self, commit=True):
print 'saving form...'
# Save the provided password in hashed format
user = super(ProfileDataForm, self).save(commit=False)
user.set_password(self.cleaned_data['password'])
if commit:
user.save()
return user
ProfileFormset = inlineformset_factory(Profiles, ProfileData,
exclude=('full_name', ),
can_delete=False,
extra=1,
widgets={
'first_name': forms.TextInput(attrs={'placeholder': 'First name', 'class': 'form-control'}),
'last_name': forms.TextInput(attrs={'placeholder': 'Last name', 'class': 'form-control'}),
},
labels={
'first_name': None,
'last_name': None
},
)
I have made sure to include everything, there is no error, the debug doesn't pop up and form is saved (views->ProfilesViews->post).
Despite everything, the inlineform doesn't save. I have tried to make a custom def save(), without success.
the variable "form" in views is connected to Profiles while "profile_formset" is connected to ProfileData.
I am usually rubbish at asking questions here, I shall edit if you find me unclear.
Although this is not a solution, There are a few things to note here:
1) I didn't understand why you are using exclude after selecting the fields.
2) You are doing password matching twice in forms.py and views.py
3) In forms.py the method that validates field, as far as I know should be like clean_fieldname.
Please correct me if I'm wrong.
Related
Building logic that, when a user logs in would change a boolean field in my Profile model to true and then turn that to false when the user logs out. The problem is I have an api_end point where I can see a list of all users and information related to said users.
If I login as two different users (using different browsers), When I console log their information both users are shown as online:
email: "user#gmail.com"
...
is_online: true
...
However, when I check the api_end point showing me the list of all users, only 1 user appears to be online (the last user I logged in as).
This is the view related to api_end point to view all users:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all().order_by('-date_joined')
serializer_class = RegisterSerializer
#action(detail=True, methods=['POST'])
def set_password(self, request, pk=None):
user = self.get_object()
serializer = PasswordSerializer(data=request.data)
if serializer.is_valid():
user.set_password(serializer.validated_data['new_password'])
user.save()
return Response({'status': 'password set'})
else:
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
This is my RegisterSerializer:
class RegisterSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ['username', 'email', 'password', 'first_name', 'last_name', 'profile']
extra_kwargs = {
'password': {'write_only': True},
}
def validate_password(self, value):
validate_password(value)
return value
def create(self,validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(**profile_data, user=user)
return user
This is my profile model:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
city = models.CharField(max_length=50, blank=True)
country = models.CharField(max_length=50, blank=True)
bio = models.CharField(max_length=500, blank=True)
profile_pic = models.ImageField(upload_to='profile/%Y/%m/%d', default='media/placeholder.png', blank=False,
null=False)
is_online = models.BooleanField(default=False)
currently_active = models.BooleanField(default=False)
is_in_session = models.BooleanField(default=False)
#receiver(user_logged_in)
def got_online(sender, user, request, **kwargs):
user.profile.is_online = True
user.profile.save()
#receiver(user_logged_out)
def got_offline(sender, user, request, **kwargs):
user.profile.is_online = False
user.profile.save()
#receiver(post_save, sender=user)
def update_profile_signal(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
This is the function that is triggered when a user logs in- this is where I set the user.profile.is_online field to true when a user logs in. I assume this is where the problem is coming from?:
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
authenticate_kwargs = {
self.username_field: attrs[self.username_field],
"password": attrs["password"],
}
try:
authenticate_kwargs["request"] = self.context["request"]
except KeyError:
pass
user = authenticate(**authenticate_kwargs)
if not user:
return {
'user': 'Username or password is incorrect',
}
token = RefreshToken.for_user(user)
# customizing token payload
token['username'] = user.username
token['first_name'] = user.first_name
token['last_name'] = user.last_name
token['country'] = user.profile.country
token['city'] = user.profile.city
token['bio'] = user.profile.bio
token['photo'] = json.dumps(str(user.profile.profile_pic))
user_logged_in.send(sender=user.__class__, request=self.context['request'], user=user)
if not api_settings.USER_AUTHENTICATION_RULE(user):
raise exceptions.AuthenticationFailed(
self.error_messages["no_active_account"],
"no_active_account",
)
return {
'refresh': str(token),
'access': str(token.access_token),
}
I have a user registration form that asks for user information and also asks a question: "Are you a PSMC member?"
The options are:
rank = [
('Supporter', 'Supporter (non-member)'),
('Anak', 'Anak'),
('Uso', 'Uso'),
('Chief', 'Chief'),
]
If Supporter is selected, then the registration form proceeds and saves user info, etc. This part works fine. However, if Anak is selected, I want it to take the user to another form that asks additional questions.
In my forms.py, I have class RegisterForm which is the main registration form for all users. I also have class AnakRegisterForm which is what I want it to continue on to. I used Django's AuthenticationForm based off what I read from their website (but I could be wrong). I know the issue is in views.py register function. Specifically:
if rank == 'Anak':
anak_register(response)
During my debug session, after it moves response to anak_register function, it gets a bunch of scrambled information. I'm pretty lost, any help would be appreciated. Here is my code:
forms.py
class RegisterForm(UserCreationForm):
email = forms.EmailField(
initial='',
required=True,
help_text='Please enter a valid email address'
)
rank = forms.ChoiceField(
label='Are you a PSMC member?',
choices=SavBlock.models.User.rank,
initial=False,
required=True,
help_text='Member accounts will be validated with your HC.'
)
class Meta:
model = User
# username = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
fields = ['username', 'first_name', 'last_name', 'email',
'rank', 'password1', 'password2']
def save(self, commit=True):
user = super(RegisterForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.ranking = self.cleaned_data['rank']
if commit:
user.save()
return user
class AnakRegisterForm(AuthenticationForm):
tribe = forms.ChoiceField(
label='What tribe are you from, Uce?',
choices=SavBlock.models.Anak.tribe,
initial=False,
required=True,
help_text='Member accounts will be validated with your HC.'
)
class Meta:
model = Anak
fields = ['tribe']
def save(self, commit=True):
user = super(AnakRegisterForm, self).save(commit=False)
user.tribe = self.cleaned_data['tribe']
if commit:
user.save()
return user
class UsoRegisterForm(AuthenticationForm):
pass
class ChiefRegisterForm(AuthenticationForm):
pass
views.py
def register(response):
context = {}
if response.method == "POST":
form = RegisterForm(response.POST)
if form.is_valid():
form.save()
rank = form.cleaned_data.get('rank')
if rank == 'Anak':
anak_register(response)
else:
form.save()
messages.success(response, 'Registration successful. Please login.')
return redirect('login')
else:
context['register'] = form
else:
form = RegisterForm()
context['register'] = form
return render(request=response, template_name='register/register.html', context={'form': form})
def anak_register(response):
# context = {}
if response.method == "POST":
form = AnakRegisterForm(response.POST)
if form.request.is_valid():
form.save()
messages.success(response, 'Registration successful. Please login.')
return redirect('login')
else:
'''
context['register'] = form
'''
else:
form = AnakRegisterForm()
# context['register'] = form
# messages.error(request, 'Unsuccessful registration. Invalid information.')
# form = RegisterForm
return render(request=response, template_name='register/register.html', context={'form': form})
models.py
class User(AbstractBaseUser, PermissionsMixin):
rank = [
('Supporter', 'Supporter (non-member)'),
('Anak', 'Anak'),
('Uso', 'Uso'),
('Chief', 'Chief'),
]
tribe = [
('NaKoaHema', 'Na Koa Hema'),
('Alakai', 'Alaka\'i')
]
username = models.CharField("user name", max_length=50, default='', unique=True)
email = models.EmailField("email address", max_length=30, unique=True, blank=True)
first_name = models.CharField("first name", max_length=50)
last_name = models.CharField("last name", max_length=50)
is_active = models.BooleanField('active', default=True)
# password = models.CharField("password", unique=True, max_length=32, default='')
id = models.AutoField(primary_key=True)
is_staff = models.BooleanField('staff status', default=False)
date_joined = models.DateField('date_joined', default=timezone.now)
ranking = models.CharField(choices=rank, max_length=50, default="Supporter")
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'password', 'ranking']
# Magic method returns string of self
def __str__(self):
return f"User {self.first_name} {self.last_name} rank {self.rank}".strip()
#property
def get_full_name(self):
return f"{self.first_name} {self.last_name}".strip()
class Anak(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[1]
EDIT
I changed AuthenticationForm to UserCreationForm and now it accepts the form. However, when I try to run it, I get the following error:
TypeError at /register/
__init__() missing 1 required positional argument: 'tribe'
If someone could point me in the right direction, I'd appreciate it!
Not sure how I missed this, but the best solution that I found is to implement Django Form Wizard. More information can be found here:
https://django-formtools.readthedocs.io/en/latest/wizard.html
I am new the Django and I am unable to save the Registration form using the Class Based View. I have made the Abstract user in the Models as shown below.
models.py
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
full_name = models.CharField(max_length=255, blank=True, null=True)
active = models.BooleanField(default=True) # can login
staff = models.BooleanField(default=False) # staff user non superuser
admin = models.BooleanField(default=False) # superuser
timestamp = models.DateTimeField(auto_now_add=True)
user_type = models.CharField(max_length= 120, choices=u_type)
# confirm = models.BooleanField(default=False)
# confirmed_date = models.DateTimeField(default=False)
USERNAME_FIELD = 'email' #username
# USERNAME_FIELD and password are required by default
REQUIRED_FIELDS = [] #['full_name'] #python manage.py createsuperuser
objects = UserManager()
def __str__(self):
return self.email
def get_full_name(self):
if self.full_name:
return self.full_name
return self.email
def get_short_name(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
#property
def is_active(self):
return self.active
I have used Form for creating the Registration form as shown below
forms.py
class RegistrationForm(forms.Form):
password1 = forms.CharField(label='password')
password2 = forms.CharField(label='Confirm Password')
user_email = forms.CharField(label='Email')
full_name = forms.CharField(label='Full Name')
class Meta:
model = User
fields = ('full_name', 'email','user_type')
def clean_password2(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise forms.ValidationError('password does not match')
return password2
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user_mail = self.cleaned_data.get('user_email')
print(user_mail)
user.set_password(self.cleaned_data['password1'])
if(commit):
user.save()
return user
this is the view file for the form
views.py
class RegisterView(FormView):
form_class = RegistrationForm
template_name = 'register.html'
success_url='/login'
def form_valid(self,form):
request = self.request
# f = JobForm(request.POST)
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
print(form)
instance = form.save(commit=False)
return redirect('/')
The issue I am facing is when I am trying to save the registration form then it is giving me the error 'super' object has no attribute 'save'. Currently I am struggling to save the form using the Class Based View.
I am using a custom user model for my API. The following are the codes for my project:
models.py
class AccountManager(BaseUserManager):
def create_user(self, email, password=None, **kwargs):
if not email:
raise ValueError('Users must have a valid email address.')
if not kwargs.get('username'):
raise ValueError('Users must have a valid username.')
account = self.model(
email=self.normalize_email(email), username=kwargs.get('username')
)
account.set_password(password)
account.save()
return account
def create_superuser(self, email, password, **kwargs):
account = self.create_user(email, password, **kwargs)
account.is_staff = True
account.is_superuser = True
account.save()
return account
class Account(AbstractBaseUser):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True)
first_name = models.CharField(max_length=40, blank=True)
last_name = models.CharField(max_length=40, blank=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = AccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
def __unicode__(self):
return self.email
def get_full_name(self):
return ' '.join([self.first_name, self.last_name])
def get_short_name(self):
return self.first_name
def has_perm(self, perm, obj=None):
return self.is_superuser
def has_module_perms(self, app_label):
return self.is_superuser
I am serializing the Account model using a serializer as shown below in serializers.py
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
confirm_password = serializers.CharField(write_only=True, required=False)
class Meta:
model = Account
fields = (
'id', 'email', 'username', 'created_at', 'updated_at',
'first_name', 'last_name', 'password', 'confirm_password',
)
read_only_fields = ('created_at', 'updated_at',)
def create(self, validated_data):
return Account.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.username = validated_data.get('username', instance.username)
instance.save()
password = validated_data.get('password', None)
confirm_password = validated_data.get('confirm_password', None)
if password and confirm_password and password == confirm_password:
instance.set_password(password)
instance.save()
return instance
And of course I have a view-set which handles the API requests through an end-point, views.py
class AccountViewSet(viewsets.ModelViewSet):
lookup_field = 'username'
queryset = Account.objects.all()
serializer_class = AccountSerializer
def get_permissions(self):
if self.request.method in permissions.SAFE_METHODS:
return (permissions.AllowAny(),)
if self.request.method == 'POST':
return (permissions.AllowAny(),)
return (permissions.IsAuthenticated(), IsAccountOwner(),)
def create(self):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
Account.objects.create_user(**serializer.validated_data)
return Response(serializer.validated_data, status=status.HTTP_201_CREATED)
return Response({
'status': 'Bad request',
'message': 'Account could not be created with received data.'
}, status=status.HTTP_400_BAD_REQUEST)
When I try to post a new user through the API, I get this error:
create() takes exactly 1 argument (2 given) error
I also have this as my traceback:
http://dpaste.com/2ED1XSX
So what exactly am I doing wrong? I basically followed a tutorial to do this. Any help? Thanks a lot.
Edit
I fixed the indentation error, but I still get the same error :/
Your indentation is wrong, create() and update() methods should be defined on the "serializer" level - not on the Meta class level:
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
confirm_password = serializers.CharField(write_only=True, required=False)
def create(self, validated_data):
return Account.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.username = validated_data.get('username', instance.username)
instance.save()
password = validated_data.get('password', None)
confirm_password = validated_data.get('confirm_password', None)
if password and confirm_password and password == confirm_password:
instance.set_password(password)
instance.save()
return instance
class Meta:
model = Account
fields = (
'id', 'email', 'username', 'created_at', 'updated_at',
'first_name', 'last_name', 'password', 'confirm_password',
)
read_only_fields = ('created_at', 'updated_at',)
Note that in the code above, I've also moved them before the Meta inner class definition - this usually helps to avoid problems like this one.
I have this method in my views.py file
def guest_login(request):
form = SomeForm(request.POST or None)
if form.is_valid():
email = request.POST['email']
password= request.POST['password']
u = authenticate(username = email, password = password)
if uis not None:
if u.is_active:
login(request, u)
userProfile= request.user.profile
return HttpResponseRedirect(userProfile.get_absolute_url())
else:
messages.error(request, 'Text', extra_tags='text')
else:
messages.error(request, 'Text', extra_tags='text')
else:
form = SomeForm()
context = {
"form": form,
}
return render(request, 'loginpage.html', context)
So, I did not extend the basic User, I created my own, and i did it like this:
class MyUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), max_length=255, db_index=True, blank = False, unique = True)
name= models.CharField(blank = False, max_length = 100)
surname= models.CharField(blank = False, max_length = 100)
# slug = models.SlugField(unique = True)
is_staff = models.BooleanField(
_('some_text'), default=False, help_text=_(
'text'))
is_active = models.BooleanField(_('ctive'), default=True, help_text=_(
'text'
'text'))
date_joined = models.DateTimeField(_('date created'), default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'email'
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
# abstract = True
def get_full_name(self):
return self.name + " " + self.surname
def get_short_name(self):
return self.name
def get_email(self):
return self.email
def email_user(self, subject, message, from_email=None, **kwargs):
"""Send an email to this User."""
send_mail(subject, message, from_email, [self.email], **kwargs)
class MyUserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(unique=True)
def get_absolute_url(self):
return reverse("user:restoraunts", kwargs={"slug": self.slug})
User.profile = property(lambda u: MyUser.objects.get_or_create(user=u)[0])
def create_slug(instance, new_slug=None):
slug = slugify(instance.user.name)
if new_slug is not None:
slug = new_slug
qs = MyUserProfile.objects.filter(slug=slug).order_by('-id')
exists = qs.exists()
if exists:
new_slug = "%s-%s" % (slug, qs.first().id)
return create_slug(instance, new_slug=new_slug)
return slug
def pre_save_guest_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = create_slug(instance)
#
pre_save.connect(pre_save_guest_receiver, sender=MyUserProfile)
And in settings.py a added:
AUTH_USER_MODEL = 'korisnik.Korisnik'
AUTH_PROFILE_MODULE = 'korisnik.KorisnikProfil'
Everything works fine, except this line:
userProfile= request.user.profile
It says that "MyUser has no attribute profile".
I tried everything, get_profile(), get_profile, profile(), profile... Nothing worked. Can anyone help me? Thank you.
Note that the AUTH_PROFILE_MODULE setting and the get_profile() method where remove in django 1.7.
Try adding a related_name to your MyUserProfile.user field.
Also note that you might be able to just add that slug filed on the user model and avoid the extra relation.