Have slug populate from title or create random - Django Form - python

I would like the slug to be generated automatically from the title the user imports, or have random integers generated if the title is blank. The way I currently have it, the slug is supposed to be populated from the form title, but I get an error saying the form doesn't have a title field.
So, I need to:
change the slug in the views.py to be populated from the inputed title
create a random integer generator if the title is blank (I'm assuming in models.py and views.py?)
Could someone please help me with this?
Thank you in advance! I appreciate any and all help!
forms.py:
class PhotoUploadForm(forms.ModelForm):
title = forms.CharField(
widget=forms.TextInput(attrs={"placeholder": "Title of photo", "size": "30"})
)
description = forms.CharField(
widget=forms.Textarea(attrs={"placeholder": "Description of photo"})
)
class Meta:
model = Photo
fields = ('category', 'title', 'description', 'image')
models.py:
class Photo(models.Model):
creator = models.ForeignKey(MyUser, null=False, blank=False)
title = models.CharField(max_length=30, null=True, blank=True)
description = models.TextField(max_length=120, null=True, blank=True)
image = models.ImageField(upload_to='user/photos/', null=True, blank=True)
slug = models.SlugField(null=False, blank=False)
active = models.BooleanField(default=True)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
class Meta:
ordering = ['-timestamp']
def __unicode__(self):
return "%s" %(self.creator)
views.py:
def photo_upload_view(request, username):
u = MyUser.objects.get(username=username)
form = PhotoUploadForm()
if request.method == 'POST':
form = PhotoUploadForm(request.POST or None, request.FILES)
new_slug = Photo.objects.get(slug=form.title)
if form.is_valid():
obj = form.save(commit=False)
obj.creator = request.user
obj.slug = slugify(new_slug)
obj.save()
messages.success(request, "Thank you! You have successfully posted your picture!")
return HttpResponseRedirect('/')
else:
form = PhotoUploadForm()
submit_btn = "Upload Post"
context = {
"submit_btn": submit_btn,
"form": form
}
return render(request, "photos/photo_upload.html", context)

This line is your problem:
new_slug = Photo.objects.get(slug=form.title)
You're setting the value of new_slug to a retrieved object, not a string. That isn't going to slugify. You probably just want this:
new_slug = form.title
But if you actually want to retrieve a value from a Photo, reference that attribute at the end, so:
new_slug = Photo.objects.get(slug=form.title).slug
As for generating a random integer:
from random import randint
randint(0,100)
Will return a random integer between 0 and 100 (inclusive).

Related

View returning None and not returning a response object django

What I am working on is saving a new listing that is created by a given user on my commerce site, and displaying/redirecting the user to my index page. For some reason, the view keeps returning None and I'm not exactly sure why. Here is the code snippets below:
views.py
def createListing(request):
if request.method == "POST":
listing = NewListingForm(request.POST)
if listing.is_valid():
creator = request.user
title = listing.cleaned_data['title']
price = listing.cleaned_data['price']
description = listing.cleaned_data['description']
image = listing.cleaned_data['image']
category = listing.cleaned_data['category']
# Using .objects.create much simpler solution
auction = Listing.objects.create(
creator=creator,
title=title,
description=description,
price=price,
category=category,
image=image,
)
starting_bid = auction.price
bid = Bid.objects.create(
bid=starting_bid,
user=creator,
auction=auction
)
return render(request, "auctions/index.html", {
"message": "Listing Created Successfully."
})
if request.method == "GET":
return render(request, "auctions/create.html", {
"create_form": NewListingForm()
})
models.py
class User(AbstractUser):
pass
class Comment(models.Model):
comment = models.CharField(max_length=64)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user_comment")
class Listing(models.Model):
CATEGORIES = [
('Toys', 'Toys'),
('Electronics', 'Electronics'),
('Lifestyle', 'Lifestyle'),
('Home', 'Home'),
('Fashion', 'Fashion'),
('Other', 'Other')
]
creator = models.ForeignKey(User, on_delete=models.CASCADE, related_name="creator")
title = models.CharField(max_length=64, blank=False, null=False)
price = models.DecimalField(max_digits=10, decimal_places=2, blank=False, null=True)
description = models.CharField(blank=True, max_length=1064, null=True)
category = models.CharField(max_length=64, blank=True, choices=CATEGORIES)
image = models.URLField(default='https://user-images.githubusercontent.com/52632898/161646398-6d49eca9-267f-4eab-a5a7-6ba6069d21df.png')
starting_bid = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
bid_counter = models.IntegerField(default=0)
active = models.BooleanField(default=True)
winner = models.CharField(max_length=64, blank=True, null=True)
def _str__(self):
return f"{self.title} by {self.creator}"
class Bid(models.Model):
bid = models.DecimalField(decimal_places=2, max_digits=10)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user_bid")
date_created = models.DateTimeField(auto_now=True)
auction = models.ForeignKey(Listing, on_delete=models.CASCADE)
def __str__(self):
return f"{self.bid} made by {self.user}"
The new listing form:
# Creating a new listing form
class NewListingForm(forms.Form):
title = forms.CharField(label='', min_length=2, widget=forms.TextInput(
attrs={"class": "form-control", "style": "margin-bottom: 10px", "placeholder": "Title"}))
description = forms.CharField(label='', widget=forms.Textarea(
attrs={"class": "form-control", "style": "margin-bottom: 10px", "placeholder": "Description"}))
price = forms.DecimalField(label='', widget=forms.NumberInput(
attrs={"class": "form-control", "style": "margin-bottom: 10px", "placeholder": "Starting Bid ($)"}))
image = forms.ImageField(label="Choose an Image for your Listing")
category = forms.MultipleChoiceField(
label='Pick a Category', widget=forms.CheckboxSelectMultiple, choices=Listing.CATEGORIES)
I have tried looking into urls.py to ensure I was calling the right view with its according name and using 'return redirect('index')' but it doesn't seem to work either. I'm relatively new to django so any help would be appreciated! Let me know if there are any other files that are required to help clarify the problem.
Django handled http GET method automatically not needing to write it, and also need to remove the unwanted stuff.
your code becomes like this...
from django.shortcuts import render,redirect
from django.contrib import messages
def createListing(request):
listing =NewListingForm()
if request.method == "POST":
listing = NewListingForm(request.POST)
if listing.is_valid():
creator = request.user
title = listing.cleaned_data['title']
price = listing.cleaned_data['price']
description = listing.cleaned_data['description']
image = listing.cleaned_data['image']
category = listing.cleaned_data['category']
# Using .objects.create much simpler solution
auction = Listing.objects.create(
creator=creator,
title=title,
description=description,
price=price,
category=category,
image=image,
)
starting_bid = auction.price
bid = Bid.objects.create(
bid=starting_bid,
user=creator,
auction=auction
)
messages.success(request,"Listing Created Successfully")
return redirect("/home/")
context = {
"listing": listing
}
return render(request, "auctions/create.html", context)

Error when trying to save a form in django

I am new to django and I am working on a project whereby users fill a form from frontend and the data is saved to a gig model where the writer extends from a profile foreignkey. The error says
ValueError at /seller_profile/ The Gig could not be created because
the data didn't validate.
Here is the models.py:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(default='avatar.jpg', null=True, blank=True)
about = models.CharField(max_length=100)
def __str__(self):
return self.user.username
class Gig(models.Model):
writer = models.ForeignKey(Profile, on_delete = models.CASCADE, null=False, blank=False)
category = models.ForeignKey('Category', on_delete = models.CASCADE, null=False, blank=False)
title = models.CharField(max_length=500, null=True, blank=True)
description = models.CharField(max_length=500, null=True, blank=True)
image = models.ImageField(null=False, blank=False)
gig_id = models.UUIDField(default=uuid.uuid4, primary_key=True, unique=True, editable=False)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
Views.py:
def createGig(request):
gig = request.user.profile
form = CreateGigForm()
if request.method == 'POST':
form = CreateGigForm(request.POST, request.FILES)
if form.is_valid:
gig = form.save(commit=False)
gig.writer = gig
gig.save()
messages.info(request, 'Profile Succesfully Created')
return redirect('create')
else:
messages.error(request, 'Gig Not Created! Try Again Later')
context = {'form':form}
return render(request, 'starter/create_gig.html', context)
And here is a screenshot of the error message: Error message screenshot
I found the solution to this. The problem was with checking if form is valid there was an error with missing brackets. if form.is_valid: should be if form.is_valid:.

How to Write a blog post with slug & image (django)

When I clicked the publish button. I get this error (image field = `This field is required), and it's not submitting the post.
models.py:
class Blog(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='post_author')
blog_title = models.CharField(max_length=300, verbose_name='Put a Title')
slug = models.SlugField(max_length=264, unique=True, null=True)
blog_content = models.TextField(verbose_name='What is on your mind')
blog_image = models.ImageField(upload_to='blog_images', verbose_name='Image', null=True)
publish_date = models.DateTimeField(auto_now_add=True)
update_date = models.DateTimeField(auto_now=True)
def __str__(self):
return self.blog_title
views.py:
#login_required
def createblog(request):
form = CreateBlogPost()
if request.method == 'POST':
form = CreateBlogPost(request.POST, request.FILES)
if form.is_valid():
blog_obj = form.save(commit=False)
blog_obj.author = request.user
title = blog_obj.blog_title
print(title)
blog_obj.slug = title.replace(" ", "-")+"-"+str(uuid.uuid4())
print(blog_obj.slug)
blog_obj.save()
return HttpResponseRedirect(reverse('index'))
return render(request, 'App_Blog/create_blog.html', {'form': form})
This field is required this is a Validation error from Django form and it depends on your models, if you are using model form you have to set blank=True like this
blog_image = models.ImageField(upload_to='blog_images', verbose_name='Image', null=True,blank=True)
blank=True means field can be empty (it is not required field) and null=True means your database table column can accept null values.

Django M2M field in a Model Form?

I have a many to many field ConnectedTo in my model and I want to create the object using a form. However when I list it as a field I just get a listbox with options to highlight and no way of selecting one or more.
Ideally I'd love a multiple selection checkbox with a list of items in a scroll box. But I'd start with just having a selectable item.
Here's my code so far:
models.py:
class Part(models.Model):
PartID = models.AutoField(primary_key=True, unique=True)
SiteID = models.ForeignKey('Site', on_delete=models.CASCADE, null=True)
Comment = models.CharField(max_length=255, blank=True)
Subtype = models.ForeignKey('Subtype', on_delete=models.CASCADE, null=True)
Location = models.CharField(max_length=255, blank=True)
ConnectedTo= models.ManyToManyField('self', blank=True, null=True)
BatchNo = models.CharField(max_length=32, blank=False, null=True)
SerialNo = models.CharField(max_length=32,blank=True)
Manufacturer = models.CharField(max_length=32, blank=False, null=True)
Length = models.CharField(max_length=6, blank=True, null=True)
InspectionPeriod = models.IntegerField(blank=True, null=True)
LastInspected = models.DateField(blank=True, null=True)
InspectionDue = models.CharField(max_length=255, blank=True)
#classmethod
def create(cls, siteid, comment, subtype, location, batchno, serialno, manufacturer, length, inspectionperiod, lastinspected, inspectiondue):
part = cls(SiteID = siteid, Comment = comment, Subtype = subtype, Location = location, BatchNo = batchno, SerialNo = serialno, Manufacturer = manufacturer, Length = length, InspectionPeriod = inspectionperiod, LastInspected = lastinspected, InspectionDue = inspectiondue)
return part
def __str__(self):
return str(self.PartID)
forms.py:
class PartForm(forms.ModelForm):
class Meta:
model = Part
fields = ('Comment', 'Subtype', 'Location', 'ConnectedTo', 'BatchNo', 'SerialNo', 'Manufacturer', 'Length', 'InspectionPeriod', 'LastInspected')
views.py:
#login_required(login_url='/accounts/login/')
def addPartForm_Create(request, site, subtype):
siteselected = site
subtypeselected = Subtype.objects.get(SubtypeID = subtype)
if request.method == 'POST':
form = addPartForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.SiteID = Site.objects.get(SiteID = siteselected)
obj.Subtype = subtypeselected
obj.save()
return redirect('/sites/'+str(site))
else:
form = addPartForm()
return render(request, 'myproj/addPart.html', {'form': form, 'SiteNo': Site.objects.get(SiteID = siteselected).SiteID, 'subtype': subtypeselected})
EDIT: had the wrong view, sorry.
EDIT 2: example of what I mean by the highlighted box:
UPDATE:
Jey_Jen's answer has helped me get the style I want. I now have a multiple selection checkbox. But the ConnectedTo attributes do not save. Everything else in the model is saved and a new part is created. But no many to many links.
I would suggest looking into django form widgets. you can override the default widget to be a whatever you want. you can view them here.
heres a small example the django docs give:
class CommentForm(forms.Form):
name = forms.CharField()
url = forms.URLField()
comment = forms.CharField(widget=forms.Textarea)

Confused about how is_valid works

I have a view which validates data from a form which just has some basic information about an item. I'm confused with how the is_valid method works here even after reading
this . If the user doesn't input some of the required fields like name or image 1, I want them to see the error on the page "this field is required" or something of that nature. I thought if the form.is_valid returned False, these messages would automatically be raised on the page for the user. Or do I need to specify what error message for each field somewhere that I would want the user see?
#view
def sell(request):
if request.method == "POST":
form = AddItem(request.POST, request.FILES)
if form.is_valid():
item = form.save(commit=False)
item.user = request.user
item.is_active = True
item.slug = slugify(item.name)
item.save()
return HttpResponseRedirect('thanks.html')
else:
form = AddItem()
return render_to_response('forsale.html', locals(), context_instance=RequestContext(request))
#form
class AddItem(forms.ModelForm):
name = forms.CharField(label="Title")
class Meta:
model = Item
exclude = ('user','slug','is_active',)
#model
class Item(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=75)
slug = models.SlugField(max_length=50, unique=True)
is_active = models.BooleanField(default=True, blank=True)
image1 = models.ImageField(upload_to='img')
image2 = models.ImageField(upload_to='img', blank=True)
image3 = models.ImageField(upload_to='img', blank=True)
image_caption1 = models.CharField(max_length=200, blank=True)
image_caption2 = models.CharField(max_length=200, blank=True)
image_caption3 = models.CharField(max_length=200, blank=True)
price = models.DecimalField(max_digits=8, decimal_places=2)
quantity = models.IntegerField(default=1)
description = models.TextField()
created = models.DateTimeField(auto_now_add=True)
shipping_price = models.DecimalField(decimal_places=2, max_digits=6)
categories = models.ManyToManyField(Category)
You need to extract the errors from the form object using form.errors then deal with the dict however you want. If you're using ajax, simply send the dict as json back over and use javascript to handle it. If it was a direct html form submit, then you need to render and respond with a page with the errors in the passed dictionary and deal with the passed error in the template (usually with an {% if errors %} tag

Categories

Resources