object data editting form - python

I'm making django app which allow me to study. It has multiple tests with multiple question each. Every question has one correct answer. I'm trying to make form which allow me to edit answer If I made mistake in passing correct answer during making question.
That's what I have already made:
models.py
class Question(models.Model):
text = models.CharField(max_length=200, null=True)
test = models.ForeignKey(Test, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add = True)
def get_answer(self):
return self.answer_set.all()
def __str__(self):
return self.text
class Answer(models.Model):
text = models.CharField(max_length=200)
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='parent')
def __str__(self):
return self.text
forms.py
class AnswerEditForm(ModelForm):
class Meta:
model = Answer
exclude = ('question',)
views.py
def UpdateAnswerView(request, pk):
form = AnswerEditForm()
if request.method == 'POST':
form = AnswerEditForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.question = Question.objects.get(id=pk)
obj.save()
return redirect('home')
context = {'form':form}
return render(request, 'exam/update_answer.html', context)
urls.py
urlpatterns = [
~some other urls~
path('answer/edit/<int:pk>/', views.UpdateAnswerView, name='update-answer'),
]
while I'm trying to edit answer i'm getting Question matching query does not exist. error.
Where did i make mistake ?

Probably pk is None.
it is better you check your pk
def UpdateAnswerView(request, pk):
form = AnswerEditForm()
if request.method == 'POST' and pk is not None:
form = AnswerEditForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
try:
obj.question = Question.objects.get(id=pk)
obj.save()
return redirect('home')
except Question.DoesNotExist:
pass
context = {'form':form}
return render(request, 'exam/update_answer.html', context)

You should confirm that pk is actually getting passed to UpdateAnswerView. Also confirm that you're actually passing a Question ID and not an Answer ID.

Related

The view mainsite.views.winner_detail didn't return an HttpResponse object. It returned None instead

Guys I'm losing my freaking mind.
I Keep getting this error after updating a model form.
I've made many of these forms before in previous projects and before and never had this issue.
I've looked at every single question here with the same issue and got nowhere.
this is the view
def winner_edit_form(request, pk):
winner = PrizeWinner.objects.get(id=pk)
if request.method == 'POST':
form = WinnerForm(request.POST, instance=winner)
if form.is_valid():
form.save()
return HttpResponseRedirect('winner-details.html', winner.id)
else:
form = WinnerForm(instance=winner)
return render(request,'edit-winner-form.html',{'form': form})
I've tried several versions of this, including:
def winner_edit_form(request, pk):
if request.method == 'POST':
winner = PrizeWinner.objects.get(id=pk)
form = WinnerForm(request.POST or None, instance=winner)
if form.is_valid() and request.POST['winner'] != '':
form.save()
return HttpResponseRedirect('winner-detail')
else:
form = WinnerForm(instance=winner)
context = {'winner': winner, 'form': form}
return render(request, 'partials/edit-winner-form.html', context)
I literally copied and pasted from previous and more complex projects and from other examples and I keep getting this error.
These are my urls
from django.urls import path
from mainsite import views
urlpatterns = [
path('',views.HomePage.as_view(), name='home'),
path("winner-detail/<int:pk>", views.winner_detail, name='winner-detail'),
path("winner-detail/<int:pk>/edit/", views.winner_edit_form, name='winner_edit_form'),
]
models.py
class PrizeWinner(models.Model):
name = models.CharField(max_length=200, blank= False)
prizecode = models.CharField(max_length=120, blank=True)
prizestatus = models.CharField(max_length=200, null=True, blank=True, choices=STATUS_CHOICES, default='Unclaimed')
prizechoices = models.CharField(max_length=200, null= True, blank= True, choices =PRIZE_CHOICES, default='£10 Bar Tab')
date_won = models.DateTimeField(auto_created=True, null=True, blank=True)
comment = models.TextField(null=True, blank=True)
def __str__(self):
return self.name
def pre_save_prize_code(instance, sender, *args, **kwargs):
if not instance.prizecode:
instance.prizecode= unique_prize_code_generator(instance)
pre_save.connect(pre_save_prize_code, sender= PrizeWinner)
This is my form
from django import forms
from mainsite.models import PrizeWinner
class WinnerForm(forms.ModelForm):
class Meta:
model = PrizeWinner
fields =('name','prizestatus','prizechoices','comment')
Without even reading the code I know two things. (1) You are falling off the end of the view function without returning a response object, and (2) you would be far better abandoning FBVs and using Class-based views.
OK, looking for the bug now ...
Yes, with the first version if form.is_valid() returns False, no further code is executed and it returns None by default.
The second version ought not to be failing this way, though. Try it again? Some other error?
A CBV equivalent. Off the top of my head so it may contain bugs.
class WinnerEditView( UpdateView):
template_name = 'partials/edit-winner-form.html'
context_object_name = 'winner'
model = PrizeWinner
form_class = WinnerForm
success_url = reverse_lazy('winner_detail') # needs an app name?
def form_valid( self, form):
if request.POST['winner'] != '': # I don't understand this, isn't the parsed pk the winner by definition?
form.save()
url
path("winner-detail/<int:pk>/edit/", views.WinnerEditView.as_view(), name='winner_edit_form')

