How to override django signup view class - django

I want to override django all-auth signup view to input an extra field value.
In this case, User model has a foreign field which is combined to Company model.
from allauth.account.views import SignupView as AllAuthSignupView
from .models import Company
class SignupView(AllAuthSignupView):
def save(self):
user = super(SignupView, self).save()
a_company = get_object_or_404(Company, name='A')
user.company = a_company
return user
However, This only saves username, password, email. The company field is NULL.
I don't want an answer that recommends change the default value in Company model. That's not the way I try to solve this problem.

Rather than overriding the view, you can simply create a new Form to save the additional data. For example:
companies = (
('comapny_name_1', 'ABC'),
('comapny_name_2', 'DEF'),
)
class SignupForm(forms.Form):
company = forms.ChoiceField(choices=companies)
def signup(self, request, user):
user.company = Company.objects.get(name=self.cleaned_data['company'])
user.save()
Then add the Form Path to ACCOUNT_SIGNUP_FORM_CLASS in settings.py:
ACCOUNT_SIGNUP_FORM_CLASS = 'path.to.SignupForm'
More information can be found in documentation.

Related

Django - How to link the current authenticated user with the data provided by a form

Sorry if the question is too basic but I've read the documentation and many articles and none of them seem to answer my question.
I want to link a posted form by an user with that user into the DB, so I can query the data provided for each particular user and use delete on CASCADE in the event the user is deleted.
I tried creating a Model, then a ModelForm based on that Model.
I added a field named "user" in the Model as a ForeignKey, so in the ModelForm is translated to ModelChoiceField which by the way is hidden, since the user shouldn't change that value.
But when I try to update the user field in the views.py, nothing happens, the form is saved into the DB, but the user field remains as None or Null in the DB.
models.py
class Foo(models.Model):
user = models.ForeignKey(User, related_name='+', on_delete=models.CASCADE)
forms.py
class FooForm(ModelForm):
class Meta:
model = Foo
fields = ['user', 'field1', 'field2']
exclude = ['user']
views.py
def index(request):
if request.user.is_authenticated:
if request.method == 'POST':
foo = FooForm(request.POST)
if foo.is_valid():
foo.save(commit=False)
foo.user = request.user
foo.save()
I got the posted Form saved into the DB but the user field is NULL.
Please tell me if you see any errors in my code or if there is a better way to achieve what I want.
Thank you in advance.
You are quite close. But foo is the form, not the instance. You can alter the instance by writing foo.instance.user = request.user. For example:
from django.contrib.auth.decorators import login_required
#login_required
def index(request):
if request.user.is_authenticated:
if request.method == 'POST':
foo = FooForm(request.POST)
if foo.is_valid():
foo.instance.user = request.user
foo.save()
# …
You probably want to decorate your view with the #login_required decorator [Django-doc], such that in case there is no authenticated user, it will redirect to the login page.

Django forms dynamic getting author as a logged in user in model forms

I'm trying to make some forms that will allow users to add some objects, delete them or edit but I've stucked with thing like author of model. Let's say we got model Shot which got field
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
Because I've created custom user model to expand user by some fields that I want, and then we creating modelForm, creating views etc. and finally got form. When we will try to submit this form, it won't add this object submited in form to db because form has no filled field author author which means this field == Null and that's why it won't add this to db. So my question is how to get it dynamic, for example when user with nick "thebestuser" will try to add this modelForm it will work and mark author as "thebestuser"? Ofc I could add to form field author, but it's the worst way in my opinion and every user would be allowed then to add object for example as a another user, let's say user with nick "anothernick" could add form as a user with "thebestuser" which is In my opinion not acceptable.
models.py
from django.db import models
from django.contrib.auth.models import User
from streamers.models import Streamer
from django.conf import settings
from django.utils import timezone
class Shot(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=70)
url = models.CharField(max_length=100)
streamer = models.ForeignKey(Streamer, on_delete=models.CASCADE)
published_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
forms.py
from django import forms
from .models import Shot
class AddShot(forms.ModelForm):
class Meta:
model = Shot
fields = [
'title',
'url',
'streamer',
]
views.py
#login_required
def add_shot(request):
form = AddShot(request.POST or None)
if form.is_valid():
form.save()
instance = form.save(commit=False)
instance.published_date = request.published_date
instance.author = request.user
instance.save()
context = {
'form': form
}
return render(request, 'shots/add_shot.html', context)
You'll need to do it in your view. When you save your form pass commit=False to your save method, add your user, then save the returned instance.
def my_view(request):
form = AddShot(request.POST)
instance = form.save(commit=False)
instance.author = request.user
instance.save()
Documented here: https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/#the-save-method

