well done. i have got to admit that stack overflow has helped me when all seemed dreadful.
in my simple application, i need when a person books a room,
it shows a confirmation message
there is an auto decrement in book number i.e let's say, if there are 40 rooms, after a single book they are decremented to 39
to make sure one person can book only once.
though the code i have been putting seemed wrong and irrelevant, any help given is appreciated. is the logic put in models or views, and if yes, just show me atleast a line of code how it can be iniciated.
models.py
class Booking(models.Model):
Book_No = models.IntegerField(default=1)
Hostel = models.ForeignKey(List, null=True, blank=True)
Room_Number = models.ForeignKey(Room)
Room_capacity = models.CharField(max_length=1, choices=[('S', 'Single'), ('D', 'Double')], default="--")
Booked_by = models.ForeignKey(Student, default='--')
Booked_on = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{}, booked a {} room in {} {} at {}'.format(
self.Booked_by, self.Room_capacity, self.Hostel, self.Room_Number, self.Booked_on)
views.py
def book(request):
if request.method == "POST":
form = BookForm(request.POST)
if form.is_valid():
post = form.save(commit=True)
post.save()
else:
form = BookForm()
return render(request, 'gyobera/book_now.html', {'form': form})
forms.py
class BookForm(forms.ModelForm):
class Meta:
model = Booking
fields = ('Book_No', 'Hostel', 'Room_Number', 'Room_capacity', 'Booked_by')
book_now.html
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}{{ classification_name }}{% endblock %}
{% block body_block %}
<h1>Book_now</h1> Home<br/>
<br/>
<form method="POST" class="post-form">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Book_now</button>
</form>
{% endblock %}
thanks
i chose to edit and post the question here since it's more similar like the one i had posted above.. i have these here: below is my view to pull the available rooms from the database to be viewed on the site and the book view.
in my appplication you can book a hostel but when you book it off, it doesn't show or simply put it remains in the database as an available room, the code i had written seems totally wrong and irrelevant, i seek some help please..
then what is the simplest way i can filter hostels availed to make sure if a male is booking, hostels of that gender are only availed.
i hope the code below would really work to aid help. thanks
views.py
def rooms(request):
context_dict = {}
context = RequestContext(request)
room_list = Room.objects.all()
for room in room_list:
context_dict = {'rooms': room_list}
return render_to_response('gyobera/room.html', context_dict, context)
def book(request):
# check if user has already booked:
has_booked = Booking.objects.filter(Booked_by_id=request.POST.get('booked_by')).exists()
# are room free?
rooms_full = Booking.objects.count() == 40
if rooms_full or has_booked:
# redirect to a error view
return 'You have reserved yourself a room'
if request.method == "POST":
form = BookForm(request.POST)
if form.is_valid():
post = form.save(commit=True)
post.save()
else:
form = BookForm()
return render(request, 'gyobera/book_now.html', {'form': form})
models.py
class Room(models.Model):
Hostel = models.ForeignKey(List)
Room_Number = models.CharField(max_length=50)
Total_rooms = models.IntegerField(default=0, blank=True)
Price_single = models.IntegerField(default=0, blank=True)
Price_double = models.IntegerField(default=0, blank=True)
def __str__(self):
return ' {} | {} '.format(self.Hostel, self.Room_Number)
class Booking(models.Model):
Book_No = models.IntegerField(default=1)
Gender = models.CharField(max_length=1, choices=[('M', 'Male'), ('F', 'Female')], default="--")
Hostel = models.ForeignKey(List, null=True, blank=True)
Room_Number = models.ForeignKey(Room)
Room_capacity = models.CharField(max_length=1, choices=[('S', 'Single'), ('D', 'Double')], default="--")
Booked_by = models.ForeignKey(Student, default='--')
Booked_on = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{}, {} booked a {} room in {} {} at {}'.format(
self.Booked_by, self.Gender, self.Room_capacity, self.Hostel, self.Room_Number, self.Booked_on)
room.html
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}{{ category_name }}{% endblock %}
{% block body_block %}
<h1><strong>Available rooms </strong></h1>Home<br/>
{% if rooms %}
<ul>
{% for room in rooms %}
<!-- Following line changed to add an HTML hyperlink -->
<li>{{ room }}</li>
{% endfor %}
</ul>
{% else %}
<strong>There are no rooms in this hostel.</strong>
{% endif %}
{% endblock %}
There are many ways to achieve this. The simplest is to add this in the view. There you have to check, if the user has already booked and if there are still rooms free.
def book(request):
# check if user has already booked:
has_booked = Booking.objects.filter(booked_by=request.user).exists()
# are room free?
rooms_full = Booking.objects.count() == 40
if rooms_full or has_booked:
# redirect to a error view
return ...
if request.method == "POST":
form = BookForm(request.POST)
if form.is_valid():
post = form.save(commit=True)
post.save()
else:
form = BookForm()
return render(request, 'gyobera/book_now.html', {'form': form})
Related
Good Day,
I have a delete btn for each created Title. When you click on the delete button, the model will be delete with the url localhost:8000/delete/OBJECT_ID
models.py
class NewTitle(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
default=None,
null=True,
on_delete=models.CASCADE,
)
title = models.CharField(max_length=200)
creator_adress = models.GenericIPAddressField(null=True)
id = models.BigAutoField(primary_key=True)
def __str__(self):
return str(self.title)
views.py
def title_view(request):
custom_title_id = random.randint(1111, 1111111111111)
titles = # What to here, maybe NewTitle.pk?
if request.method == 'POST':
form = NewTitleForm(request.POST, instance=NewTitle(user=request.user))
if form.is_valid():
obj = form.save(commit=False)
obj.creator_adress = get_client_ip(request)
obj.id = custom_title_id
while NewTitle.objects.filter(id=obj.id).exists():
obj.id = random.randint(111, 11111111111)
obj.save()
return redirect('/another')
else:
form = NewTitleForm()
return render(request, 'test.html', {'form': form, 'titles': titles})
def title_delete(request, title_id):
user_title = NewTitle.objects.filter(id=title_id,
user=request.user)
if user_title:
user_title.delete()
else:
return redirect('https://example.com')
return HttpResponseRedirect('/another')
test.html
{% for i in request.user.newtitle_set.all %}
<p> {% if i.user == request.user %} {{ i.title }} {% endif %} <form action="delete/ #THE CURRENT OBJECT ID" method="POST">{% csrf_token %}<button type="submit">Delete Title</button></form> </p>
{% endfor %}
Every 'Title' is displayed in the template. Next to each title there is a Delete button that leads to delete/OBJECT_ID. How can I set the action="" to the correct delete URL. So that I get the current ID of the title (object).
The interesting part is in views.py the titles variable and in test.html the second form action=""
Thank you very much! :-)
You can use url template filter, but first you need to give the url which leads to title_delete a name (for example "delete_title").
Then for the button you can write action={% url 'delete_title' i.id %} .
It will automatically create the url which leads to title_delete view and will also put the id in the request path.
I'm making a low-spec e-bay clone, I'm trying to implement a watchlist function but the problem is I can't access the ManyToManyField in the Watchlist model so I can use the contents of the field in the template I'm using. To display each user's watchlist to them, so far I only get this result:
but I need to get a result like so:
Code I'm using:
watchlist.html
{% extends "auctions/layout.html" %}
{% load static %}
{% block title %} {{name}}'s Watchlist {% endblock %}
{% block body %}
<h2>{{name}}'s Watchlist</h2>
{% for listing in watchlist %}
<div class='listing'>
<h3>{{ listing.list_title}}</h3>
{% if listing.img_url == "" %}
<a href='#'><img src="{% static 'auctions/img404.png' %}" class='img-fluid'></a>
{% else %}
<a href='#'><img src="{{ listing.img_url }}" class="img-fluid" alt='image of {{ listing.list_title }}'></a>
{% endif %}
<p>
{{ listing.desc }}
</p>
<p>
Current Bid: ${{ listing.start_bid }}
</p>
{% if listing.category == "" %}
<p>Category: No Category Listed</p>
{% else %}
<p>Category: {{ listing.category }}</p>
{% endif %}
<a href='#' class='btn btn-primary' id='go'>Go To Listing</a>
</div>
{% endfor %}
{% endblock %}
views.py
def render_listing(request, title):
if request.method == "POST":
form = BidForm(request.POST)
bid = int(request.POST['new_bid'])
listing = Auction_Listing.objects.get(list_title=title)
comments = Auction_Comments.objects.all().filter(auction_id=listing)
if bid < listing.start_bid:
error = True
else:
error = False
listing.start_bid = bid
listing.save()
return render(request, 'auctions/listing.html', {
"listing": listing,
"form": form,
"comments": comments,
"error": error
})
else:
form = BidForm()
listing = Auction_Listing.objects.get(list_title=title)
comments = Auction_Comments.objects.all().filter(auction_id=listing)
return render(request, 'auctions/listing.html', {
"listing": listing,
"form": form,
"comments": comments,
"error": False
})
#login_required
def watchlist_render(request):
user = request.user.id
username = request.user.username
watched = Watchlist.objects.filter(user_id=user)
return render(request, 'auctions/watchlist.html', {
"watchlist": watched,
"name": username
})
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.db.models.deletion import CASCADE
CATEGORIES = [
('Appliances', 'Appliances'),
('Tech', 'Tech'),
('Gaming', 'Gaming'),
('Fashion', 'Fashion'),
('Sports and Fitness','Sports and Fitness'),
('Other','Other'),
("Hygiene and Medicine","Hygiene and Medicine"),
("Stationery","Stationery"),
('Decor', 'Decor'),
('Furniture','Furniture'),
('Cars and Mechanical Things','Cars and Mechanical Things'),
("Tools","Tools")
]
# Create models here
class User(AbstractUser):
pass
class Auction_Listing(models.Model):
user_id = models.IntegerField(default=1)
list_title = models.CharField(max_length=64)
desc = models.TextField(max_length=324)
img_url = models.URLField(max_length=200, null=True, blank=True)
start_bid = models.IntegerField()
category = models.CharField(choices=CATEGORIES, max_length=35, null=True, blank=True)
def __str__(self):
return f"ID:{self.id}, {self.list_title}: {self.desc}, {self.start_bid} posted by user:{self.user_id} in Category:{self.category}, url:{self.img_url}"
class Bids(models.Model):
bid = models.IntegerField(default=0)
user_id = models.IntegerField(default=1)
auction_id = models.ManyToManyField(Auction_Listing)
def __str__(self):
return f"ID:{self.id}, Bid {self.bid} posted by user:{self.user_id} on auction {self.auction_id}"
class Auction_Comments(models.Model):
user_id = models.IntegerField(default=1)
comment = models.TextField(max_length=324, default='N/A')
auction_id = models.ManyToManyField(Auction_Listing)
def __str__(self):
return f"ID:{self.id}, Comment: {self.comment} posted by user:{self.user_id} on auction {self.auction_id}"
class Watchlist(models.Model):
user_id = models.ForeignKey(User, on_delete=CASCADE,default=1)
auction_id = models.ManyToManyField(Auction_Listing, related_name='auction_listing')
def __str__(self):
return f"ID:{self.user_id} on auction {self.auction_id}"
Thanks in advance for the help!
Kind Regards
PrimeBeat
EDIT: The results of the links as #nigel222 requested
Ahh CS50W. I love this course. Anyway, I recognize where you've gotten stuck. What you're doing is that you're passing the Watchlist object in the context, instead of passing a list of listings.
This is why your {% for listing in watchlist %} is failing, because watchlist is a single object.
What you can do instead is, in your views.py, get the full list of watched items, and pass in that list in as the context. So:
#login_required
def watchlist_render(request):
user = request.user.id
username = request.user.username
# This will give you the Watchlist instance
watchlist = Watchlist.objects.filter(user_id=user)
# I would recommend renaming auction_id (in your models.py file) to `auctionItems` or 'listings'
# because it returns an object of type Auction_Listing, rather than just the id.
# for eg. watchlist.listings.all() allows you to instinctively understand what you're trying to do.
# Now you can extract the listings from the watchlist
listings = watchlist.auction_id.all()
return render(request, 'auctions/watchlist.html', {
"watchlist": listings,
"name": username
})
Now in your template you can access each listing in the list: {% for listing in listings %}
Unable to delete an object:
HViews is as follows
def deleteorder(request, pk):
order = Order.object.get(id=pk)
if request.method == 'POST':
order.delete()
return redirect()
context = {'item':order}
return render(request,'accounts/delet.html', context)
And
Urls.py is as
path('delete_order/<str:pk>/', views.deleteorder, name= 'delete_order')
models.py
class Order(models.Model):
STATUS = ( (' Pending', 'Pending'), ('Out for Delivery ', 'Out for Delivery '), ('Delivered ', 'Delivered ') , )
customers = models.ForeignKey(Customer, null=True, on_delete= models.SET_NULL)
products = models.ForeignKey( Product, null=True, on_delete = models.SET_NULL)
created_date = models.DateTimeField(auto_now_add=True, null=True)
status = models.CharField(max_length=100, null=True, choices = STATUS)
def __str__(self):
return self.products.name
Try this and see it it work for you. How to delete an order by ID or pk. For example you have order views like this:
def order_views(request):
my_order = OrderItem.objects.all()
#you can also filter through your order
context = {'my_order': my_order}
{% for order in my_order %}
#Your code here
Delete
{% endfor %}
def deleteorder(request, pk):
order = Order.object.get(id=pk)
order.delete()
return redirect()
path('delete_order/<pk>/', views.deleteorder, name= 'delete_order')
or
path('delete_order/<int:pk>/', views.deleteorder, name= 'delete_order')
Remember to pass the correct Order context with the pk in template, so you don't get reverse not found.
my code where POST is being called is given below.
{% extends 'accounts/main.html' %}
{% load static %}
{% block content %}
<form action="" method="POST">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{form}}
<hr>
{% endfor %}
<input type="submit" name="Submit">
</form>
{% endblock %}
I am working on a Hybrid of Quora and StackOverflow clone. I have made an "add_answer" view for letting me add answers to the questions but for some reasons it is showing the integrity error:
Here's the error image
But when I add through admin panel then it adds answer in the database. What is wrong?
The code is as follows:
models.py:
class Answer(models.Model):
content = models.TextField()
user = models.ForeignKey(User,on_delete=models.CASCADE)
question = models.ForeignKey(Question,on_delete=models.CASCADE,blank=False)
created = models.DateTimeField(auto_now_add=True)
upvotes = models.PositiveIntegerField(default=0)
is_active = models.BooleanField(default=True)
def __str__(self):
return '{}\'s Answer'.format(self.user.username)
class Meta:
ordering = ('-upvotes','-created')
forms.py:
class AnswerForm(forms.ModelForm):
content = forms.CharField(widget=forms.Textarea,help_text='Your Answer in Detail. Note: MarkDown is enabled.')
class Meta:
model = Answer
fields = ['content']
def __init__(self,author,question,*args,**kwargs):
super().__init__(*args,**kwargs)
self.user = author
self.question = question
"add_answer" view (views.py):
#login_required
def add_answer(request, pk):
ques = get_object_or_404(Question, pk = pk)
if request.method == 'POST':
form = AnswerForm(request.user,ques,request.POST)
if form.is_valid():
cd = form.cleaned_data
answer = form.save(commit=False)
answer.content = cd['content']
answer.save()
messages.success(request,'Success! Your Answer has been added!')
return redirect('forum')
else:
messages.error(request,form.errors)
else:
form = AnswerForm(request.user,ques)
return render(request,'discussion/answer_create.html',{'form':form})
answer_create.html (template):
{% extends 'base.html' %}
{% load markdownify %}
{% block title %} Add Answer {% endblock %}
{% block header %}
<h2 class="display-5" style="font-family: x-locale-heading-primary,zillaslab,Palatino,Palatino Linotype,x-locale-heading-secondary,serif;">
Add Answer:
</h2>
{% endblock %}
{% block content %}
{% if form.errors %}
<h4 class="alert alert-primary alert-warning" role="alert">Errors:<br> {{form.errors}} <hr></h4>
{% endif %}
<form action="" method="POST">
{% csrf_token %}
{{form.as_p}}
<input type="submit">
</form>
{% endblock %}
It would be really grateful if somebody helps me out.
You forgot to assign the question instance to answer model
answer.question = ques
ques = get_object_or_404(Question, pk = pk)
if form.is_valid():
cd = form.cleaned_data
answer = form.save(commit=False)
answer.question = ques
answer.content = cd['content']
answer.save()
you can also do the following in model form init
def __init__(self,author,question,*args,**kwargs):
super().__init__(*args,**kwargs)
self.form.instance.user = author
self.form.instance.question = question
I'm making a comment system for my django app and i've been told it's best to make a seperate model for comment-voting. So i've done that and here's my models.py:
class Comment(models.Model):
user = models.ForeignKey(User, default=1)
destination = models.CharField(default='1', max_length=12, blank=True)
author = models.CharField(max_length=120, blank=True)
comment_id = models.IntegerField(default=1)
parent_id = models.IntegerField(default=0)
comment_text = models.TextField(max_length=350, blank=True)
timestamp = models.DateTimeField(default=timezone.now, blank=True)
def __str__(self):
return self.comment_text
class CommentScore(models.Model):
user = models.ForeignKey(User, default=1)
comment = models.ForeignKey(Comment, related_name='score')
upvotes = models.IntegerField(default=0)
downvotes = models.IntegerField(default=0)
def __str__(self):
return str(self.comment)
Here's my views.py where the comments are created:
def article(request, category, id):
name = resolve(request.path).kwargs['category']
for a, b in CATEGORY_CHOICES:
if b == name:
name = a
instance = get_object_or_404(Post, id=id, category=name)
allauth_login = LoginForm(request.POST or None)
allauth_signup = SignupForm(request.POST or None)
#comments
comment = CommentForm(request.POST or None)
ajax_comment = request.POST.get('text')
comment_length = len(str(ajax_comment))
comment_list = Comment.objects.filter(destination=id)
score = CommentScore.objects.filter(comment=comment_list)
if request.is_ajax():
if comment.is_valid():
comment = Comment.objects.create(comment_text=ajax_comment, author=str(request.user), destination=id)
print(comment)
comment.save()
score = CommentScore.objects.create(comment=comment)
score.save()
username = str(request.user)
return JsonResponse({'text': ajax_comment, 'text_length': comment_length, 'username': username})
else:
print(comment.errors)
context = {
'score': score,
'comment_list': comment_list,
'comment': comment,
'instance': instance,
'allauth_login': allauth_login,
'allauth_signup': allauth_signup
}
return render(request, 'article.html', context)
So the comment works fine, but as you can see a couple lines later i'm trying to then create a CommentScore instance to match with the comment. In my template, I've rendered each comment and it's fields (comment_text, author etc), but I want to render the upvotes field associated with that comment. How would I do this?
template
{% for i in comment_list %}
<div class='comment_div'>
<h3>{{ i.author }}</h3>
<p>{{ i.comment_text }}</p><br>
</div>
{% endfor %}
forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = [
'comment_text',
'id',
'author',
'destination',
]
I've already tried the following and they haven't worked;
{% for i in comment_list %}
<div class='comment_div'>
<h3>{{ i.author }}</h3>
<p>{{ i.comment_text }}</p><br>
{% for i in comment_list.score_set.all %}
{{ i.upvotes }} #renders nothing
{% endfor %}
</div>
{% endfor %}
{% for i in comment_list %}
<div class='comment_div'>
<h3>{{ i.author }}</h3>
<p>{{ i.comment_text }}</p><br>
{% for j in i.score %}
{{ j.upvotes }} #Error: 'RelatedManager' object is not iterable
{% endfor %}
</div>
{% endfor %}
Having a lot of trouble so help is appreciated.
Changing "i.score" to "i.score.all" resolves the problem as the RelatedManaager error usually happens when you are trying to iterate over the manager and not the objects selected by that manager. - Solved by #joe-j
So it works now but if someone could explain the 2nd line of this syntax that would be great:
comment_list = Comment.objects.filter(destination=id)
score = CommentScore.objects.filter(comment=comment_list)
What exactly is happening when I assign comment=comment_list here? I copied this code from someone else but i'm still abit unsure how it's working.