I have a form on my webpage for users to create a new listing. The form loads up okay but on submission an error comes up:
NoReverseMatch at /NewListing
Reverse for 'listing' with keyword arguments '{'listing': None}' not found. 1 pattern(s) tried: ['(?P<listing_id>[0-9]+)$']
The form does save the new listing and update the homepage with the new listing but I would like that once the listing is submitted, the user is taken to the new listing page and I can't seem to get that to work without this error popping up.
models.py
class Category(models.Model):
group = models.CharField(max_length=20)
def __str__(self):
return f"{self.group}"
class Listing(models.Model):
title = models.CharField(max_length=64)
description = models.TextField(max_length=64)
price = models.DecimalField(max_digits=9, decimal_places=2, validators=[MinValueValidator(0.99)])
image = models.URLField(max_length=200, blank=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="categories")
def __str__(self):
return f"Product: {self.title} \nDescription: {self.description} \nCurrent Price: £{self.price}\nImage: {self.image} \nCategory: {self.category}"
forms.py
class NewListingForm(forms.ModelForm):
class Meta:
model = Listing
fields = ["title", "description", "price", "image", "category"]
title = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
description = forms.CharField(widget=forms.TextInput(attrs={'autocomplete':'off'}))
price = forms.DecimalField(label='Starting Bid Price (£)')
image = forms.URLField(widget=forms.URLInput(attrs={'autocomplete':'off'}))
views.py
def listing(request, listing_id):
listing = Listing.objects.get(pk=listing_id)
return render(request, "auctions/listingPage.html", {
"listing": listing
})
def newListing(request):
if request.method == "POST":
form = NewListingForm(request.POST)
if form.is_valid():
title = form.cleaned_data['title']
description = form.cleaned_data['description']
price = form.cleaned_data.get('price')
image = form.cleaned_data['image']
category = form.cleaned_data['category']
listing = Listing(title=title, description=description, price=price, image=image, category=category)
form.save()
return HttpResponseRedirect(reverse("listing", kwargs={'listing': listing.id}))
else:
return render(request, "auctions/newListing.html", {
"form": form,
})
else:
form = NewListingForm()
return render(request, "auctions/newListing.html", {
"form": form
})
urls.py
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("<int:listing_id>", views.listing, name="listing"),
path("NewListing", views.newListing, name="newListing")
]
You're making a new Listing by hand from the form data, but never saving it, so it never gets an ID.
As a result, the URL that your code tries to compute as the redirection destination uses None instead of an integer for the listing ID, which blows up, because it's expecting an integer ID.
(You also save the modelform, but you don't do anything with the data that returns.)
Instead of this:
listing = Listing(title=title, description=description, price=price,image=image, category=category)
form.save()
Try just:
listing = form.save()
to let the ModelForm do all the heavy lifting and return saved object with an ID because it's in the database - that's what model forms are there for :o) https://docs.djangoproject.com/en/3.1/topics/forms/modelforms/#the-save-method
Related
--WHY I CANT TO ACCESS TO ID OF USER AND PRODUCT WITH user__id and product__id?
i have error: (The view store.views.submit_review didn't return an HttpResponse object. It returned None instead).
<pre><code>
i define some code for rating post for any user user
--#views
def submit_review(request, product_id):
url = request.META.get('HTTP_REFERER')
if request.method == 'POST':
try:
reviews = ReviewRating.objects.get(user__id=request.user.id,Product__id=product_id) #my problem is here
form = Reviewform(request.POST, instance=reviews)
form.save()
messages.success(request, 'Thank you!your review has been updated.')
return redirect(url)
except ReviewRating.DoesNotExist:
form = Reviewform(request.POST)
if form.is_valid():
data = ReviewRating()
data.subject = form.cleaned_data['subject']
data.review = form.cleaned_data['review']
data.rating = form.cleaned_data['rating']
data.ip = request.META.get['REMOTE_ADDR']
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted')
return redirect(url)
</code></pre>
this section i define model.I checked this part it work correctly
define model for views in my app
#models
class ReviewRating(models.Model):
Product = models.ForeignKey(product, on_delete=models.CASCADE)
user = models.ForeignKey(Account, on_delete=models.CASCADE)
subject = models.CharField(max_length=100, blank=True)
review = models.TextField(max_length=500, blank=True)
rating = models.FloatField()
ip = models.CharField(max_length=20, blank=True)
status = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.subject
this part i define url
#urls
define path for html and views
urlpatterns = [
path('submit_review/int:product_id/',views.submit_review,name='submit_review')
]
your model is not clear. It would be better if you could atleast share your full model.py file
if you provide the objective of your service with models.py, serializers.py, views.py I think I will be able to help more specifically
till now, one issue i've found in the the url section is that you need to add < > on int:product_id.
it should be,
urlpatterns = [
path('submit_review/<int:product_id>/',views.submit_review,name='submit_review')
]
I am trying to create a web app that has a Like button option for the Post. Everything works fine but when I click on the Like button it shows DoesNotExist error.
This is the model part of the code:
class Like(models.Model):
user = models.ForeignKey(Yatru, on_delete=models.CASCADE)
location = models.ForeignKey(Post, on_delete=models.CASCADE)
value = models.CharField(choices=LIKE_CHOICES, max_length=8)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user}-{self.location}-{self.value}"
This is the views:
def like_unlike(request):
user = request.user
if request.method == 'POST':
location_id = request.POST.get('location_id')
location_obj = Post.objects.get(id=location_id)
profile = Yatru.objects.get(user=user)
if profile in location_obj.liked.all():
location_obj.liked.remove(profile)
else:
location_obj.liked.add(profile)
like, created = Like.objects.get_or_create(user=profile, location_id=location_id)
if not created:
if like.value=='Like':
like.value='Unlike'
else:
like.value='Like'
location_obj.save()
like.save()
return redirect('posts:post_views')
When I try to load the page it shows this error:
DoesNotExist at /posts/liked
I am sorry for asking this. I described a service that uploads an image through a form. The bottom line is that after a successful download (add_picture), I have to get to the image page (picture_detail). I don’t understand why I can’t transfer ID. I did the following:
models.py:
class Picture(models.Model):
url = models.URLField(blank=True, verbose_name='Ссылка на изображение')
image = models.ImageField(upload_to='pictures/%Y/%m/%d', width_field='image_width', height_field='image_height',
blank=True, verbose_name='Изображение')
def get_absolute_url(self):
return reverse('home:picture_detail', args=[self.id])
views.py:
def add_picture(request, id=None):
picture = Picture.objects.filter(is_active=True)
# picture_form = None
# picture = get_object_or_404(Picture, id=id)
if request.method == 'POST':
form = PictureCreateForm(data=request.POST, files=request.FILES)
if form.is_valid():
form.save()
picture_id = form.save()
request.session['id'] = picture_id.id
id = request.session.get('id')
return HttpResponseRedirect(reverse('home:picture_detail', kwargs={'id': id}))
else:
return render(request, 'add_picture.html', locals())
else:
form = PictureCreateForm()
return render(request, 'add_picture.html', locals())
urls.py:
urlpatterns = [
path('', views.home, name='home'),
path('add_picture/', views.add_picture, name='add_picture'),
path('picture_detail/<int:id>/', views.picture_detail, name='picture_detail'),
]
As a result, I should get to a page of this kind:
The id can be obtained out of the result of the form.save():
from django.shortcuts import redirect
# …
if form.is_valid():
item = form.save()
return redirect('home:picture_detail', id=item.id)
# …
Hurrah! I managed. All that was needed was to pass the id to the session. I have corrected my code and it works. Look in views.py.
Short background of whole idea: I'm trying to create landing page and for backend I use Python/Django3 framework. I need to create form with such fields as name, surname, email, mobile number and address of customer.
I've decided to save all the information that the user enters in the database, and also send it to my email. In order to connect database to forms I use ModelForms in forms.py section (all the required code will be shown below). In order to connect my email to form I use send_mail function from django.core.mail.
So when a user fills out his form, he is redirected to the 'thank you' page and all the information from the form is saved in the database and sent to my email.
But when I finally wrote the code and started to test functionality, I found out that when I hit 'submit' form button, error <type object 'ClientInfoForm' has no attribute 'cleaned_data'> is raised.
I suppose, that method cleaned_data is wrong in my case and I have to replace it with something else but I don't know with what exactly. All the code will be placed below and any help will be helpful. Thank you!
Models.py file
from django.db import models
class ClientInfo(models.Model):
name = models.CharField(max_length=264)
surname = models.CharField(max_length=264)
email = models.EmailField(max_length=264, unique=True)
mobile_number = models.CharField(max_length=20, unique=True)
address = models.CharField(max_length=264)
def __str__(self):
return f'Client: {self.name} {self.surname}'
Forms.py file
from django import forms
from landing_page.models import ClientInfo
class ClientInfoForm(forms.ModelForm):
class Meta():
model = ClientInfo
fields = '__all__'
Views.py file
from django.shortcuts import render
from landing_page.forms import ClientInfoForm
from django.core.mail import send_mail
def thanks(request):
return render(request, 'landing_page/thanks.html')
def index(request):
form = ClientInfoForm()
if request.method == 'POST':
form = ClientInfoForm(request.POST)
if form.is_valid():
form.save(commit=True)
name = ClientInfoForm.cleaned_data['name']
surname = ClientInfoForm.cleaned_data['surname']
email = ClientInfoForm.cleaned_data['email']
mobile_number = ClientInfoForm.cleaned_data['mobile_number']
address = ClientInfoForm.cleaned_data['address']
send_mail(
f'New client: {name} {surname}',
f'Client Name: {name}\nClient Surname: {surname}\nClient email: {email}\n'
f'Client Mobile Number: {mobile_number}\nClient address: {address}',
email,
['zombe#yandex.ru'],
)
return thanks(request)
else:
print('ERROR FORM INVALID')
return render(request, 'landing_page/index.html', {'form':form})
guys, in case you all interested I found out what was the actual problem. I just had to change this code below
name = ClientInfoForm.cleaned_data['name']
surname = ClientInfoForm.cleaned_data['surname']
email = ClientInfoForm.cleaned_data['email']
mobile_number = ClientInfoForm.cleaned_data['mobile_number']
address = ClientInfoForm.cleaned_data['address']
To this version
name = form.cleaned_data['name']
surname = form.cleaned_data['surname']
email = form.cleaned_data['email']
mobile_number = form.cleaned_data['mobile_number']
address = form.cleaned_data['address']
Let's say we have this model:
class Creation(models.Model):
title = models.CharField(max_length=DEFAULT_LENGTH)
url = models.CharField(max_length=DEFAULT_LENGTH)
date = models.DateTimeField('date published', default=datetime.date.today)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
def __str__(self):
return self.title
And let's use this view:
def submit(request):
FormSet = modelformset_factory(Creation, fields=('title', 'url'))
if request.method == 'POST':
formset = FormSet(request.POST, request.FILES)
if formset.is_valid():
obj = formset.save(commit=False)
obj.author = request.user
obj.save()
else:
formset = FormSet
return render(request, 'app/submit.html', {'formset': formset})
I saved formset to obj and added request.user and committed it to the database.
This doesn't work, because now django throws an error which says
'list' object has no attribute 'author'
which makes perfectly sense, because there is no author in the fields-list above.
But if I add 'author' to fields, another selectbox would be displayed while rendering the template via {{formset}}.
Maybe I could code my own template-code instead of using {{formset}} and omit the author, but I feel that there must be a more elegant way with Django3.0. Is there any?
All I want to do is to get the foreignkey author (see model above) filled with the logged in user.
Turns out that something is wrong with modelformset_factory(..).
If you use a proper CreationForm in models.py:
class CreationForm(ModelForm):
class Meta:
model = Creation
fields = ['title', 'url']
and use it in your views.py:
formset = CreationForm(request.POST)
if request.method == 'POST':
if formset.is_valid():
f = formset.save(commit=False)
f.author = request.user
f.save()
it works.