How to save foreign key data using forms.py? - python

urls.py
...
path('restaurant/menu/', r_view.Menu, name='menu'),
...
menu.html
<form method="POST" id="menuForm" autocomplete="off" action="" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-inline">
<div class="form-group mb-4">
{{ form.item|as_crispy_field }}
</div>
<div class="form-group mb-4">
{{ form.itemImage|as_crispy_field }}
</div>
<div class="form-group mb-4">
{{ form.price|as_crispy_field }}
</div>
<div class="form-group mb-4">
{{ form.category|as_crispy_field }}
</div>
</div>
<button type="submit" class="col-md-12 myBtn">Submit</button>
</form>
views.py
def Menu(request, restaurantID):
restaurant = get_object_or_404(Restaurant_Account, restaurantID=restaurantID)
form = MenuForm()
if request.method == 'POST':
form = MenuForm(request.POST, request.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.restaurant = restaurant
instance.save()
messages.success(request, "Saved successfully!")
return redirect('r_index')
context = {'form':form}
return render(request, 'restaurant/menu.html', context)
forms.py
class MenuForm(forms.ModelForm):
restaurantID = Restaurant_Account.objects.filter(restaurantID='restaurantID')
item = forms.CharField(required=True)
itemImage = forms.ImageField(required=False, label='Item image')
price = forms.DecimalField(required=True)
category = forms.ChoiceField(choices=CATEGORY)
class Meta:
model = Menu
fields = ('item', 'itemImage', 'price', 'category')
models.py
class Restaurant(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
is_restaurant = models.BooleanField(default=True)
restaurantID = models.AutoField(primary_key=True)
name = models.CharField(max_length=200)
isActive = models.BooleanField(default=True)
image = models.ImageField(upload_to='images/', blank=True)
website = models.URLField(blank=True, unique=False)
country = models.CharField(max_length=50)
def __str__(self):
return self.user.username
class Menu(models.Model):
menuID = models.AutoField(primary_key=True)
restaurantID = models.ForeignKey(Restaurant_Account, on_delete=models.CASCADE, default=None)
item = models.CharField(max_length=100)
itemImage = models.ImageField(upload_to='images/', blank=True)
price = models.DecimalField(max_digits=6, decimal_places=2)
category = models.CharField(
max_length=20,
choices=[('', 'Choose category'),('Appetizer', 'Appetizer'),('Entree', 'Entree'),('Drink', 'Drink'),('Dessert', 'Dessert'), ('Side', 'Side')])
def __str__(self):
return self.item
I'm new to Django.
I made a form for saving menu data. If the user fills the form and click the submit button every data should be saved in the Menu table. I have no idea how to save restaurantID, which is a foreign key that refers to the Restaurant table, automatically. (By automatically I mean without the user entering input) Can somebody help me with this?

You haven't need to do all these things, if you have made restaurantID a foreign key while defining the model that is Menu, django itself handles it.
Below code might work for you:
forms.py
class MenuForm(forms.ModelForm):
item = forms.CharField(required=True)
itemImage = forms.ImageField(required=False, label='Item image')
price = forms.DecimalField(required=True)
category = forms.ChoiceField(choices=CATEGORY)
class Meta:
model = Menu
fields = ('item', 'itemImage', 'price', 'category')
views.py
def menu(request):
if request.method == 'POST':
form = MenuForm(request.POST, request.FILES)
if form.is_valid():
form.save()
messages.success(request, "Saved successfully!")
return redirect('r_index')
else:
form=MenuForm()
return render(request, 'restaurant/menu.html', {'form':form})
optional: You also don't need to write this line menuID = models.AutoField(primary_key=True) in Menu model, as django makes id column by default for AutoField.
Update:
Make your models.py in this way:
MY_CHOICES=[
('', 'Choose category'),
('Appetizer', 'Appetizer'),
('Entree', 'Entree'),
('Drink', 'Drink'),
('Dessert', 'Dessert'),
('Side', 'Side')
]
class Restaurant(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
is_restaurant = models.BooleanField(default=True)
name = models.CharField(max_length=200)
isActive = models.BooleanField(default=True)
image = models.ImageField(upload_to='images/', blank=True)
website = models.URLField(blank=True, unique=False)
country = models.CharField(max_length=50)
def __str__(self):
return self.user.username
class Menu(models.Model):
restaurant= models.ForeignKey(Restaurant, on_delete=models.CASCADE, default=None)
item = models.CharField(max_length=100)
itemImage = models.ImageField(upload_to='images/', blank=True)
price = models.DecimalField(max_digits=6, decimal_places=2)
category = models.CharField(
max_length=20,
choices=MY_CHOICES)
def __str__(self):
return self.item
Remove your AutoField, django by default make id which is primary key.
Don't forget to run makemigrations and migrate, after doing this, if it still gives error, so comment your all models and then run.

Related

NOT NULL constraint failed: tickets_ticket.name

I am creating a ticket app in my django project. When I try to create a ticket the NOT NULL constraint failed: tickets_ticket.name error shows up. I'm not sure why the value for ticket.name field won't pass correctly. How do I proceed? any help is much appreciated.
Here's what i have so far
models.py
class Category(models.Model):
name = models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
class Ticket(models.Model):
STATUS = (
(True, 'Open'),
(False, 'Closed')
)
PRIORITIES = (
('None', 'None'),
('Low', 'Low'),
('Medium', 'Medium'),
('High', 'High')
)
TYPE = (
('Misc', 'Misc'),
('Bug', 'Bug'),
('Help Needed', 'Help Needed'),
('Concern', 'Concern'),
('Question', 'Question')
)
host = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True, related_name='host')
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='category')
name = models.CharField(max_length=200, null=True)
status = models.BooleanField(choices=STATUS, default=True)
priority = models.TextField(choices=PRIORITIES, default='None', max_length=10)
type = models.TextField(choices=TYPE, default='Misc', max_length=15)
description = RichTextField(null=True, blank=True)
# description = models.TextField(null=True, blank=True)
participants = models.ManyToManyField(CustomUser, related_name='participants', blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-updated', '-created']
def __str__(self):
return self.name
views.py
view for creating a ticket
def createTicket(request):
form = TicketForm()
categories = Category.objects.all()
if request.method == 'POST':
category_name = request.POST.get('category')
category, created = Category.objects.get_or_create(name=category_name)
ticket = Ticket.objects.create(
host = request.user,
category=category,
name=request.POST.get('name'),
status=request.POST.get('status'),
priority=request.POST.get('priority'),
type=request.POST.get('type'),
description=request.POST.get('description'),
)
return redirect('ticket', pk=ticket.id)
context = {'form': form, 'categories': categories}
return render(request, 'projects/ticket_form.html', context)
view for ticket page
def ticket(request, pk):
ticket = Ticket.objects.get(id=pk)
ticket_messages = ticket.message_set.all()
participants = ticket.participants.all()
if request.method == 'POST':
message = Message.objects.create(
user=request.user,
ticket=ticket,
body=request.POST.get('body')
)
ticket.participants.add(request.user)
return redirect('ticket', pk=ticket.id)
context = {'ticket': ticket, 'ticket_messages': ticket_messages,
'participants': participants}
return render(request, 'projects/ticket.html', context)
here is part of the template for the ticket page
<div class="main-column">
<form action="" method="POST">
{% csrf_token %}
<div class="form__group">
<label for="ticket_name">Ticket Name</label>
{{form.name}}
</div>
<div class="form__group">
<label for="ticket_description">Ticket Description</label>
{{form.description}}
</div>
</form>
</div>
ticket form
class TicketForm(ModelForm):
description = forms.CharField(widget = CKEditorWidget())
class Meta:
model = Ticket
fields = '__all__'
exclude = ['host', 'participants']

How to compare data from two models in Modelform Django

I'm creating an ebay like auction site where users can bid on an item they like and if the bid is higher than the last bid, the bid amount displayed would update to the newest bid.
I want to run validation on the modelform to compare the first amount (that the person that created the listing) inputted with the last bid (that the new user inputted).
The problem is that they are in two different models and I'm not sure how to validate both without an error
FORMS.PY
class BidForm(forms.ModelForm):
class Meta:
model = Bids
fields = ['new_bid']
labels = {
'new_bid': ('Bid'),
}
def clean_new_bid(self):
new_bid = self.cleaned_data['new_bid']
current_bid = self.cleaned_data['current_bid']
if new_bid <= current_bid:
error = ValidationError("New bid must be greater than the previous bid")
self.add_error('new_bid', error)
return new_bid
MODELS.PY
class Auction(models.Model):
title = models.CharField(max_length=25)
description = models.TextField()
current_bid = models.IntegerField(null=False, blank=False)
image_url = models.URLField(verbose_name="URL", max_length=255, unique=True, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey(Category, max_length=12, null=True, blank=True, on_delete=models.CASCADE)
is_active = models.BooleanField(default=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
class Meta:
ordering = ['-created_at']
class Bids(models.Model):
auction = models.ForeignKey(Auction, on_delete=models.CASCADE, related_name='bidding', null=True)
user = models.ForeignKey(User, on_delete=models.PROTECT, related_name='bidding')
new_bid = models.IntegerField()
done_at = models.DateTimeField(auto_now_add=True)
VIEWS.PY
#login_required
def make_bid(request, listing_id):
auction = Auction.objects.get(pk=listing_id)
user = request.user
if request.method == 'POST':
bid_form = BidForm(request.POST)
if bid_form.is_valid():
new_bid = request.POST['new_bid']
current_price = Bids.objects.create(
listing_id = listing_id,
user = user,
new_bid = new_bid
)
messages.success(request, 'Successfully added your bid')
return HttpResponseRedirect(reverse("listing_detail", args=(listing_id,)))
else:
bid_form = BidForm(request.POST)
return render(request, 'auctions/details.html', {"bid_form": bid_form})
return render(request, 'auctions/details.html', bid_form = BidForm())
DETAILS.HTML
<p>{{ detail.description }}</p>
<hr>
<p>Current price: ${{detail.current_price}}</p>
<form action="{% url 'make_bid' detail.id %}" method="post">
{% csrf_token %}
{{ form.non_field_errors }}
{{ form.errors }}
{{ bid_form }}
<input type="submit" class="btn btn-primary btn-block mt-3" value="Place bid">
</form>
I'm having this error
KeyError at /make_bid/2
'current_bid'
Request Method:
POST
Request URL:
http://127.0.0.1:8000/make_bid/2
I'm sure its because I'm trying to compare two different models, but don't know a better way to do this. Could you please direct me or is there a better way to run this bid validation process?

Drop down field shows values of all users

I have a form field in Django called Label. My problem is that the field shows the Labels of all users while I only want to show self created labels.
models
class Label(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
tag = models.CharField(max_length=25)
def __str__(self):
return self.tag
class Birthday(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=25, default="")
day = models.DateField()
label = models.ForeignKey(Label, on_delete=models.SET_NULL, default=0, null=True, blank=True)
def __str__(self):
return self.name
forms
class BirthdayForm(forms.ModelForm):
class Meta:
model = Birthday
fields = ('name', 'day', 'label')
class LabelForm(forms.ModelForm):
class Meta:
model = Label
fields = ('tag',)
template
<form method="POST">{% csrf_token %}
<table border="0">
{{ form }}
</table>
<button class="submitButton" type="submit">Submit</button>
</form>
This is the view for this template
view
#login_required
def index(request):
if request.method == "POST":
form = BirthdayForm(request.POST)
if form.is_valid():
birthday = form.save(commit=False)
birthday.user = request.user
birthday.save()
return redirect('index')
else:
#default_labels("Friend", request)
#default_labels("Family", request)
form = BirthdayForm()
birthday = Birthday.objects.filter(user=request.user)
username = request.user
return render(request, 'bd_calendar/index.html', {'form': form, 'birthday': birthday, 'username': username })

Additional help text to form in Django

When I create or edit model CV, I need to input some data in birth_date field. It's working, but I want to add some additional text to define some date format like (yyyy-mm-dd). I'm using cripsy forms for better look of forms. How can I add this help text ?
my code:
template.html
{% block profile %}
<div class="jumbotron">
<h2>Edit your basic informations</h2>
<hr>
<form method="POST" class="post-form" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="save btn btn-default">Save</button>
</form>
</div>
{% endblock %}
models.py
class Cv(models.Model):
author = models.ForeignKey('auth.User')
name = models.CharField(max_length=25, null = True)
surname = models.CharField(max_length=25, null = True)
city = models.CharField(max_length=100, blank=True)
birth_date = models.DateField(blank=True, null=True)
email = models.EmailField(max_length=50, null=True)
main_programming_language = models.CharField(max_length=15, null = True)
specialization = models.CharField(max_length=30, blank=True, null=True)
interests = models.TextField(blank=True, null=True)
summary = models.TextField(blank=True, null=True)
#thumbnail = models.FileField(upload_to=get_upload_file_name, blank=True)
#property
def age(self):
return int((datetime.datetime.now().date() - self.birth_date).days / 365.25 )
def zapisz(self):
self.save()
def __str__(self):
return self.surname.encode('utf-8')
forms.py
class CvForm(forms.ModelForm):
class Meta:
model = Cv
fields = ('name', 'surname', 'city', 'birth_date', 'email', 'main_programming_language', 'specialization', 'interests', 'summary',)
views.py
#login_required
def new_cv(request):
if request.method == "POST":
form = CvForm(request.POST, request.FILES)
if form.is_valid():
cv = form.save(commit=False)
cv.author = request.user
cv.save()
return redirect('proj.views.cv_detail', pk=cv.pk)
else:
form = CvForm()
return render(request, 'new_cv.html', {'form': form})
Can add help_text to your model fields:
birth_date = models.DateField(blank=True, null=True, help_text="format (yyyy-mm-dd)")
see more Django Model and Form docs.
You can also use external library JQuery Tooltip too.

ImageField() not saving images in ModelForm - Django/Python

When I try to upload a picture from my form, everything processes, but the image is not being saved.
Does anyone know why this is happening?
Thanks ahead of time!
models.py:
class Photo(models.Model):
user = models.ForeignKey(MyUser, null=False, blank=False)
category = models.ForeignKey("Category", default=1, null=True, blank=True)
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=True, blank=True)
active = models.BooleanField(default=True)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False, null=True)
updated = models.DateTimeField(auto_now_add=False, auto_now=True, null=True)
class Meta:
unique_together = ('slug', 'category')
ordering = ['-timestamp']
def __unicode__(self):
return "%s" %(self.user)
views.py:
def photo_upload_view(request, username):
u = MyUser.objects.get(username=username)
if request.method == 'POST':
form = PhotoUploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
messages.success(request, "Thank you! You have successfully posted your picture!")
return HttpResponseRedirect('/')
else:
form = PhotoUploadForm()
submit_btn = "Upload Post"
context = {
"form": form,
"submit_btn": submit_btn
}
return render(request, "photos/photo_upload.html", context)
forms.py:
class PhotoUploadForm(forms.ModelForm):
class Meta:
model = Photo
fields = ('user', 'category', 'title', 'description', 'image')
.html:
<form method='POST' action='{{ action_url }}'>{% csrf_token %}
{{ form|crispy }}
<input class='btn btn-default {{ submit_btn_class }}' type='submit' value='{{ submit_btn }}'/>
</form>
You should add the enctype=multipart/form-data attribute to the <form> tag:
<form method='POST' action='{{ action_url }}' enctype='multipart/form-data'>
except for adding enctype=multipart/form-data, another possible reason that your image is not saving in modelform can be adding request.FILES in your POST condition:
if request.method == 'POST':
form = forms.ProjectCreateForm(request.POST, instance=project)
should be:
if request.method == 'POST':
form = forms.ProjectCreateForm(request.POST, request.FILES, instance=project)
data.profile_pic = request.FILES['profile_pic']
use request.FILES

Categories