I am confused while rendering my views.py "Django" - python

My vews.py:
if you want me to share another piece of information feel free to ask!
I just have a problem with the bidding system !!, I tried the bidding but when I add the new number into the input field and click the place bid button the page just reloads which means the function doesn't work!!
I have another problem when I try to close the bid I git this Django error
ValueError at /bidding/26
The view auctions.views.bidding didn't return an HttpResponse object.
It returned None instead.
The code:
def viewList(request, id):
# check for the watchlist
listing = Post.objects.get(id=id)
user = User.objects.get(username=request.user)
if listing.watchers.filter(id=request.user.id).exists():
is_watched = True
else:
is_watched = False
if not listing.activate:
if request.POST.get('button') == "Close":
listing.activate = True
listing.save()
else:
price = request.POST.get('bid', 0)
bids = listing.bids.all()
if user.username != listing.creator.username:
if price <= listing.price:
return render(request, 'auctions/item.html', {
"listing": listing,
'form': BidForm(),
"message": "Error! Your bid must be largest than the current bid!",
'comment_form': CommentForm(),
'comments': listing.get_comments.all(),
'is_watched': is_watched,
})
form = BidForm(request.POST)
if form.is_valid():
bid = form.save(commit=False)
bid.user = user
bid.save()
listing.bids.add(bid)
listing.bid = price
listing.save()
else:
return render(request, 'acutions/item.html', {'form'})
context = {
'listing': listing,
'comment_form': CommentForm(),
'comments': listing.get_comments.all(),
'is_watched': is_watched,
'form': BidForm()}
return render(request, 'auctions/item.html', context)
models.py
class Bid(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
bid = models.DecimalField(max_digits=10, decimal_places=2)
time = models.DateTimeField(default=timezone.now)
class Post(models.Model):
# data fields
title = models.CharField(max_length=64)
textarea = models.TextField()
# bid
price = models.FloatField(default=0)
currentBid = models.FloatField(blank=True, null=True)
imageurl = models.CharField(max_length=255, null=True, blank=True)
category = models.ForeignKey(
Category, on_delete=models.CASCADE, default="No Category Yet!", null=True, blank=True)
creator = models.ForeignKey(
User, on_delete=models.PROTECT, related_name="all_creators_listings")
watchers = models.ManyToManyField(
User, blank=True, related_name='favorite')
date = models.DateTimeField(auto_now_add=True)
# for activated the Category
activate = models.BooleanField(default=False)
bids = models.ManyToManyField(Bid, )
def __str__(self):
return f"{self.title} | {self.textarea} | {self.date.strftime('%B %d %Y')}"
item.html
<div class="card-body">
<ul class="list-group">
<div class="info">
<li class="list-group-item mb-2">Description:<br>{{listing.textarea}}</li>
<li class="list-group-item mb-2">category: {{listing.category.name}}</li>
<li class="list-group-item mb-2"><h5>Start bid: {{listing.price}}$</h5></li>
</div>
<div class="newbid">
<p>{{ message }}</p>
<form action="{% url 'viewList' listing.id %}" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="bid">{{ listing.bids.count }} bid(s) so far. Your bid is the current bid</label>
</div>
<div class="form-group">
{{ form }}
</div>
<div class="form-group">
<input type="submit" name="button" class="btn btn-primary" value="Place Bid">
</div>
</form>
{% if listing.activate %}
<li><strong>Winner: </strong>{{ listing.bids.last.user.username }}</li>
{% endif %}
{% if user.username == listing.creator.username and not listing.activate %}
<form action="{% url 'viewList' listing.id %}" method="POST">
{% csrf_token %}
<button type="submit" name="button" class="btn btn-danger" value="Close">Close</button>
</form>
{% endif %}
</div>
</ul>
</div>
inside this view, I added a punch of my project requirement (comments/watchlist(bookmark)/and the last thing(that what I have a lot of problem with it) is the system of Bid) that lets users add bids on such posts and let the creator of that post the ability to close it.... please help I am sticking in this zone, I tried many times to understand!
Note I am new at Back-end Development!

There is the two problem in you code first one is hi-lighted by Husam
user = User.objects.get(username=request.user.username)
and the other one is in the return statement in the else part
render(request, 'acutions/item.html', {'form'}) instead of context object you pass the string in which is consider as set object in python and thats why you are getting None type error.
here is the refactored code :-
def viewList(request, id):
# check for the watchlist
listing = Post.objects.get(id=id)
user = User.objects.get(username=request.user.username)
form = BidForm()
is_watched = listing.watchers.filter(id=request.user.id).exists():
context = {}
if not listing.activate:
if request.POST.get('button') == "Close":
listing.activate = True
listing.save()
else:
price = request.POST.get('bid', 0)
bids = listing.bids.all()
if user.username != listing.creator.username:
if price <= listing.price:
context.update({'message':"Error! your bid must be largest than the current bid !"})
else:
form = BidForm(request.POST)
if form.is_valid():
bid = form.save(commit=False)
bid.user = user
bid.save()
listing.bids.add(bid)
listing.bid = price
listing.save()
else:
return render(request, 'acutions/item.html', {'form': form})
context.update({'listing': listing,
'comment_form': CommentForm(),
'comments': listing.get_comments.all(),
'is_watched': is_watched,
'form': form})
return render(request, 'auctions/item.html', context)

The error you face in bidding view and the view you have shared is view list, it would be better if you shared the bidding view and highlight the error line/s
Anyway I have noticed that this line has one mistake:
user = User.objects.get(username=request.user)
Which suppose to be :
user = User.objects.get(username=request.user.username)
Hope this can help you little bit

Related

Problem with textarea "query_utils.DeferredAttribute" message in empty form

I am new in Django and i am making a typical CRUD app. In the "add" section, in the comment textarea this message appears "
<django.db.models.query_utils.DeferredAttribute object at 0x03B446A0>"
and i dont know what to do. I had tried multiples solutions in other stackoverflow questions but i cant find the solutions!
Here's the code
class Turno(models.Model):
date = models.DateTimeField()
person = models.ForeignKey('Person', on_delete=models.CASCADE)
medic = models.ForeignKey('Medic', on_delete=models.CASCADE)
observations = models.CharField(blank=True, max_length=255)
def __str__(self):
return f'{self.date} {self.person} {self.medic}'
def new_turn(request):
if request.method == 'POST':
turnFormPost = TurnForm(request.POST)
if turnFormPost.is_valid():
turnFormPost.save()
return redirect("admin_index")
turnForm = TurnForm(instance=Turno)
context = {
'form':turnForm
}
return render(request,"turn_new.html", context)
class TurnForm(ModelForm):
class Meta:
model = Turno
fields = '__all__'
widgets = {
'date': DateTimeInput(attrs={'type':'date'}),
'observations': Textarea(attrs={'rows':5, 'cols':50})
}
-turn_new.html
<div class="container">
<h2>New Turn</h2>
<form method="POST">
{% csrf_token %}
<table>
{{form}}
</table>
<button type="submit" class="btn btn-primary">Create</button>
</form>
<div>
Back to index
</div>
</div>
in the textarea of 'observations' in 'turn_new.html' the message that appears is this
"<django.db.models.query_utils.DeferredAttribute object at 0x03B446A0>"

Why are my ValidationErrors not rendering anymore?

I have a form that has to check a few things before submission to make sure the data is valid. Before I did a few changes (went from class based views to function based) everything worked fine, but when I went back to test everything I noticed that a very important part was not working properly, which is the number validation.
What used to happen before was that, if a number that was not in the DB was entered, the user would be shown an error at the top. If they entered a number that was in the DB, but it was not the right "team" then it would show an error. I was handling this in forms.py, and completely forgot about this since it was working before, and all the things I started working with were in views.py. Now, while it will not actually submit the form (so it is still going through the logic) it will not display any errors. It will just re-render the page but empty, and not submit anything unless the data entered is right. The logic that would handle this was clean_employee_number.
I'm not sure If I deleted something from my html without noticing, but I have been trying to figure out what could have cause this to stop working and I cannot figure it out. I am also not sure if it could have been due to the widget, since I made that change afterwards (it is a widget because the employee_number is tied to the "id" of the employee which is stored in another model called Salesman).
models.py
class EmployeeWorkAreaLog(TimeStampedModel, SoftDeleteModel, models.Model):
employee_number = models.ForeignKey(Salesman, on_delete=models.SET_NULL, help_text="Employee #", null=True, blank=False)
work_area = models.ForeignKey(WorkArea, on_delete=models.SET_NULL, null=True, blank=False, help_text="Work Area", related_name="work_area")
station_number = models.ForeignKey(Station, on_delete=models.SET_NULL, null=True, help_text="Station", related_name="stations", blank=True)
forms.py
class WarehouseForm(AppsModelForm):
class Meta:
model = EmployeeWorkAreaLog
widgets = {
'employee_number': ForeignKeyRawIdWidget(EmployeeWorkAreaLog._meta.get_field('employee_number').remote_field, site, attrs={'id':'employee_number_field'}),
}
fields = ('employee_number', 'work_area', 'station_number', 'edited_timestamp')
def clean_employee_number(self):
employee_number = self.cleaned_data.get('employee_number')
if employee_number is None:
raise forms.ValidationError("Must enter emp #")
elif employee_number.team is None:
raise forms.ValidationError("Not valid")
elif employee_number.team not in ('WF', 'WP', 'OM') or employee_number.employee_status not in 'A':
raise forms.ValidationError("Employee not valid, please contact manager")
views.py
def enter_exit_area(request):
form = WarehouseForm(request.POST or None)
enter_without_exit = None
exit_without_enter = None
if request.method == 'POST':
temp = request.POST.copy()
form = WarehouseForm(temp)
if form.is_valid():
emp_num = form.cleaned_data['employee_number']
area = form.cleaned_data['work_area']
station = form.cleaned_data['station_number']
edited_time = form.cleaned_data['edited_timestamp']
if 'enter_area' in request.POST:
new_entry = form.save()
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_out__isnull=True) & Q(time_in__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).update(time_in=datetime.now())
# If employee has an entry without an exit and attempts to enter a new area, mark as an exception 'N'
enters_without_exits = EmployeeWorkAreaLog.objects.filter(Q(employee_number=emp_num) & Q(time_out__isnull=True) & Q(time_exceptions="")).exclude(pk=new_entry.pk).order_by("-time_in")
if len(enters_without_exits) > 0:
enter_without_exit = enters_without_exits[0]
enters_without_exits.update(time_exceptions='N')
message = 'You have entered %(area)s' % {'area': area}
if station is not None:
message += ': %(station)s' % {'station': station}
messages.success(request, message)
elif 'leave_area' in request.POST:
# Something similar to above
form = WarehouseForm()
return render(request, "operations/enter_exit_area.html", {
'form': form,
'enter_without_exit': enter_without_exit,
'exit_without_enter': exit_without_enter,
})
enter_exit_area.html
{% extends "base.html" %}
{% block main %}
<form id="warehouseForm" action="" method="POST" novalidate >
{% csrf_token %}
{{ form.non_field_errors }}
{{ form.source.errors }}
{{ form.source }}
<div>
<div>
<div>{{ form.employee_number.errors.as_text }}</div>
<label>Employee #</label>
{{ form.employee_number }}
</div>
<div>
<div>{{ form.work_area.errors.as_text }}</div>
<label>Work Area</label>
{{ form.work_area }}
</div>
<div>{{ form.station_number.errors.as_text }}</div>
<div>
<label>Station</label>
{{ form.station_number }}
</div>
</div>
<div>
<div>
<button type="submit" name="enter_area" value="Enter">Enter Area</button>
<button type="submit" name="leave_area" value="Leave">Leave Area</button>
</div>
</div>
</form>
You construct a new form in case it is a POST request and the form is not valid. The workflow of your enter_exit_area should be:
def enter_exit_area(request):
enter_without_exit = None
exit_without_enter = None
if request.method == 'POST':
form = WarehouseForm(request.POST)
if form.is_valid():
# …
return redirect('some-view')
else:
form = WarehouseForm()
return render(request, "operations/enter_exit_area.html", {
'form': form,
'enter_without_exit': enter_without_exit,
'exit_without_enter': exit_without_enter,
})
Notice thus that the form = WarehouseForm() is constructed in an else block of the if request.method == 'POST'.
In case of a successful POST request, you normally make a redirect, to implement the Post/Redirect/Get pattern [wiki].

