Model Choice Field - get the id - python

I am busy trying to get the id only in integer format preferably for the ModelChoiceField. I get the list to display but get's returned in a string format. Please helping me in retrieving the id of ModelChoiceField. I think I need to do this in the view.
forms.py
class ProjectForm(forms.ModelForm):
items = forms.ModelChoiceField(queryset=Project.objects.all())
class Meta:
model = Project
fields = ['items']
models.py
class Project(models.Model):
items = models.IntegerField(default=0, blank=True, null=True)
views.py
def ProjectView(request):
form = ProjectForm(request.POST)
if request.method == 'POST':
if form.is_valid():
save_it = form.save(commit=False)
save_it.save()
return HttpResponseRedirect('/')
else:
form = ProjectForm()
return render(request, 't.html', {'form': form })

From what I can tell, items should never be an IntegerField. Your usage has it set up to be a ForeignKey to a Project so you should just make that explicit
items = models.ForeignKey('self', null=True, blank=True)
Possibly with a better descriptive name than items.
Then, you don't need to define anything on the form, it just becomes a standard model form, with a standard model form usage.

Related

how to request and post an object to a foreignkey field

When I do this exactly as provided below, a shipping address object is created without the customer assigned in the shipping address foreignkey field, I can add it from the admin panel manually but I'm not able to make it work through code, idk what I'm doing wrong, please help!
**models.py**
class Customer(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, blank=True, null=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField(max_length=150)
class ShippingAddress(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, blank=True, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, blank=True, null=True)
address_one = models.CharField(max_length=200)
address_two = models.CharField(max_length=200)
...
**views.py**
def checkout(request):
if request.user.is_authenticated:
customer = request.user.customer
order, created = Order.objects.get_or_create(customer=customer, complete=False)
items = order.orderitem_set.all()
else:
items = []
order = {'get_cart_total': 0, 'get_cart_items': 0}
if request.method == 'POST':
form = ShippingForm(request.POST)
if form.is_valid():
#how do I get the customer to get added in the foreignkey field for the shipping address model
form.save()
return redirect('store:checkout_shipping')
else:
form = ShippingForm()
else:
form = ShippingForm()
context = {"items": items, "order": order, "form": form}
return render(request, 'store/checkout.html', context)
In response to your comment #how do I get the customer to get added... etc, in the case that your ShippingForm() points to your ShippingAddress model, or at least something with a customer foreign key field, you may need to do something like this:
def checkout(request):
if request.user.is_authenticated:
customer = request.user.customer
order, created = Order.objects.get_or_create(customer=customer, complete=False)
items = order.orderitem_set.all()
else:
items = []
order = {'get_cart_total': 0, 'get_cart_items': 0}
if request.method == 'POST':
form = ShippingForm(request.POST)
if form.is_valid():
new_shipment = form.save(commit=False)
new_shipment.customer = customer
new_shipment.save()
return redirect('store:checkout_shipping')
else:
form = ShippingForm()
else:
form = ShippingForm()
context = {"items": items, "order": order, "form": form}
return render(request, 'store/checkout.html', context)
Using commit=False on the form.save() will allow you to subsequently modify other fields, in this case, by adding the customer relation, then saving it. More information here in the Django documentation. Salient quote:
This save() method accepts an optional commit keyword argument, which
accepts either True or False. If you call save() with commit=False,
then it will return an object that hasn’t yet been saved to the
database. In this case, it’s up to you to call save() on the resulting
model instance. This is useful if you want to do custom processing on
the object before saving it, or if you want to use one of the
specialized model saving options. commit is True by default.
"Custom processing" in this case is the creation of the foreign key relationship to the model instance (customer).

Select specific option from dropdown menu DJANGO

I have a page that lists all the items from a table named Stocks for each row there's a clickable ORDER button that leads users to another page where they can enter all their details as well as select what item and how much they wanna buy which would then save all of that data to a table named Orders.
This orders table is linked with the Stocks table like this:
class Order(models.Model):
name = models.CharField(max_length=50, blank=True, null=True)
quantity = models.IntegerField(default='0', blank=False, null=True)
order_item = models.ForeignKey(Stock, on_delete=models.CASCADE, blank=True)
address = models.CharField(max_length=50, blank=True, null=True)
city = models.CharField(max_length=50, blank=True, null=True)
Depending on what item they clicked the order button for I wanted to automatically select the corressponding item from the dropdown menu on the next page so that they won't have to.
def create_order(request, pk):
queryset = Stock.objects.get(id=pk)
form = CreateOrderForm(request.POST or None, initial={'order_item':queryset.item_name})
if form.is_valid():
form.save()
context = {
'form':form
}
return render(request, 'add_items.html', context)
I tried doing this by using the intitial command but for some reason it just won't change from the default blank option.
Here's my forms.py just in case
class CreateOrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['name','quantity','order_item','address','city']
Use the Stock object as initial value, so not queryset.item_name, but queryset (although since it is not a queryset, it is better to rename this to stock):
from django.shortcuts import get_object_or_404
def create_order(request, pk):
stock = get_object_or_404(Stock, id=pk)
if request.method == 'POST':
form = CreateOrderForm(request.POST, initial={'order_item': stock})
if form.is_valid():
form.save()
else:
form = CreateOrderForm(initial={'order_item': stock})
context = {
'form':form
}
return render(request, 'add_items.html', context)
Note: It is often better to use get_object_or_404(…) [Django-doc],
then to use .get(…) [Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using
.get(…) will result in a HTTP 500 Server Error.

Decrementing a value in a foreign key model (when creating or updating instances)

I currently have models shown below
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
stock = models.CharField(max_length=200, null=True)
class Order(models.Model):
product = models.ForeignKey(Product, null=True, on_delete = models.SET_NULL)
As you can see the order model has the product model as a foreign key.
When I create or update instances based upon on the order model, I would like to decrement one value from the stock field in the products model.
See below for the my views for both when creating and updating instances.
#login_required
def newOrder(request):
form = CreateOrderForm()
if request.method == 'POST':
form = CreateOrderForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('customer_order_list')
return render(request, 'accounts/new_order.html', {'form': form})
#login_required
def editOrder(request, pk):
order = Order.objects.get(id=pk)
sho = Order.objects.all().values_list('date_created')
order_date = sho.filter(id=pk)
form = CreateOrderForm(instance=order)
if request.method == "POST":
form = CreateOrderForm(request.POST, instance=order)
if form.is_valid():
form.save()
return redirect('customer_order_list')
return render(request, 'accounts/edit_order.html', {'form': form, 'order_date': order_date})
I am aware that using the a similar example below will need to be implemented, however I will have to use the primary key of that particular instance.
with transaction.atomic():
product = (
Product.objects
.select_for_update()
.get(id=1)
)
product.inventory -= 1
product.save()
However this example will not apply for when creating instance based on the order form.
How can one implement this?
If I'm not mistaken, you're trying to update Product.stock when an Order is made. You can use signals for this. For example:
from django.db.models.signals import post_save
#receiver(post_save, sender=Order)
def update_stock(sender, instance, created, **kwargs):
if created:
instance.product.stock = instance.product.stock - 1
instance.product.save()

How to change a field in parent class while creating chiled class fields in forms.py and views.py?

I'm was creating ModelForm I try to make change the parent class while saving child class fields to the database, in the views.py I made but it didn't save to the database.
here is my model.py
class Table(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
book = models.BooleanField(default=False)
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
taple = models.OneToOneField(Table, on_delete=models.CASCADE, null=True, blank=True)
#receiver(post_save, sender=User)
def update_people_profile(sender, instance, created, **kwargs):
try:
instance.people.save()
except ObjectDoesNotExist:
People.objects.create(user=instance)
Class People is the child class and Table is the parent class so I'm using People class for making forms. here is my forms.py
class Booking(forms.ModelForm):
class Meta:
model = People
fields = [
'taple',
]
So I want to make True book field in Table class and save it to the database when saving Booking form. here is my views.py
def booking(request):
if request.method == 'POST':
try:
people_instance = People.objects.get(user=request.user)
except Table.DoesNotExist:
people_instance = People(user=request.user)
form = Booking(request.POST, instance=people_instance)
if form.is_valid():
user = form.save(commit=False)
user.taple.booking = True
user.refresh_from_db()
user.user = request.user
user.taple = form.cleaned_data.get('taple')
user.save()
print(user.taple.booking, user.taple.id)
return redirect('booked')
else:
form = Booking()
return render(request, 'main/booking.html', {'form': form})
Any Idea?
What I understand from the snippets is that you want to be able to record if a table is booked (book Boolean Field in your Table model and if so by whom, which is the object of your People model.
If my understanding is correct, then I don't think you really need a join table (People model). Instead, I would change your model as follow:
class Table(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
booked_by = models.OneToOneField(User, null=True, on_delete=models.SET_NULL, related_name='table_booked')
#property
def is_booked(self):
# This returns True if booked_by is set, False otherwise
return self.booked_by_id is not None
This way you don't need the People model. The property decorator will allow you to use is_booked as a calculated field.
Also, note the related name which will be used in the form:
class BookingForm(forms.ModelForm):
table_booked = forms.ModelChoiceField(queryset=Table.objects.filter(booked_by__isnull=True))
class Meta:
model = User
fields = ['table_booked',]
In the form, you will see that we define a custom queryset for table_booked. THe aim is to filter for free tables only.
Then you can hopefully simplify as well your view as follow:
Update:
As table_booked is a reverse foreign key, we actually need to save the table object which contains the relation. Here is the modified view:
#login_required
def booking(request):
form = BookingForm(request.POST or None, instance=request.user)
if form.is_valid():
user = form.save(commit=False)
tbl = form.cleaned_data['table_booked']
tbl.booked_by = request.user
tbl.save()
user.save()
print(request.user.table_booked.id, request.user.table_booked.is_booked)
return redirect('/')
return render(request, 'booking/booking.html', {'form': form})
Note: I haven't tested the code so there could be some typos but that should help you getting started.

How to use ModelForm to save data from user input forms

I think I am missing a key fundamental of how to use a ModelForm and Forms to save data in my database. I have a UserProfile model that is stores specific data that is not included in the User class
Models.py:
class UserProfile(models.Model):
GRADE_YEAR_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate')
)
school = models.CharField(max_length=64)
grade_year = models.CharField(max_length=2, choices=GRADE_YEAR_CHOICES)
gpa = models.DecimalField(decimal_places=2, max_digits=6, blank=True, null=True)
user = models.ForeignKey(User, unique=True)
My Forms.py looks like:
class UserProfileForm(ModelForm):
class Meta:
model = UserProfile
The View for this looks like:
def more(request):
if request.method == 'POST':
form = UserProfileForm(request.POST)
if form.is_valid():
form = UserProfileForm(request.POST,
school = form.cleaned_data['school'],
grade_year = form.cleaned_data['grade_year'],
gpa = form.cleaned_data['gpa'],
user = form.cleaned_data['user']
)
form.save()
return HttpResponseRedirect('/success')
else:
form = UserProfileForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response('more.html', variables)
The form renders correctly with all of the fields from the model that I specified but when I try to save the data I get:
__init__() got an unexpected keyword argument 'grade_year'
What am I missing here? I realize that I might be missing a big concept so any help would be greatly appreciated.
You are passing UserProfileForm a keyword argument that refers to your model fields which it isn't expecting.
Simply call save() after the form is instantiated - if it had cleaned_data (i.e. the form is valid), then the POSTed fields are already mapped to the instance via ModelForm magic.
if form.is_valid():
form.save()

Categories

Resources