How to partially update an object when using modelForm in Django? - django

I want to let users to add/update caption of their already updated photos without changing any other field of the photo.
Here is the model:
class UserPic(models.Model):
user = models.ForeignKey(User, unique=False)
picfile = ImageWithThumbsField(upload_to= get_uplaod_file_name, sizes=((648,648),(200,200),(1200,1200)))
caption = models.CharField(max_length=200 , blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
likes = models.IntegerField(default=0)
liked_by= models.ForeignKey(Liker, blank=True)
#models.permalink
def get_absolute_url(self):
return ('view_pirate', None, {'user': self.account.user})
def __unicode__(self):
return unicode(self.picfile.name)
views.py
def edit_photo(request, pic_id):
pic = UserPic.objects.get(id=pic_id)
if request.method == 'POST':
if pic.user== request.user:
picform = CaptionForm(request.POST)
if picform.is_valid():
edform = picform.save(commit=False)
edform.caption = request.POST['caption']
edform.save()
message = "caption is uploaded"
else:
edform = CaptionForm()
args = {}
args.update(csrf(request))
args['pic'] = pic
args['pic_id'] = pic_id
#args['form'] = edform
return render_to_response('userpics/photo.html', args,
context_instance= RequestContext(request))
photo.html
<div class="caption">
<form action="{% url "userpics.views.edit_photo" pic.id %}" method="POST">
{% csrf_token %}
{{form.as_ul}}
<input type="submit" value="SEND">
</form>
forms.py:
class CaptionForm(forms.ModelForm):
class Meta:
model= UserPic
fields = ('caption',)
However when I post the form, django still complain that:
MultiValueDictKeyError at /pics/edit/26
"'caption'"
I really got confused as I could not find any resources to deal with this particular problem. So appreciate your hints.

Ok I managed to solved the problem like this:
photo.html
<form action="{% url "userpics.views.edit_photo" pic.id %}" method="POST">
{% csrf_token %}
<input type="text" name="caption" value="{{pic.caption}}">
<input type="submit" value="SEND">
</form>
views.py
def edit_photo(request, pic_id):
pic = UserPic.objects.get(id=pic_id)
if request.method == 'POST':
if pic.user== request.user:
picform = CaptionForm(request.POST)
if picform.is_valid():
pic.caption = request.POST['caption']
pic.save()
message = "caption is uploaded"
else:
edform = CaptionForm(instance=pic)
args = {}
args.update(csrf(request))
args['pic'] = pic
args['pic_id'] = pic_id
return render_to_response('userpics/photo.html', args,
context_instance= RequestContext(request))

Related

Django - User not passing through form

I am making an auction site and I try passing the user who posted a bid on a listing through a form. I already asked this about passing the creator of a listing and I tried the same method but I cannot manage to do it.
My view looks something like this (I shortened it because it's very long):
def show_listing(request, listing_id):
listing = AuctionListing.objects.get(id=listing_id)
bidding = listing.bidlisting.last()
if bidding is None:
field_name = "starting_bid"
starting_bid = getattr(listing, field_name)
createbidform = CreateBid(initial={"bids": starting_bid, "user":request.user})
else:
field_name2 = "bids"
highest_bid = getattr(bidding, field_name2)
createbidform = CreateBid(initial={"bids": highest_bid, "user":request.user})
if request.method == "POST":
form = CreateBid(request.POST)
if bidding is None and float(form['bids'].value()) >= float(starting_bid):
if form.is_valid():
message = "Your bid is placed"
form.instance.listing = listing
form.save()
createbidform = CreateBid(initial={"bids": form['bids'].value(), "user":request.user})
amount_bids = len(Bid.objects.filter(listing=listing_id))
return render(request, "auctions/listing.html", {
"createbidform" : createbidform
})
else:
print(form.errors)
return render(request, "auctions/listing.html", {
"bidform" : createbidform
})
listing.html looks something like this:
<form method="POST">
{% csrf_token %}
${{ bidform.bids }}
<button type="submit" name="bidbid" class="btn btn-primary save btn-sm">Place your bid</button>
</form>
RIGHT NOW form.errors prints:
<ul class="errorlist"><li>user<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
Here is the model Bid:
class Bid(models.Model):
listing = models.ForeignKey(AuctionListing, on_delete=models.CASCADE, related_name="bidlisting")
bids = models.DecimalField(max_digits=6, decimal_places=2)
user = models.ForeignKey(User, on_delete=models.CASCADE, db_constraint=False, related_name="userrr")
def __str__(self):
return str(self.bids)
And here is the form CreateBid:
class CreateBid(forms.ModelForm):
class Meta:
model = Bid
fields = ('bids', 'user')
widgets = {
'user': forms.HiddenInput(),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super().__init__(*args, **kwargs)
self.fields['user'].initial = user.id
For some reason it doesn't provide the user who posted the bidding to the form, causing the form to not be valid. How to fix this?
You already do it with bids so you don't need extra kwarg:
createbidform = CreateBid(initial={'bids': starting_bid, 'user': request.user})
you can remove __init__ method form CreateBid form class
Template:
<form method="POST">
{% csrf_token %}
${{ bidform }}
<button type="submit" name="bidbid" class="btn btn-primary save btn-sm">Place your bid</button>
</form>

Django, Foreign key not getting filled with session data

im trying to fill my foreignkey (employer) with the user that is logged in, but i have seen alot of way but they havent worked for me, does anyone know what im doing wrong? and how i can fix it?
View:
class JobCreate(CreateView):
model = Job
form = JobCreateForm()
form_class = JobCreateForm
context = {}
success_url = reverse_lazy('jobsview')
def POST(self,request):
if request.method == 'POST':
form = JobCreateForm(request.POST)
if form.is_valid():
job = form.save(commit=False)
job.employer = request.user
job.save()
context = {}
return render(request, 'jobs/jobs.html',context)
else:
context = {}
return render(request, 'jobs/job_form.html',context)
Model:
class Job(models.Model):
employer = models.ForeignKey(User, related_name='employer', on_delete=CASCADE,blank=True)
employees = models.ManyToManyField(User, related_name='employees2user',null=True,blank=True)
title = models.CharField(max_length=200,)
description = models.CharField(max_length=200,null=True,blank=True)
category_id = models.ManyToManyField(Category,blank=True)
skill_id = models.ManyToManyField(Skill,blank=True)
approved = models.BooleanField(default=False)
# img = models.ImageField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self): # Default value
return self.title
HTML:
{% extends "jobs/layout.html" %}
{% block content %}
<h3> Job</h3>
<div class="container">
<div class="jobform">
<form action="" method="POST">
{%csrf_token%}
{% for field in form %}
<label for="{{field.id_for_label}}">{{field.html_name}}</label>
{{field}}
{% endfor %}
<p>Ctrl in houden om meerder te selecteren</p>
<button type="submit" class="btn btn-dark btn-space">Submit</button>
</form>
</div>
</div>
{%endblock%}
In your views method, try replacing
job = form.save(commit=False)
job.employer = request.user
job.save()
with
self.object = form.save(commit=False)
self.object.employer = self.request.user
self.object.save()
Also, what is the purpose of context {} ?
Can you just put this inside a form_valid method directly? That's much cleaner.
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.employer = self.request.user
self.object.save()
return super(JobCreate, self).form_valid(form)

Django MultiValueDictKeyError for upload file

There has a file upload page for upload file to a object by id in model. However, it shown MultiValueDictKeyError after submitted. I would appreciate if any help.
models.py:
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
items = models.ManyToManyField(OrderItem)
img_upload = models.FileField(upload_to='payment', null=True)
forms.py:
class Upload_File(forms.Form):
class Meta:
model = Order
fields = ('img_upload')
views.py:
def upload_page(request, id):
order = get_object_or_404(Order, id=id)
form = Upload_File(request.POST or None, request.FILES or None)
if request.method == 'POST':
order.img_upload = request.FILES['file']
if form.is_valid():
form.save()
messages.success(request, 'Succeed')
return redirect('user_info')
else:
form = Upload_File()
context = {
'form': form,
}
return render(request, 'upload.html', context)
html:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input class="form-group" type="file" name="file">
<button class="form-group" type="submit">Submit</button>
</form>

Django IntegrityError at /main/addcomment/1 NOT NULL constraint failed: main_comment.post_id

I stuck by an integrity error when I passed comment to my product review page. Help Me through this.
I think the error occurs because of the args which passed through the render function.
My models.py
class Comment(models.Model):
post = models.ForeignKey(List, on_delete=models.CASCADE, related_name='comments')
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
subject = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
approved_comment = models.BooleanField(default=False)
def __str__(self):
return str(self.user)
views.py
def addcomment(request, id):
list = get_object_or_404(List, pk=id)
form = CommentForm(request.POST or None)
if form.is_valid():
data = Comment()
data.subject = form.cleaned_data['subject']
data.text = form.cleaned_data['text']
print("Redirected.....")
current_user = request.user
data.user_id = current_user.id
data.save()
messages.success(request, "Your Comment has been sent. Thank you for your interest.")
return HttpResponseRedirect(reverse('main:hackathonList', args=[list.id]))
return render(request, 'product.html', {'list': list, 'form': form})
forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('subject', 'text')
urls.py
path('addcomment/<int:id>', views.addcomment, name='addcomment'),
template.html
<form action="{% url 'main:addcomment' user.id %}" role="form" method="post">
{% csrf_token %}
<p>{{ form | crispy }}</p>
{% if user.id is not none %}
<button type="submit" class="btn btn-secondary">Comment</button>
{% else %}
You must be logged in to post a review.
{% endif %}
</form>
In views.py instead of data.user_id = current_user.id ie remove this line and add int its place
data.user = current_user
data.post = list
You need to change
<form action="{% url 'main:addcomment' list.id %}" role="form" method="post">
this first. After that, just add a new line before save method call like:
data.post = list

'QueryDict' object has no attribute 'caption' in django

I have written this simple image upload app, where users should be able to add caption to the uploaded image.
the views is:
#login_required
def upload(request):
thisuser =User.objects.get(username = request.user.username)
args= {}
if request.method == 'POST':
picform = PicForm(request.POST, request.FILES)
if picform.is_valid():
newpic = UserPic(picfile = request.FILES['picfile'])
newpic = picform.save(commit=False)
newpic.user_id = request.user.id
newpic.caption = request.POST.caption # <--problematic line
newpic.save()
message = "file %s is uploaded" % newpic
args['pic'] = newpic.picfile
args['caption'] = newpic.caption
else:
picform = PicForm()
args.update(csrf(request))
args['picform'] = picform
return render_to_response('pics/upload.html',args,
context_instance=RequestContext(request))
The model is:
class UserPic(models.Model):
user = models.ForeignKey(User, unique=False)
picfile = ImageWithThumbsField(upload_to= get_uplaod_file_name,sizes=((200,200),))
caption = models.TextField(max_length=200 , blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
And the template:
<div>
Upload New picture
<form action="/pics/upload/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<ul class="list-unstyled form-group">
{{picform.as_ul}}
</ul>
</p>
<p><input type="submit" value="Upload" /></p>
</form>
</div>
When I upload photo, fill the caption field and submit the form,, I get:
'QueryDict' object has no attribute 'caption'
I tried different things instead of newpic.caption = request.POST.caption but none worked. So appreciate your help.
Try this
request.POST['caption']
or
request.POST.get('caption', 'Default').
Both get the caption value from the form post data. The latter is just a safer way in my opinion by specifying a default value for caption.