Django get current Model ID - python

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.

Related

Accessing a ManyToManyField's contents for a Django template

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 %}

Comment form in django didn't save the new comments

I've created a new form for comments the articles on a website. When I add the new comment from django admin everything works ok, but when I try to add the new comment directly from detail page nothings happen and I'am redirecting to the page with list of articles.
here are my files
models.py:
class Komentarz(models.Model):
post = models.ForeignKey(Wpisy, related_name="komentarze", verbose_name="Komentarze do artykułu", on_delete=models.CASCADE)
name = models.CharField(max_length=80, verbose_name="Imię")
email = models.EmailField(verbose_name="Email")
content = models.TextField(verbose_name="Treść komentarza")
created_date = models.DateTimeField(verbose_name="Utworzono", auto_now_add=True)
active = models.BooleanField(verbose_name="Aktywny?", default=True)
class Meta:
ordering = ('created_date',)
verbose_name="Komentarz"
verbose_name_plural="Komentarze"
def __str__(self):
return 'Komentarz dodany przez {} dla strony {}'.format(self.name, self.post)
vies.py with the function of details
from django.shortcuts import render, get_object_or_404
from .models import Wpisy, Komentarz
from .forms import KomentarzeForma
....
def detale_bajki(request, slug, ):
detale_bajki = get_object_or_404(Wpisy, slug=slug)
komentarze = detale_bajki.komentarze.filter(active=True)
if request.method == 'POST':
formularz_komentarza = KomentarzeForma(data=request.POST)
if formularz_komentarza.is_valid():
nowy_komentarz = formularz_komentarza.save(commit=False)
nowy_komentarz.detale_bajki = detale_bajki
nowy_komentarz.save()
else:
formularz_komentarza = KomentarzeForma()
return render(request, 'bajki/detale_bajki.html', {'detale_bajki': detale_bajki, 'komentarze': komentarze, 'formularz_komentarza': formularz_komentarza})
forms.py
from .models import Komentarz
from django import forms
class KomentarzeForma(forms.ModelForm):
class Meta:
model = Komentarz
fields = ('name', 'email', 'content')
and detail.html
...
{% with komentarze.count as total_komentarze %}
<h2>
{{ total_komentarze }} komentarz{{ total_komentarze|pluralize:"y" }}
</h2>
{% endwith %}
{% for komentarz in komentarze %}
Komentarz dodany przez <strong>{{komentarz.name}}</strong>
{{komentarz.created_date}}
<p>
{{ komentarz.content|linebreaks }}<br>
{% empty %}
<p>Nie dodano jeszcze żadnych komentarzy</p>
{% endfor %}
{% if nowy_komentarz %}
<h2>Twój komentarz został dodany</h2>
{% else %}
<h2>Dodaj nowy komentarz</h2>
<form action="." method="post">
{{formularz_komentarza.as_p}}
{% csrf_token %}
<p><input type="submit" value="Dodaj komentarz"></p>
</form>
{% endif %}
clas Wpisy in models.py
class Wpisy(models.Model):
title = models.CharField(max_length=400, verbose_name="Tytuł")
slug = models.SlugField(unique=True, max_length=400,verbose_name="Przyjazny adres url")
content = models.TextField()
status_audio = models.BooleanField(default=False, verbose_name="Czy dostępny będzie plik audio?")
audio_file = models.FileField(upload_to='uploads/',verbose_name="Plik audio")
created_date = models.DateTimeField(blank=True, null=True, verbose_name="Data utworzenia")
category = models.ForeignKey(Kategorie, verbose_name="Kategoria", on_delete=models.CASCADE)
class Meta:
verbose_name="Wpis"
verbose_name_plural="Wpisy"
def __str__(self):
return self.title
Your url pattern is
path('bajki/<slug>', views.detale_bajki, name='detale_bajki')
Note that it doesn't have a trailing slash. Your form's action is "."
<form action="." method="post">
That means you are submitting to /bajki/, which is the wrong URL.
You could fix this by adding a trailing slash to the url (which is common in Django URLs)
path('bajki/<slug>/', views.detale_bajki, name='detale_bajki')
Or you could change the form action to "" instead of ".". In the comments it looks like you fixed the issue by changing the form action to {{ detale_bajki.slug }}.
However these changes to the form action are fragile, and could break if you change your URL patterns again. The best approach is to use the {% url %} tag to reverse the correct URL.
<form action="{% url 'detale_bajki' detale_bajki.slug %}" method="post">
Try out:
nowy_komentarz.post = detale_bajki
...
return render(request, 'html page', {'key': 'what you want to return to your context'}) # don't fornget to add some return to your view.