I'm trying to link the post created by the specific user account in Django

models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Customer(models.Model):
user = models.OneToOneField(User,null=True,blank=True,on_delete=models.CASCADE)
name = models.CharField(max_length=200,null=True)
## phone = models.IntegerField(null=True)
email = models.EmailField(max_length=250)
profile_pic = models.ImageField(default='default_pic.png',null=True,blank=True)
date_created = models.DateTimeField(auto_now_add=True,null=True)
def __str__(self):
return self.name
class Task(models.Model):
customer = models.ForeignKey(Customer,on_delete=models.CASCADE,null=True)
title = models.CharField(max_length=200)
description = models.TextField(null=True,blank=True)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Meta:
ordering = ['complete']
views.py
#login_required(login_url='login')
def taskCreate(request):
if request.method == 'POST':
form = TaskForm(request.POST or None)
if form.is_valid():
form.instance.customer = request.user
form.save()
return redirect('tasks')
else:
form = TaskForm()
context = {'form':form}
return render(request,'todo_list/task_create.html',context)
Error:
ValueError at /create_task/
Cannot assign "<SimpleLazyObject: <User: Dominic>>": "Task.customer" must be a "Customer" instance.
I am trying to link the username in the user account to be shown on the model Task.customer that represents the post is created by that user. May I ask any methods could be done in order to specify the customer in the model Task? Also I do not understand the error message in detail because my admin panel already has the current username in the Customer model. However if I used request.user.customer the username does not show up instead returning None so how to solve this issue?
I don't know form.instance.customer = request.user
but I think I understood what you meant and the below code does the same thing
#login_required(login_url='login')
def taskCreate(request):
if request.method == 'POST':
form = TaskForm(request.POST or None)
if form.is_valid():
t = form.save(commit = False)
t.customer = request.user # assigning current user to created task.customer
t.save()
return redirect('tasks')
else:
form = TaskForm()
context = {'form':form}
return render(request,'todo_list/task_create.html',context)
if the code is still not working then try changing your line
customer = models.ForeignKey(Customer,on_delete=models.CASCADE,null=True) to
customer = models.ForeignKey(User,on_delete=models.CASCADE,null=True) in your models.py
The error comes from the following snippet
form.instance.customer = request.user
request.user is not a Customer instance, you can try extracting the information from request.user and create a Customer object from it and then assign it back

How to edit user profile in django rest framework from two models and save the change

I am trying to create an endpoint to edit both the user model and custom profile model below.
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500)
location = models.CharField(max_length=50)
image = models.ImageField(default='default.jpg', upload_to='profile')
In the regular django I would do:
views.py
def edit_profile(request):
if request.method == 'POST':
form = EditProfileForm(request.POST, instance=request.user)
extended_profile_form = ProfileForm(request.POST,
request.FILES,
instance=request.user.profile)
if form.is_valid() and extended_profile_form.is_valid():
form.save()
extended_profile_form.save()
return redirect('accounts:profile')
else:
form = EditProfileForm(instance=request.user)
extended_profile_form = ProfileForm(instance=request.user.profile)
context = {
'form':form,
'extended_profile_form':extended_profile_form
}
return render(request, 'accounts/edit-profile.html', context)
what is the equivalent for django rest framework?
I have tried:
views.py (Django Rest Framework)
#api_view(['GET','PUT'])
def profile(request):
if request.method == 'GET':
user = User.objects.filter(username=request.user)
profile_user = Profile.objects.filter(user=request.user)
serializer_user = UserSerializer(user, many=True)
serializer_profile_user = ProfileSerializer(profile_user, many=True)
result = {'serializer_user': serializer_user.data, 'serializer_profile_user': serializer_profile_user.data}
return Response(result)
elif request.method == 'PUT':
user = User.objects.filter(username=request.user)
profile_user = Profile.objects.filter(user=request.user)
serializer_user = UserSerializer(user, data=request.data)
serializer_profile_user = ProfileSerializer(profile_user, data=request.data)
if serializer_user.is_valid() and serializer_profile_user.is_valid():
serializer_user.save()
serializer_profile_user.save()
result = {'serializer_user': serializer_user.data, 'serializer_profile_user': serializer_profile_user.data}
return Response(result)
result = {'serializer_user': serializer_user.data, 'serializer_profile_user': serializer_profile_user.data}
return Response(result.errors, status=status.HTTP_400_BAD_REQUEST)
When I am browsing the endpoint, it does display serializer_user and serializer_profile_user data but I am unable to edit any of those data using the DRF browsable API.
Am I right thinking the codes above is the equivalent of the codes from the codes from the normal django to edit the profile of the user?
It looks fine to me, but you need to replace this:
if request.method == 'GET':
user = User.objects.filter(username=request.user)
with this:
if request.method == 'GET':
try:
user = User.objects.get(id=request.user.id)
except User.DoesNotExist:
return Response(data='no such user!', status=status.HTTP_400_BAD_REQUEST)
# you need to use objects.get because objects.filter returns a queryset not an abject
Because, request.user is an instance of User model, you cannot compare it to an attribute of user (in your case username)
PS: same goes with your PUT method as well.
Hope this helps!
Look. You can make it easier. Let's take Post model (for example):
class Post(models.Model):
author = models.ForeignKey(base.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=50)
text = models.TextField()
likes = models.ManyToManyField(base.AUTH_USER_MODEL, blank=True, related_name='post_likes')
created_date = models.DateTimeField(default=timezone.now)
And that You should describe it in your serializer (serializer is something similar to DTO. It converts data into a service-friendly JSON view):
class PostCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['id', 'title', 'text']
And the last part - Endpoint:
class PostUpdateView(UpdateAPIView):
serializer_class = PostCreateUpdateSerializer
def get_queryset(self):
return Post.objects.filter(author=self.request.user)
It will be more comfortable to use CBV for Django and DRF
And One more thing. You shouldn't create one more table for your user model. This is due to the extension of the BaseUser model. Link for help

