"Todos.user" must be a "UserProfile" instance - django

Getting Error "Todos.user" must be a "UserProfile" instance. can someone explain why?
I want users in Todos should point to UserProfile and whatever I save in Todos should be displayed in /profile/ ?
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(UserProfile)
title = models.CharField(max_length=100)
created = models.DateField()
start_time = models.TimeField()
end_time = models.TimeField()
def __unicode__(self):
return unicode(self.user)
Form
class todosform(ModelForm):
title = forms.CharField(label=(u'Todo'))
created = forms.DateField(label=(u'Date'))
start_time = forms.TimeField(label=(u'Start Time'))
end_time = forms.TimeField(label=(u'End Time'))
#user = forms.CharField(label=(u'username')
class Meta:
model = Todos
exclude=('user',)
#url todo url(r'^todo/$', 'registration.views.todo'),
def todo(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.user = request.user
form.save()
return HttpResponseRedirect('/profile/')
else:
form = formtodos()
context = {'form':form}
return render_to_response('todo.html', context, context_instance=RequestContext(request))
#url profile url(r'^profile/$', 'registration.views.Profile'),
#login_required # decorator to check if request login
def Profile(request):
if not request.user.is_authenticated(): #if user not logged in
return HttpResponseRedirect('/login/')
#model = request.user.todos_set.all().order_by('created')[:7]
#u = Todos.objects.filter(created_by = request.user).get(pk=user)
registration = request.user.get_profile
context = {'registration':registration }
return render_to_response('profile.html',context,context_instance=RequestContext(request))

Your user field on Todos is a ForeignKey to UserProfile, not User. request.user is an instance of User. You could to this:
todoss.user = request.user.get_profile()

Related

Handling form fields in django for logged in user

Im trying to handle the existing name of a Category, so that users wont be allowed to create 2 categories with the same name, but at the moment its taking all categories from the database, not only for the logged-in user. I dont know how and where to implement request.user.
I`m building an inventory app where everyone creates their own categories and adds items.
Thank you.
This is my model:
class Category(models.Model):
user = models.ForeignKey(User, default=1, on_delete=models.CASCADE,
related_name='category', null=True)
name = models.CharField(max_length=100, null=False, blank=False)
slug = models.SlugField(max_length=100)
created_on = models.DateTimeField(auto_now_add=True)
timestamp = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-timestamp']
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('category_detail', kwargs={'slug': self.slug})
This is my form:
class CategoryForm(forms.ModelForm):
add_category = forms.BooleanField(widget=forms.HiddenInput, initial=True)
class Meta:
model = Category
fields = ['name']
def clean_name(self):
name = self.cleaned_data.get('name')
if (name == ""):
raise forms.ValidationError('This field cannot be left blank')
for instance in Category.objects.all():
if instance.name == name:
raise forms.ValidationError('There is a category with the name ' + name)
return name
This is my view:
#login_required
def index(request):
categories = Category.objects.filter(user=request.user)
items = Item.objects.all()
add_item = ItemForm()
add_category = CategoryForm()
query = None
if request.method == 'POST':
if 'add_item' in request.POST:
add_item = ItemForm(request.POST)
if add_item.is_valid():
form = add_item.save(commit=False)
form.category = get_object_or_404(
Category, name=request.POST.get('category'),
user=request.user)
add_item.save()
return redirect('home')
else:
add_category = CategoryForm(request.POST)
if add_category.is_valid():
category_form = add_category.save(commit=False)
category_form.save()
messages.success(request, f'{name} has been added')
return redirect('home')
Edit Category View
#login_required
def category_edit(request, pk):
category = Category.objects.get(id=pk)
if request.method == 'POST':
form = CategoryForm(request.POST, instance=category)
if form.is_valid():
form.save()
messages.info(request, f'{category.name} has been updated!')
return redirect('home')
else:
form = CategoryForm(instance=category, user=request.user)
context = {
'form': form,
}
return render(request, 'category_edit.html', context)
Ive tried adding user = request.user in the form class, but that resulted in an error Ive tried adding category_form.user = request.user before saving the form but that was still taking names from every other user
Pass the request's user to the form:
class CategoryForm(forms.ModelForm):
add_category = forms.BooleanField(widget=forms.HiddenInput, initial=True)
def __init__(self, user, *args, **kwargs):
self.user = user
super().__init__(*args, **kwargs)
class Meta:
model = Category
fields = ['name']
def clean_name(self):
name = self.cleaned_data.get('name')
if (name == ""):
raise forms.ValidationError('This field cannot be left blank')
qs = Category.objects.filter(user=self.user, name=name)
if self.instance.pk:
# EXCLUDE CURRENT INSTANCE TO ENABLE EDIT
qs = qs.exclude(pk=self.instance.pk)
if qs.exists():
raise forms.ValidationError('There is a category with the name ' + name)
return name
then in the view you need to pass the user:
#login_required
def index(request):
categories = Category.objects.filter(user=request.user)
items = Item.objects.all()
add_item = ItemForm()
add_category = CategoryForm(user=request.user)
query = None
if request.method == 'POST':
if 'add_item' in request.POST:
add_item = ItemForm(request.POST)
if add_item.is_valid():
form = add_item.save(commit=False)
form.category = get_object_or_404(
Category, name=request.POST.get('category'),
user=request.user)
add_item.save()
return redirect('home')
else:
add_category = CategoryForm(user=request.user, data=request.POST)
if add_category.is_valid():
category_form = add_category.save(commit=False)
category_form.save()
messages.success(request, f'{name} has been added')
return redirect('home')

ModelForm inserts number in foreign key field

I have model from which I created a ModelForm:
models.py:
class City(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return f'{self.name}'
class Profile(models.Profile):
name = models.CharField(max_length=50)
user = models.OneToOneField(User, on_delete=models.CASCADE, unique=False)
location = models.ForeignKey('City', on_delete=models.SET_NULL, blank=True, null=True)
forms.py
from django import forms
from .models import Profile, City
class LocationField(forms.CharField):
def clean(self, value):
try:
city = City.objects.get(name=value)
except ObjectDoesNotExist:
city = City.objects.create(name=value)
return city
class ProfileForm(forms.ModelForm):
location = LocationField()
class Meta:
model = Profile
exclude = ['user']
views.py
def profile_update_view(request):
template_name = 'profiles/update.html'
user = request.user
profile = Profile.objects.get(user__id=user.id)
if request.method == 'GET':
form = ProfileForm(instance=profile)
else:
form = ProfileForm(request.POST, instance=profile)
if form.is_valid():
obj = form.save(commit=False)
obj.user = user
obj.save()
return redirect('profile_view')
context = {'form': form}
return render(request, template_name, context=context)
When I'm saving form, I'm satisfied how it's working, but when I load form again to update in, it fills LocationField() as an City pk integer, but I want it to load name instead. Is there a way to do this?
I've added in views.py:
if request.method == 'GET':
initial = {}
if profile.location:
initial = {'location': profile.location.name}
form = ProfileForm(instance=profile, initial=initial)
now it's working. But it's some workaround. I've thought there is some parameter maybe

Django form : Setting the user to logged in user

I am trying to create an address book website where logged in user is able to fill in a form and store contact information. I was able to implement the login and logout functionality. But the problem is that I am not able to set the username to current logged in user. Here is what I have implemented so far:
Models.py
class UserProfileInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True)
#additional
def __str__(self):
return self.user.usernname
class UserContacts(models.Model):
current_user = models.ForeignKey(User,on_delete=models.CASCADE)
first_name = models.CharField(max_length = 150)
last_name = models.CharField(max_length = 150)
phone_number = models.CharField(max_length = 150)
email_address = models.CharField(max_length = 150)
street_address = models.CharField(max_length = 350)
def __str__(self):
return '{}'.format(self.first_name)
Forms.py
class UserForm(forms.ModelForm):
password = forms.CharField(widget = forms.PasswordInput())
class Meta():
model = User
fields = ('username','email','password')
class UserContactForm(forms.ModelForm):
class Meta():
model = UserContacts
fields = "__all__"
views.py:
#login_required
def new_contact(request):
form = UserContactForm()
current_user = request.user.get_username()
user = User.objects.filter(username=current_user).first()
output = UserContacts.objects.filter(current_user_id=user.id).first()
if request.method == "POST":
form = UserContactForm(request.POST)
if form.is_valid():
form.save(commit=True)
return index(request)
else:
print('Error Form Invalid')
return render(request,'basic_app/contact.html',{'form':form})
Here is how the output looks like when the logged in user tries to enter contact information details:
Updating contact screenshot. As you can see the current user has to select his username to fill out the contact information.
How to overcome this and by default set the username in the form to the current logged in user
Change your UserContactForm to include an extra perameter in __init__, and set the initial value on the user field:
class UserContactForm(forms.ModelForm):
class Meta():
model = UserContacts
fields = "__all__"
def __init__(self, *args, **kws):
# To get request.user. Do not use kwargs.pop('user', None) due to potential security hole
self.user = kws.pop('user')
super().__init__(*args, **kws)
self.fields['user'].initial = self.user
Then change you view to add in the request.user to the form construction:
#login_required
def new_contact(request):
form = UserContactForm(user=request.user)
current_user = request.user.get_username()
user = User.objects.filter(username=current_user).first()
output = UserContacts.objects.filter(current_user_id=user.id).first()
if request.method == "POST":
form = UserContactForm(request.POST, user=request.user)
if form.is_valid():
form.save(commit=True)
return index(request)
else:
print('Error Form Invalid')
return render(request,'basic_app/contact.html',{'form':form})
You could probably remove the:
current_user = request.user.get_username()
user = User.objects.filter(username=current_user).first()
output = UserContacts.objects.filter(current_user_id=user.id).first()

Django: Create profile page creates everything except Multiple Choice Field in the database

I am using the same form for profile_edit and create_profile functionality. It is updating the multi-choice values in the profile_edit page but does not create in create_profile.
Below is the form code in forms.py
class ProfileForm(ModelForm):
full_name = forms.CharField(required=True)
current_position = forms.CharField(required=True)
about_me = forms.Textarea(attrs={'required':True})
topic_name = forms.ModelMultipleChoiceField(Topic.objects.all())
class Meta:
model = Profile
fields =(
"full_name",
"current_position",
"about_me",
"topic_name",
)
Below is the views.py for profile creation
def create_profile(request, user_id):
if request.method == "POST":
form = ProfileForm(request.POST)
if form.is_valid():
form = form.save(commit=False)
user = get_object_or_404(User, id=user_id)
form.user = user
print(form.topic_name.all()) # Prints empty queryset
form.save()
return redirect("profile_view", user_id=user_id)
else:
context = {"form": form}
return render(request, "profile/create_profile.html", context)
else:
form = ProfileForm()
context = {
"form": form
}
return render(request, "profile/create_profile.html", context)
Below is Model.py
class Topic(models.Model):
topic = models.CharField(max_length=12)
def __str__(self):
return self.topic
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True,)
full_name = models.CharField(max_length=60, null=True)
current_position = models.CharField(max_length=64, null=True)
about_me = models.TextField(max_length=255, null=True)
topic_name = models.ManyToManyField(Topic)
def __str__(self):
return self.full_name
Both create_profile and edit_profile templates are exactly the same.
It saves everything except Multichoice field.
When you do save(commit=False),
you need to use mymodelform.save_m2m() below save(commit=True) on your ModelForm,
because many to many relationships cannot be saved without an ID.
see this docs
so in your views.py
if form.is_valid():
profile = form.save(commit=False)
user = get_object_or_404(User, id=user_id)
profile.user = user
profile.save()
form.save_m2m()
return redirect("profile_view", user_id=user_id)

what causes the weird "UNIQUE constraint failed: auth_user.username" error?

I try to insert data in user model into other model by one to one relationship. In specific, I want insert username,email and password attributes of User into other models.In Addtional, I intend to create both User model and other model in one form. So, I override the save method in modelform. It works partially and be able to insert data in both models and databases, except throw a UNIQUE constraint failed: auth_user.username error.
In models.py
class Staff(models.Model):
yes_or_no = ((True, 'Yes'),(False, 'No'))
male_or_female = ((True,'Male'),(False,'Female'))
user = models.OneToOneField(User, unique=True)
gender = models.BooleanField(default = True, choices = male_or_female)
birthday = models.DateField(default =None,blank = False, null = False)
created = models.DateTimeField(default=datetime.now, blank=True)
authorized = models.BooleanField(default=False,choices = yes_or_no)
store_id = models.ForeignKey(Store,default=1)
#property
def name(self):
return self.user.username
#property
def email(self):
return self.user.email
#property
def password(self):
return self.user.password
#property
def first_name(self):
return self.user.first_name
#property
def last_name(self):
return self.user.last_name
def __str__(self):
return self.user.username
In forms.py
class StaffForm(forms.ModelForm):
name = forms.CharField(max_length=100)
email= forms.EmailField(max_length=100, required=True)
password = forms.CharField(max_length=50)
store_id = forms.ModelChoiceField(queryset = Store.objects.all(),empty_label="--------") # select values ?
first_name = forms.CharField(required = True,max_length=100)
last_name = forms.CharField(required = True,max_length=100)
class Meta:
model = Staff
fields = ('gender','birthday','authorized','store_id')
widgets = {'authorized':forms.RadioSelect,
'gender':forms.RadioSelect,
'birthday':SelectDateWidget(years=range(date.today().year-50,date.today().year))
}
def save(self,*args,**kwargs):
Staff = super(StaffForm,self).save(commit=False)
user = User.objects.create(
username=self.cleaned_data['name'],
first_name=self.cleaned_data['first_name'],
last_name = self.cleaned_data['last_name'],
email= self.cleaned_data['email'])
user.set_password(self.cleaned_data['password'])
if self.cleaned_data['authorized']:
user.is_staff = True
Staff.user = user
Staff.save()
In views.py
#login_required(login_url='/dataInfo/login/')
def createstaff(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = StaffForm(request.POST or None)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
form.save()
return HttpResponseRedirect('/dataInfo/staff_view/')
# if a GET (or any other method) we'll create a blank form
else:
form = StaffForm()
return render(request, 'dataInfo/create_staff.html', {'form': form})