How to create several custom User models and be able to customize their admin forms?

EDIT I reformulated the question here
I want to create several custom user models extending django.contrib.auth.models.User, with the following features:
some specific fields
a nice admin, i.e., for each model, an admin form that I can customize easily (eg. show/hide some fields, both from the parent django.contrib.auth.models.User and the child model).
I almost managed to do it with the code below, but I still have an issue: the password is cleared every time I want to modify an instance of MyUser1 or MyUser2 from the admin.
Is it the best way to do it? If so, how can I fix this cleared password issue?
models.py
from django.db import models
from django.contrib.auth.models import User
class MyUser1(User):
#add more fields specific to MyUser1
class MyUser2(User):
#add more fields specific to MyUser2
admin.py
class MyUser1AdminForm(forms.ModelForm):
class Meta:
model = MyUser1
def __init__(self, *args, **kwargs):
super(MyUser1AdminForm, self).__init__(*args, **kwargs)
self.fields['password'].widget = forms.PasswordInput()
def save(self, commit=True):
user = super(MyUser1AdminForm, self).save(commit=False)
user.set_password(self.cleaned_data["password"])
if commit:
user.save()
return user
class MyUser1Admin(admin.ModelAdmin):
form = MyUser1AdminForm
admin.site.register(MyUser1, MyUser1Admin)
# same for MyUser2
if you whant for user to enter pass - add new field for pass and check it before commit
class MyUser1AdminForm(forms.ModelForm):
check_pass = forms.CharField(label="Password",widget = forms.PasswordInput(), required=True)
class Meta:
model = MyUser1
exclude = ('password',)
def save(self, commit=True):
user = super(MyUser1AdminForm, self).save(commit=False)
if commit and user.check_password(self.cleaned_data["check_pass"]):
user.save()
return user

Django forms and set initial value to logged in user?

I have a form like so:
from django import forms
from django.contrib.auth.models import User
from django_countries.countries import COUNTRIES
from statuses.models import Status
class StatusForm(forms.Form):
country = forms.ChoiceField(choices=COUNTRIES)
mood = forms.IntegerField()
sleep_quality = forms.IntegerField()
This form is only displayed to the users who are logged in, how can I set request.user so that when the user submits this form, I can associate the form entry to them? My model looks like the following with the the user FK:
from django.db import models
from django.contrib.auth.models import User
from django_countries import CountryField
class Status(models.Model):
user = models.ForeignKey(User)
country = CountryField()
mood = models.SmallIntegerField(default=4)
sleep_quality = models.SmallIntegerField(default=4)
Here is my view for this form as well:
#login_required
def index(request, template_name="status/index.html"):
if request.method == 'POST':
postdata = request.POST
form = StatusForm(postdata)
if form.is_valid():
messages.success(request, 'Something happened, good!')
return redirect(urlresolvers.reverse('profile'))
else:
form = StatusForm()
context = RequestContext(request, { 'form': form })
return render_to_response(template_name, context)
I thought maybe I should create a hiddenfield and store request.user in there but that does not seem safe as it can easily be edited with firebug and such. Any suggestions as to how I can store request.user for this form?
Thanks!
The current user will be present in the request as request.user so you don't need to include it in the form. Instead why not leverage ModelForms as they will deal with linking your object to your form.
class StatusForm(forms.ModelForm):
country = forms.ChoiceField(choices=COUNTRIES)
# The other fields are automatically included, we just overwrite country
class Meta:
model = Status
exclude = ("user")
Then in your view:
...
form = StatusForm(request.POST):
if form.is_valid():
# Because your model requires that user is present, we validate the form and
# save it without commiting, manually assigning the user to the object and resaving
obj = form.save(commit=False)
obj.user = request.user
obj.save()
messages.success(request, 'Something happened, good!')
return redirect(urlresolvers.reverse('profile'))
...

Django "last_login" attribute in auth_user model

It looks like Django does not update last_login field in auth_user model when a visitor is authenticated by saved session.
So in this case, how can I implement a similar feature like the "seen" field on every SO user's profile page.
Supposed that you have last_seen_on and last_activity_ip fields in your custom UserProfile model, here is a simple middleware class that does what you want:
import datetime
class LastSeen(object):
def process_request(self, request):
user = request.user
if not user.is_authenticated(): return None
up = user.get_profile()
up.last_seen_on = datetime.now()
up.last_activity_ip = request.META['REMOTE_ADDR']
up.save()
return None