I'm using django-registration for registration and login purpose. My Models and Forms.py are working fine. The problem is I want to store the currently logged user's id in the user field of the following Model:
MALE = 1
FEMALE = 2
SEX_CHOICES = (
(MALE,'Male'),
(FEMALE,'Female'),
)
class UserProfile(models.Model):
#user = models.IntegerField() # update : Changed to ForeignKey.
user = models.ForeignKey(User)
gender = models.IntegerField(choices = SEX_CHOICES,null=True, blank=True)
zip_code = models.CharField(max_length=100,null=True, blank=True)
language = models.ManyToManyField(Category)
My ModelForm:
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
widgets = {'language': forms.CheckboxSelectMultiple}
Update 2: Here is my view:
def some_view(request):
if request.method == 'POST':
form = UserProfileForm(request.POST)
if form.is_valid():
form.save()
else:
form = UserProfileForm()
Update: I can get currently logged in user's using {{ user.id }} in template. But now How do i pass this id to user field?
Well, in you view you can access the currently logged user via request.user.
Make this user initial data in your Form :
#login_required
def my_view(request):
logged_user = request.user
initial = {'user': logged_user}
form = MyForm(request.POST or None, initial=initial)
# Here your logical code
# ...
return HttpResponse(...)
And if you are using a ModelForm:
#login_required
def my_view(request):
logged_user = request.user
form = MyUserProfileModelForm(
request.POST or None,\
instance=logged_user.get_profile())
# Here your logical code
# ...
return HttpResponse(...)
Note: get_profile() is a OneToOneField and may raise a DoesNotExist exception if your database is screwed (which may happen if you have tried different things here).
Related
I am in the middle of a project. I have extended the custom django user and modified it.
this is my user model:-
class User(AbstractUser):
name = models.CharField(max_length=200, null=True, blank=True)
usertype = models.CharField(choices = [('d','doctor'), ('p','patient')], max_length=1)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = []
def __str__(self):
return self.name
Also I have declared two seperate models named Patient and Doctors. My objective is to register the users in their respective models(Doctors or Patients) by checking the usertype.
Here are those models:-
class Patient(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='patient')
dob = models.DateField(null=True, blank=True)
contact = models.CharField(null=True, blank=True, max_length=100)
def __str__(self):
return self.user.name
class Doctor(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='doctor')
deg = models.TextField(null=True, blank=True)
def __str__(self):
return self.user.name
Now at the front end I want to apply the logic as every time a user is registered the user selects the usertype and based on that selection the Doctor or the Patient module is updated.
I have tried creating separate forms for that too.
Here are my forms :-
class MyUserCreation(UserCreationForm):
class Meta:
model = User
fields = ['name','username','usertype']
class DoctorCreation(ModelForm):
class Meta:
model = Doctor
fields = ['user','deg']
class PatientCreation(ModelForm):
class Meta:
model = Patient
fields = ['dob', 'contact','user']
The view handling this URL is :-
def registerUser(request):
page = 'general'
form = MyUserCreation()
if request.method == 'POST':
form = MyUserCreation(request.POST)
if form.is_valid:
user = form.save(commit=False)
user.save()
login(request, user)
return redirect('home')
else:
messages.error(request, 'Error occured')
if user.usertype == 'p':
page = 'patient'
form = PatientCreation()
form = PatientCreation(request.POST)
if form.is_valid:
form.save()
elif user.usertype== 'd':
page = 'doctor'
form = DoctorCreation()
form = DoctorCreation(request.POST)
if form.is_valid:
form.save()
context = {'form':form, 'page':page}
return render(request, 'rec/register_user.html', context )
The front end for this project is handled with very basic HTML.
Also, if possible I want the front end such that every time a user is registered and the usertype is selected(which is a dropdown menu) some more fields show up depending on the usertype selection by the user. If selected Doctor the additional fields respective to the Doctor module show up, and same for the patient module.
To keep it simple on the front end this solution works like:
Loads Page with User Form
Submit User Form
Uses value to Load Next form
Submit Next Form + Redirect
Notes:
Uses the Values POSTed to determine what form is being submitted
Uses Initial to set User for the 2nd Form
This current flow could be broken up into 3 view with their own distinct URLs
Django View
def registerUser(request):
form = None
if request.method == 'POST':
valid = False
if 'usertype' in request.POST:
# 1st form submit
form = MyUserCreation(request.POST)
if form.is_valid:
valid = True
user = form.save(commit=False)
user.save()
login(request, user)
# Get 2nd form for load
if user.usertype == 'p':
page = 'patient'
form = PatientCreation(initial={'user':user})
elif user.usertype== 'd':
page = 'doctor'
form = DoctorCreation(initial={'user':user})
else:
# 2nd form submit
if 'dob' in request.POST:
form = PatientCreation(request.POST)
if form.is_valid:
form.save()
valid = True
elif 'deg' in request.POST:
form = DoctorCreation(request.POST)
if form.is_valid:
form.save()
valid = True
if valid:
# form sequence done
return redirect('home')
if not valid:
# a form failed somewhere
print(form.errors)
messages.error(request, 'Error occured')
if form == None:
page = 'general'
form = MyUserCreation()
context = {'form':form, 'page':page}
return render(request, 'rec/register_user.html', context )
Basic Django HTML Form
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
Now you could make this a single page by making the Template more complex, with JQuery Hiding/Showing extra fields based on dropdown Value on Change, but I assumed this would be the route you wanted.
Edit
To make the field disabled you'd just edit the forms.py
Note: the form-control is just showing that you can also add classes + extra attributes if you need to
class PatientForm(forms.ModelForm):
class Meta:
model = RunRequest
fields = (
'user',
'dob',
'contact',
)
def __init__(self, *args, **kwargs):
super(PatientForm, self).__init__(*args, **kwargs)
self.fields['user'].widget.attrs={'class': 'form-control', 'disabled':True}
I am trying to extend the Django User model by creating a user Profile model. When users register for the site, I want them to be able to select what class period they are in. To do this, I've tried to create a form that alters the User model, and a form that alters the Profile model. The problem is that when I try to put both forms into 'users/register.html' I am getting an error that says 'Anonymous User has to data _meta'. Below is my original code that only has the form for altering the User model in 'users/register.html'. How can I configure the registration so that users are able to save to the User and Profile model when they are first signing up for the site?
models.py
class Profile(models.Model):
'''
periods = [
('-','-'),
('1','1'),
('2','2'),
('3','3'),
('4','4'),
('6','6'),
('7','7'),
]
'''
user = models.OneToOneField(User,on_delete=models.CASCADE)
period = models.IntegerField(default=1)
first_name = models.CharField(max_length=100,default='Home')
last_name = models.CharField(max_length=100,default='Simpson')
def __str__(self):
return f'{self.user.username}'
forms.py
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username','email','password1','password2']
class UserProfileForm(forms.ModelForm):
periods = [
(1,1),
(2,2),
(3,3),
(4,4),
(6,6),
(7,7),
]
period = forms.ChoiceField(choices=periods)
first_name = forms.CharField(max_length=100)
last_name = forms.CharField(max_length=100)
class Meta:
model = Profile
fields = ['first_name','last_name','period']
signals.py
#receiver(post_save,sender=User)
def create_profile(sender,instance,created,**kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save,sender=User)
def save_profile(sender,instance,**kwargs):
instance.profile.save()
views.py
def login(request):
context = {
'title':'Login',
}
return render(request,'users/login.html',context)
def register(request):
if request.method == "POST":
form = UserRegisterForm(request.POST)
if form.is_valid():
email = form.cleaned_data.get('email')
email_domain = re.search("#[\w.]+", email)
if email_domain.group() == EMAIL_DOMAIN:
form.save()
username = form.cleaned_data.get('username')
messages.success(request,f'Account created for {username}! You are now able to sign in.')
return redirect('users-login')
else:
messages.error(request,f'Sorry. You are not authorized to register.')
else:
form = UserRegisterForm()
context = {
'title':'Register',
'form':form
}
return render(request,'users/register.html',context)
This is happening because you are putting both the forms in the register page . When you have not created any user so how you can create a profile and how would you be able to add or retrieve data from it?
Now the solution for that is ,
1 . You create a page for registering the user say "users/register.html" , when they successfully register there, create a signal for creating the Profile for him , then successfully log the user in . Then redirect the just registered user to the profile change page.
Take both the forms in the user register page but do not validate the profile_change form .Create the user in the view and then reference it to the profile_change_form .
A simple code bit for that .
def registerUser(request) :
if request.method == "POST" :
user_form = UserRegisterForm(request.POST)
if user_form.is_valid():
username = request.POST.get("username")
# fields you require
user = User(username = username , password = password)
user.save()
profile_field_objects = request.POST.get("profile_field_data")
profile = Profile(user = user , profile_field_objects = profile_field_objects)
profile.save()
# rest you can code
I'm creating a questionnaire / survey, and have two forms (Model Form) built on the same model. These forms are called on separate views, but when saved they appear as separate users in the database. I'm not sure how to get them so save as the same user, I am already using the ' post = form.save(commit=False), post.user = request.user, post.save()' method to save the forms.
EDIT: Added in an attempt to save to the same instance
Model:
class QuizTakers(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
industry_choices = (
(1, 'Service'),
(2, 'Hospitality'),
(3, 'Wholesale/Retail'),
(4, 'Manufacturing'),
(5, 'Agriculture')
)
industry = MultiSelectField(choices=industry_choices, max_length=1, max_choices=1)
company_name = models.CharField( max_length=100)
email = models.EmailField(blank=True)
score = models.FloatField(default=0)
completed = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.company_name
Forms:
# Form for getting company name
class QuizTakerForm(forms.ModelForm):
class Meta:
model = QuizTakers
fields = ['company_name']
# Form for getting company industry
class QTIndustryForm(forms.ModelForm):
class Meta:
model = QuizTakers
fields = ['industry']
Views:
# view for getting company name
def start(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = QuizTakerForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
request.session['company_name'] = form.cleaned_data['company_name']
post = form.save(commit=False)
post.user = request.user
post.save()
# redirect to a new URL:
return HttpResponseRedirect('industry/')
# if a GET (or any other method) we'll create a blank form
else:
form = QuizTakerForm()
return render(request, 'ImpactCheck/start.html', {'form': form})
# view for getting industry
class IndustryView(FormView):
template_name = 'ImpactCheck/industry.html'
form_class = QTIndustryForm
success_url = '1/'
def get(self, request):
company_name = request.session['company_name']
this_user=QuizTakers.objects.filter(company_name=company_name).order_by('-timestamp').first()
form=self.form_class(instance=this_user)
company_name = request.session['company_name']
return render(request, 'ImpactCheck/industry.html', {'form': form, 'company_name': company_name})
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
post = form.save(commit=False)
post.user = self.request.user
post.save()
return HttpResponseRedirect('/1')
Firstly, in your def start(request) function, you should consider adding the ID to request.session instead of the company name. Something along the lines of
def start(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = QuizTakerForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
form.instance.user=request.user
form.save()
request.session['obj_id'] = post.id
# redirect to a new URL:
return HttpResponseRedirect('industry/')
Now you can use that id to get both the name of your company, as well as the object.
In your IndustryView(FormView), if you're having trouble with the form instances, it's better to use UpdateView instead of the FormView (Be sure to import UpdateView first)
class IndustryView(UpdateView):
template_name = 'ImpactCheck/industry.html'
model = QuizTakers
fields = ['industry']
success_url = '/1'
def get_object(self):
return QuizTakers.objects.get(pk=self.request.session.get('obj_id'))
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['company_name'] = QuizTakers.objects.get(pk=self.request.session.get('obj_id'))
return ctx
We use the get_context_data method since you need the company_name in your template. The get_object method in this view, tells django which object is to be updated. By default, it grabs the pk from the url (as a url parameter). But since we store our id in the session, we need to explicitly define this function.
Also, since we switched to UpdateView, you no longer need the QTIndustryForm either.
I'm trying to limit number of "categories" that user have available when entering new "feed" only to categories that he owns and he created. The way it works now is that user can add "feed" to other users' "categories" as this is what the form displays. How can I fix it ?
thanks!
-M
models.py
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=50)
user = models.ForeignKey(User)
class Feed(models.Model):
url = models.URLField()
name = models.CharField(max_length=50)
created = models.DateTimeField(auto_now_add=True)
description = models.TextField(blank=True)
category = models.ForeignKey(Category)
user = models.ForeignKey(User)
forms.py
class FeedForm(forms.ModelForm):
class Meta:
model = Feed
exclude = ['user']
views.py
def addfeed(request, user):
user = request.user
page_title = "Add feed"
instance = Category.objects.filter(user=request.user)
if request.method == 'POST':
form = FeedForm(request.POST, instance=instance)
if form.is_valid():
feed = form.save(commit=False)
feed.user = request.user
feed.save()
return HttpResponseRedirect("/user/" + user.username + "/manage")
else:
form = FeedForm()
return render(request, "form_manage.html", {
'page_title': page_title,
'form': form,
})
Set the queryset attribute of the field somewhere. Because it depends on your user, it's something you have to set during or after instantiating the form. For instance, here's how to do it in the view:
def addfeed(request, user):
user = request.user # why does this view take user as an arg and then reassign?
page_title = "Add feed"
categories = Category.objects.filter(user=request.user)
if request.method == 'POST':
form = FeedForm(request.POST)
form.fields['category'].queryset = categories
if form.is_valid():
feed = form.save(commit=False)
feed.user = request.user
feed.save()
return HttpResponseRedirect("/user/" + user.username + "/manage")
else:
form = FeedForm()
form.fields['category'].queryset = categories
return render(request, "form_manage.html", {
'page_title': page_title,
'form': form,})
I removed the instance argument to your POST case's form construction because that's meant for passing in an existing Feed instance, not a categories queryset.
You could also do this in the form's __init__ if you pass in the correct categories queryset.
I use javascript to do this. For example, you could pass a list of the relevant categories as extra context in your view then use javascript in your template to empty the pre-populated option field in the form and replace it with your extra context.
I have question regarding how to attach additional form to logged in users in Django.
I want that additional form belongs to logged in user and the data I enter in the form should goes under logged in user table. I am new to Django and python please have patience I hope i can explain correctly what i want to do with this
Data I shall enter for this view shall go under logged in user only basically i want to attach this view to the logged in user only Error I am getting is
Exception Value:
registration_todos.user_id may not be NULL
#models
class userProfile(models.Model):
user = models.OneToOneField(User)
birth =models.DateField()
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class todos(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=100)
created = models.DateField()
time = models.TimeField()
def __unicode__(self):
return unicode(self.user)
#forms additional form for todos
class formtodos(ModelForm):
title = forms.CharField(label=(u'Todo'))
created = forms.DateField(label=(u'Date'))
time = forms.TimeField(label=(u'Time'))
#user = forms.CharField(label=(u'username'))
class Meta:
model = todos
exclude=('user',)
#view
def modeltodo(request):
if request.user.is_authenticated():
todos.objects.filter(user=request.user)
if request.method == 'POST':
form =formtodos(request.POST)
if form.is_valid():# All validation rules pass
todoss = form.save(commit=False)
todoss.created_by = request.user
form.save()
return HttpResponseRedirect('/profile/')
else:
form = formtodos() # An unbound form
context = {'form':form}
return render_to_response('todo.html', context, context_instance=RequestContext(request))
you've specified exclude = ('user',) in your form. This means that when you try to save the form there is no user_id present which causes the error. You probably want to put this before the save() call: todoss.user = request.user