how to display all the reviews for the particular product?

With the below code i am adding reviews for some particular product in the database and it is doing good but the problem is while displaying the reviews for the selected product.I get confused how can i display the all reviews of some product and which review done by which user at what time?
models.py
class Product(models.Model):
name = models.CharField(max_length=250)
description = models.TextField(blank=True)
featured = models.BooleanField(default=False)
def __str__(self):
return self.name
class Review(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
review = models.TextField()
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.review
views.py
def detail(request,pk):
product = College.objects.get(pk=pk)
form = ReviewForm()
return render(request,'products/detail.html',{'product':product,'form':form})
#login_required(login_url='products:signin')
def review(request,pk):
if request.method == "POST":
form = ReviewForm(request.POST)
if form.is_valid():
review = form.save(commit=False)
review.product = Product.objects.get(pk=pk)
review.user = request.user
review.save()
messages.success(request, "Review saved")
return redirect('products:detail',pk)
else:
messages.error(request,'error in form')
return redirect('products:detail', pk)
detail.html
<h3>All reviews(total.no. of reviews?)</h3>
# Here i want to display all reviews and which is done by which user and at what time
<div class="col-lg-6 col-md-6 mb-6">
<form method="post" action="{% url 'products:review' product.pk %}">
{% csrf_token %}
{% form.as_p %}
<input type="submit" class="btn btn-success">
</form>
</div>
You can do it like this using reverse relation:
<h3>All reviews {{ product.review_set.count }}</h3>
{% for review in product.review_set.all %}
{{ review.review }}
{{ review.date }}
{% endfor %}

Django: Assign current user as foreign key to comments model

I have been working thorough the DjangoGirls tutorial and was trying to improve on the section on adding comments to an application - TutorialExtensions
I have added the comments to a simple photo blog application but what I was attempting to do was replace the author = models.CharField(max_length=200) with an alternative that would store the current/logged-in user who was commenting on the photo instance and then allow me to display on the photo_detail template.
I thought I was close using author = models.ForeignKey(User, related_name='Commenter') but this through up an error:
NOT NULL constraint failed: timeline_comment.author_id
Here is my models.py consisiting of a Photo model and Comments model:
class Photo(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
title = models.CharField(max_length=120)
slug = models.SlugField(unique=True)
image = ProcessedImageField(upload_to=upload_location,
null=True,
blank=False,
processors=[Transpose(), ResizeToFit(1000, 1000, False)],
format='JPEG',
options={'quality': 50},
width_field="width_field",
height_field="height_field")
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
description = models.TextField(max_length=1000)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
class Comment(models.Model):
post = models.ForeignKey('timeline.Photo', related_name='comments')
author = models.CharField(max_length=200)
text = models.TextField(max_length=1000)
created_date = models.DateTimeField(default=timezone.now)
The related view:
def photo_detail(request, slug=None):
if not request.user.is_authenticated():
return HttpResponseRedirect("/accounts/login")
instance = get_object_or_404(Photo, slug=slug)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = instance
comment.save()
return redirect('timeline:detail', slug=instance.slug)
else:
form = CommentForm()
share_string = quote_plus(instance.description)
context = {
"title": instance.title,
"instance": instance,
"share_string": share_string,
"form": form,
}
return render(request, "photo_detail.html", context)
My forms.py:
class CommentForm(forms.ModelForm):
text = forms.CharField(widget=forms.Textarea, label='Leave a comment: ')
class Meta:
model = Comment
fields = [
"text",
]
Finally the template for the photo_detail view:
<div class="row">
<div class="col-md-12" id="comments">
<p>
{% if instance.comments.count == 0 %}
No Comments
{% elif instance.comments.count == 1 %}
{{ instance.comments.count }} Comment
{% else %}
{{ instance.comments.count }} Comments
{% endif %}
</p>
<hr style="margin-top: 10px;">
{% for comment in instance.comments.all %}
<div class="comment">
<div class="date pull-right">{{ comment.created_date | timesince }} Ago</div>
<strong>{{ comment.author }}</strong>
<p>{{ comment.text|linebreaks }}</p>
</div>
<hr>
{% empty %}
<p>No comments here yet :(</p>
{% endfor %}
</div>
</div>
{% if user.is_superuser or user.is_authenticated %}
<div class="row">
<div class="col-md-12">
<form method="POST" class="comment-form" action=''>
{% csrf_token %}
{{ form | crispy }}
<button type="submit" class="comment-add btn btn-lg btn-purple">Add</button>
</form>
</div>
</div>
{% endif %}
Could anybody recommend the best approach for this? Any help would be very much appreciated! Thank You.
Using the ForeignKey is correct[1] - the missing piece is that you need to assign that in your view. After comment = form.save(commit=False) just add one line:
comment.author = request.user
and it will work.
[1] although you don't want the related_name as "Commenter" (because it refers to the way you access the comment from the user: the default is comment_set which makes more sense).

Django: show value of dictionary in dropdown

In my template, the dropdown box is populated with a dictionary instead of the value of the dictionary. How can I make that only the value is shown?
This is my collectionPoint
class CollectionPoint(models.Model):
addressID = models.AutoField(primary_key=True)
collectionPointName = models.CharField(max_length=50, null=False)
street = models.CharField(max_length=50, null=False)
streetnumber = models.CharField(max_length=20, null=False)
city = models.CharField(max_length=50, null=False)
postalcode = models.CharField(max_length=30, null=True)
gps_latitude = models.FloatField(blank=True, null=True)
gps_longitude = models.FloatField(blank=True, null=True)
country = models.ForeignKey(Country)
company = models.ForeignKey(Company)
#only the name is returned to the user
def __str__(self):
template = '{collectionPointName}'
return template.format(collectionPointName=self.collectionPointName)
I want to display all the distinct city of the collectionpoints
class RentalSelectCityForm(forms.Form):
city = forms.ModelChoiceField(queryset=CollectionPoint.objects.order_by().values('city').distinct(),initial=0)
My view
#login_required
def rentalselectcity(request):
# Get the context from the request.
context = RequestContext(request)
# A HTTP POST?
if request.method == 'POST':
form = RentalSelectCityForm(request.POST)
# Have we been provided with a valid form?
return HttpResponseRedirect('/')
else:
# If the request was not a POST, display the form to enter details.
form = RentalSelectCityForm()
context['path'] = [{'name': 'My rentals', 'url': reverse('rentals-list')}]
context['path'] += [{'name': 'Select city', 'url': reverse('rental-select-city')}]
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render_to_response('user/rentalselectcity.html', {'form': form}, context)
And my template
{% block content %}
<div class="box box-default">
<!--<div class="box-header">
<h3 class="box-title">Title</h3>
</div>--><!-- /.box-header -->
<!-- form start -->
<form action="{% url 'rental-select-city' %}" method="post" role="form">
{% csrf_token %}
<div class="box-body">
{{ form.non_field_errors }}
<div class="form-group">
{{ form.city.errors }}
<label for="{{ form.city.id_for_label }}">Select a city</label>
{{ form.city|attr:"class:form-control" }}
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<button type="submit" class="btn btn-primary">Select city</button>
</div>
</form>
</div><!-- /.box -->
{% endblock %}
You can change form field queryset to
CollectionPoint.objects.order_by().values_list('city', flat=True).distinct()
See the values_list docs for the reference

Categories

Resources