Django editing model instance

The Django project that I am working on lists patient details and lets the user edit the details. I have been able to list it out but views.py is not getting linked to the url for updating the list.
views.py:
def update_patient(request, patient_id):
patient = Patient.objects.get(id=patient_id)
if request.method != 'POST':
form = PatientForm(instance=patient)
else:
# POST data submitted; process data.
form = PatientForm(instance=patient, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('patient:patient',
args=[patient.id]))
context = { 'patient': patient, 'form': form}
return render(request, 'patient/update_patient.html', context)
models.py:
class Patient(models.Model):
patientID = models.CharField(max_length=20)
firstName =models.CharField(max_length=20)
lastName = models.CharField(max_length=20)
age = models.IntegerField(max_length=None)
SSN = models.CharField(max_length=15)
address = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
urls.py:
url(r'^patients/(?P<patient_id>\update\d+)/$', views.update_patient, name='update'),
update_patient.html:
{% extends "patient/base.html" %} {% block content %}
<p>{{ patient }}
</p>
<p>Update Patient:</p>
<form action="{% url 'patient:update' patient.id %}" method='post'>
{% csrf_token %} {{ form.as_p }}
<button name='submit'>add entry</button>
</form>
{% endblock content %}
Your URL pattern is wrong, you have \update within capturing group, it shouldn't be, change the pattern to this:
url(r'^patients/(?P<patient_id>\d+)/update/$', views.update_patient, name='update')

can't figure out how to present my logic within the project

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})

Page not save forms data in django

I am trying to do exercise 7 in tango with django where i must save new page to specific category by adding information to forms.
So I write new code to forms.py
class PageForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="Please enter the title of the page.")
url = forms.CharField(max_length=200, help_text="Please enter the url of the page.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
class Meta:
model = Page
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
if url and not url.startswith('http//'):
url = 'http://' + url
cleaned_data['url'] = url
return cleaned_data
fields = ('title', 'url', 'views')
def save_form(self):
if self.is_valid():
page = self.save(commit=False)
try:
cat = Category.objects.get(name=category_name)
page.category = cat
except:
return render_to_response('rango/add_category.html', {}, context)
page.views = 0
page.save()
return True
else:
return False
Then I edit views.py
def add_page(request, category_name_url):
context = RequestContext(request)
category_name = decode_url(category_name_url)
if request.method == 'POST':
form = PageForm(request.POST)
if form.save_form():
return category(request, category_name_url)
else:
print form.errors
else:
form = PageForm()
return render_to_response( 'rango/add_page.html',
{'category_name_url': category_name_url,
'category_name': category_name,
'form': form},
context)
def decode_url(element):
return element.replace(' ', '_')
def encode_url(element):
return element.replace('_', '')
Then I created template:
Rango
<body>
<h1>Add page to category</h1>
<form id="page_form" method="post" action="/">
{% csrf_token %}
{% for hidden in forms.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="submit" name="Submit" value="Add a page" />
</form>
</body> </html>
I have made reference to new page in category.html
Add page to this category
And of course a edit urls.py
> url(r'^rango/category/(?P<category_name_url>\w+)/add_page/$',
> views.add_page, name='add_page'),
Everything is visible and I am able to fill form. But when i confirm data by clicking on button, page is return to home and not in category and new page is not save in database. So please someone, where a have error?
Your <form> element has the action set to action="/". This makes the form submit send a POST request to the homepage not the current page. You can correct this by making the form action empty action="" to submit to the current URL or be explicit and use the {% url %} template tag for the required form action.

Categories