When creating django model, it posts the data, but does not save it in database

I can create model objects through admin panel. But I want it to be created on website. The code below allows me to enter values of a model, and when I submit it, it redirects to the written url, which happens after form.save. This is the message from server "POST /taskcreate HTTP/1.1" 302 0. But there is no changes in database. How to solve this issue? Any thoughts... Thanks
models.py
class Task(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=1000)
pub_date = models.DateTimeField('date_published', auto_now_add = True)
cost = models.IntegerField()
def __str__(self):
return '%s' % (self.name)
forms.py
class TaskCreateForm(forms.ModelForm):
class Meta:
model = Task
fields = ('name', 'description', 'cost')
views.py
def TaskCreateView(request):
if request.method == 'POST':
form = TaskCreateForm(request.POST)
if form.is_valid():
form.save
return redirect('home')
else:
form = TaskCreateForm()
return render(request, 'employer/create_task.html')
You didn't actually call the save method.
if form.is_valid():
form.save()
return redirect('home')
When you use ModelForm you just need to write form.save() method right after if is_valid() if case. In your case, you are missing curly brackets after save.
def TaskCreateView(request):
if request.method == 'POST':
form = TaskCreateForm(request.POST)
if form.is_valid():
form.save() # here you were missing curly brackets
return redirect('home')
else:
form = TaskCreateForm()
return render(request, 'employer/create_task.html')

Save form with user id Django

To make my question simple I have A Form That user can upload their cv's into databse.
My forms.py
class resume_upload(forms.ModelForm):
cv = forms.FileField(required = True)
job_title = forms.CharField(required = True)
def save(self, commit=False):
cvs = super(resume_upload, self).save(commit=False)
cvs.cv = self.cleaned_data['cv']
cvs.job_title = self.cleaned_data['job_title']
if commit:
cvs.save()
class Meta:
model = Cv
fields = ('cv', 'job_title',)
My models.py
class Cv(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
cv = models.FileField(upload_to='cvs', default='', validators=[validate_file_extension])
job_title = models.CharField(max_length=100, default='')
def __str__(self):
return self.job_title
and my views.py
def upload_resume(request):
if request.method == 'POST':
form = resume_upload(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('/')
else:
messages.error(request,"Oops! That didn't work. Please try again")
else:
form = resume_upload()
return render(request, 'upload_resume.html',{'form':form,})
And the problem is it redirect to home page but i cant find object in admin panel
You're overriding the save method like so,
def save(self, commit=False):
cvs = super(resume_upload, self).save(commit=False)
cvs.cv = self.cleaned_data['cv']
cvs.job_title = self.cleaned_data['job_title']
if commit:
cvs.save()
You're therefore passing a an optional parameter commit which is False by default.
You'll need to provide a True parameter when calling save if you want it to actually be saved.
form.save(commit=True)
EDIT
Also, there seems to be a problem with your code. This is probably what you intended,
def upload_resume(request):
if request.method == 'POST':
form = resume_upload(request.POST, request.FILES)
if form.is_valid():
cv_form = form.save() # commit is False in this case.
cv_form.user = request.user
form.save(commit=True)
return redirect('/')
else:
messages.error(request,"Oops! That didn't work. Please try again")
else:
form = resume_upload()
return render(request, 'upload_resume.html',{'form':form,})
Basically here you're patching the user to the form before it is actually saved to the database. This is exactly the purpose of your boolean switch commit.
EDIT 2
To overcome your 'NoneType' object has no attribute 'user' error, you would need to add this in your save override to return your object.
def save(self, commit=False):
cvs = super(resume_upload, self).save(commit=False)
cvs.cv = self.cleaned_data['cv']
cvs.job_title = self.cleaned_data['job_title']
if commit:
cvs.save()
return cvs

Categories

Resources