I currently have a Django form that saves data from a questionnaire against a user, where a user is stored as a Foreign Key from the Person model. I can successfully find the person from the Person class using get_object_or_404(), but when I try to save(commit=True), the data is not being saved in the database. See below for my code:
# models.py
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=100)
email = models.EmailField(max_length=254, primary_key=True)
tel_number = models.CharField(max_length=13, blank=True)
referral_code = models.UUIDField()
class Meta:
verbose_name_plural = 'People'
def __str__(self):
return str(self.referral_code)
class Questionnaire(models.Model):
user = models.ForeignKey(Person, related_name='questionnaire_person', on_delete=models.CASCADE)
... and some questionnaire questions here (CharFields and TextFields) ...
# views.py
def index_questionnaire(request):
template = 'questionnaire.html'
# load blank instance of template
questionnaire = UserQuestionnaire()
context = {
"questionnaire": questionnaire
}
# if user has submitted something, check form is valid
if request.method == 'POST':
answers = UserQuestionnaire(data=request.POST)
if answers.is_valid():
# submission is genuine so save as new entry to database
# get user's unique referral ID from URL
user_referral_id = request.GET.get('user')
# check legit person
try:
answers.save(commit=False)
answers.person = get_object_or_404(Person, referral_code=user_referral_id)
print('user found: {}'.format(answers.person))
answers.save(commit=True)
print('Questionnaire saved')
except:
print("user not found")
return render(
request,
template,
context
)
#forms.py
class UserQuestionnaire(forms.ModelForm):
class Meta:
model = Questionnaire
fields = (
'answers_1',
'free_text_1',
'answers_2',
'answers_3',
'answers_4',
'answers_5',
'answers_6'
)
widgets = {
'answers_2' : forms.RadioSelect(),
'answers_3' : forms.RadioSelect(),
'answers_4' : forms.RadioSelect(),
'answers_5' : forms.RadioSelect(),
}
So at the moment I'm drawing the user parameter from the URL, which is uuid.uuid4(). The print statement in the "try: except" bit successfully prints out the user UUID as expected, yet when submitted it doesn't save correctly. For further info, I am using the MultiSelectField() for one of the questionnaire questions.
If anyone has any suggestions as to why this might be, that would be amazing!
That is because asnwers.save(commit=False) creates another new object.
Do something like
f = answer.save(commit=false)
f.person = get_object_or_404(Person, referral_code=user_referral_id)
f.save()
No need to do f.save(commit=True) since the True is default.
for more info check docs:
docs.djangoproject.com/en/3.1/topics/forms/modelforms/
Related
I am learning Django, using function based views, and I am struggling with the following:
I have this path in urls.py
path('user/<str:username>',views.UserProjectList,name='user-projects')
that is supposed to show all the projects of the particular user (client). In order to reach it, username should be parameter of the function based view, however I am struggling how to write such view...
I have this:
def UserProjectList(request,username):
user = User.objects.get(username=username) #THIS IS WRONG and should return id of the user
#user = User.objects.filter(username=username) #also wrong
tag_list = ProjectTagsSQL.objects.all() #ProjectTagsSQL and ProjectSQL are connected
project_list = ProjectSQL.objects.filter(client=user) #ProjectSQL table has column client_id (pk is id in User) and table contains all the projects
context = {
'tagy' : tag_list,
'projecty' : project_list
}
return render(request, 'home_page/user_projects.html', context) #SHOULD THE PARAMETER BE INCLUDED HERE?
I tried to inspire with the code from class based view I found on the internets (thats is working for me but i didnt manage to connect it with ProjectTagsSQL as i managed in FBV, but that's a different problem) but i didnt manage
class UserProjectListView(ListView):
model = ProjectSQL
template_name = 'home_page/user_projects.html'
context_object_name = 'data'
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return ProjectSQL.objects.filter(client=user)
Could someone help me how to deal with such function based view please? As this solution its not working (will return nothing for any user)
Here is also the ProjectSQL model (and ProjectTagsSQL model) :
class ProjectSQL(models.Model):
id = models.AutoField(primary_key=True)
country = models.TextField()
city = models.TextField()
time_added = models.DateTimeField(default=timezone.now)
start_date = models.DateField()
end_date = models.DateField()
client = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
managed = False #https://docs.djangoproject.com/en/4.0/ref/models/options/
db_table = 'project'
class ProjectTagsSQL(models.Model):
id = models.IntegerField(primary_key=True)
project = models.ForeignKey(ProjectSQL, on_delete=models.CASCADE)
tag = models.ForeignKey(ProjectTagSQL, on_delete=models.CASCADE)
class Meta:
managed = False # https://docs.djangoproject.com/en/4.0/ref/models/options/
db_table = 'project_tags'
You need to write user.id so:
from django.shortcuts import get_object_or_404
def UserProjectList(request,username):
user = get_object_or_404(User,username=username)
tag_list = ProjectTagsSQL.objects.all()
project_list = ProjectSQL.objects.filter(client=user.id)
context = {
'tagy' : tag_list,
'projecty' : project_list
}
return render(request, 'home_page/user_projects.html', context)
Also, try to check template variables' name, whether you used same or not.
Note: Always append / at the end of every route so it should be path('user/<str:username>/'....
Note: Function based views are generally written in snake_case so it is better to name it as user_project_list instead of UserProjectList.
This are my models:
class PersoonGegevens(models.Model):
# Voornaam en achternaam
voornaam = models.CharField(max_length=265,)
achternaam = models.CharField(max_length=265)
#username
user = models.OneToOneField(User, on_delete=models.CASCADE)
class inkomen(models.Model):
pg = models.ForeignKey(PersoonGegevens, on_delete=models.CASCADE)
inkomenfield = models.CharField(max_length=100)
This is the form:
class inkomenForm(forms.ModelForm):
class Meta():
model = inkomen
fields = ('inkomenfield',)
This is my view:
def tijdelijk(request):
#User id
user = request.user.id
if request.method == 'POST':
incoming = inkomenForm(data=request.POST)
if incoming.is_valid():
incoming.save()
return HttpResponse("saved")
else:
x = incoming.errors
print (x)
return HttpResponseRedirect('/tijdelijk')
else:
incoming = inkomenForm()
return render(request, 'index/tijdelijkeindex.html', {'inkomen':incoming})
I have tried:
incoming.save(commit=False)
incoming.pg = user
incoming.save
also readed the documentation about Inline formsets of django. But i dont really get
So i get the following error:(NOT NULL constraint failed) and i know it comes because i need to assign the pg.id and i know i can do that by adding the field in the form.py and let the user choose the id. But what i actually want is that pg = the logged in user.
You need to assign the return value of form.save(commit=False) to a variable, the return value is the created (but not committed to the database) model object
obj = incoming.save(commit=False)
obj.pg = user
obj.save()
Hi im following the tango with django tutorial.. I've searched for a solution to this but nothing!
the error:
IntegrityError at /rango/add_category/
UNIQUE constraint failed: rango_category.name
my model:
from django.db import models
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
def __unicode__(self):
return self.name
class Page(models.Model):
category = models.ForeignKey(Category) #ForeignKey denotes a relationship between page and category
title = models.CharField(max_length=128)
url = models.URLField()
views = models.IntegerField(default=0)
def __unicode__(self):
return self.title
my add_category view:
def add_category(request):
# Get the context from the request.
context = RequestContext(request)
# A HTTP POST?
if request.method == 'POST':
form = CategoryForm(request.POST)
#Have we been provided with a valid form?
if form.is_valid():
#save the new category to the database
form.save(commit=True)
# Now call the index() view.
# The user will be shown the Homepage.
return index(request)
else:
# The supplied form contained errors - just print them to the terminal
print (form.errors)
else:
form = CategoryForm()
# Bad form (or form details), no form supplied...
# Render the form with error message(if any).
return render_to_response('rango/add_category.html', {'form':form}, context)
my forms:
from django import forms
from rango.models import Page, Category
class CategoryForm(forms.ModelForm):
names = forms.CharField(max_length=128, help_text="please enter the category name.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
likes = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
#an inline class to to provide additional information on the form
class Meta:
# provide an association between the Modelform and a model
model = Category
fields = ('views', 'likes')
class PageForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="Please enter the title of the page")
url = forms.URLField(max_length=200, help_text="Please enter the url of the page")
views = forms.IntegerField(widget=forms.HiddenInput(),initial=0)
class Meta:
# Provide an association between the ModelForm and a model
model = Page
#what fields do we want to include in our form
# this way we dont need every field in the model present
# Some fields may allow NULL values, so we may not want to include them...
# Here we are hiding.
fields = ('title', 'url', 'views')
'name' field is missing in CategoryForm's Meta 'fields'. Since Category::name is a unique field and default is not possible, any attempt to save will fail.
If the model does not allow the missing fields to be empty, and does
not provide a default value (not possible for unique) for the missing fields, any attempt to save() a ModelForm with missing fields will fail.
I have spent a good few hours looking over the documentation and on here as well and i still can't find an answer to my issue. please if you know of one direct me to it. otherwise please look at the following issue. I receive a KeyError when trying to register a user as a host for an open source homestay project im working on: https://github.com/castaway2000/OpenStay this is yet to be pushed to the master branch. i have tried setattr() and instance as well. something just isn't clicking with me on this one.
models.py
class HostRegistration(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
address = models.CharField(max_length=200)
city = models.CharField(max_length=100)
state = models.CharField(max_length=30)
zipcode = models.CharField(max_length=15)
country = models.CharField(max_length=30)
# Override the __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.user
forms.py
class HostForm(forms.ModelForm):
#no need for charfields here because we refrence the model with the fields
class Meta:
model = HostRegistration
fields = ['address', 'city', 'state', 'zipcode', 'country']
views.py - the problem starts here XD
# become a host
def host_register(request):
user = request.user
if user.is_authenticated:
if request.method == 'POST':
host_form = HostForm(data=request.POST)
if host_form.is_valid():
host_form.fields['user'].instance = user.id # this is where its failing.
host = host_form.save(commit=False)
print host
host.save()
return HttpResponseRedirect('/edit_userpage/')
else:
print host_form.errors
else:
return HttpResponseRedirect('/')
guide_form = HostForm()
context = {'guide_form': guide_form}
return render(request, 'users/host.html', context)
please let me know how to access the model object 'user' in my views and save the currently logged in user as a reference to it with the modelform. it would be great help.
i found the answer.
i changed my model.py to
class HostRegistration(models.Model):
# user is the changed variable
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
address = models.CharField(max_length=200)
city = models.CharField(max_length=100)
state = models.CharField(max_length=30)
zipcode = models.CharField(max_length=15)
country = models.CharField(max_length=30)
# Override the __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.user
and i updated my views.py to:
def host_register(request):
user = request.user
if user.is_authenticated:
if request.method == 'POST':
host_form = HostForm(data=request.POST)
if host_form.is_valid():
instance = host_form.save(commit=False) # this is the trick.
instance.user = request.user # and this to get the currently logged in user
instance.save() # to commit the new info
return HttpResponseRedirect('/edit_userpage/')
else:
print host_form.errors
else:
return HttpResponseRedirect('/')
guide_form = HostForm()
context = {'guide_form': guide_form}
return render(request, 'users/host.html', context)
Does it work if you do host_form.cleaned_data.get("user") instead of host_form.fields['user'].instance?
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='oser')
picture = models.ImageField(upload_to='profile_images', blank=True)
So, I've added picture to user profile , it works good , but I can't access picture to show it in user profile
view.py:
def profile(request):
if request.user.is_authenticated():
user = User.objects.get_by_natural_key(request.user.get_username())
t = loader.get_template("profile.html")
c = Context({'user2': user, })
return HttpResponse(t.render(c))
else:
raise Http404
What I've found in django docs
class Employee(models.Model):
user = models.OneToOneField(User)
department = models.CharField(max_length=100)
u = User.objects.get(username='fsmith')
freds_department = u.employee.department
However, this doesn't work for me , I just can't get UserProfile.picture
u = User.objects.get(username= request.user.get_username())
s = u.UserProfile.picture
What I'm doing wrong?
You should use "related name", which specified in foreign key field, to access user profile, not class name:
s = u.oser.picture
By default "related_name" is the same as related model class name, but in lowercase. You specified related_name="oser".