Django Modelform - setting field value to foreign key - python

I created two models in my app: "Prescription" and "Prescription_status." When a user clicks save on the "New_prescription" modelform, I need to add a "Prescription_status" to the "Prescription."
For example, below I'd like to add 'Draft' status (PK=1). I don't want to set a default status. I've been trying everything, what am I missing?? Thanks in advance!
models.py
# Static Prescription Status Types
class Prescription_status(models.Model):
status = models.CharField(max_length=200)
status_definition = models.TextField()
def __str__(self):
return '%s' % (self.status)
# Prescription Model
class Prescription(models.Model):
order_id = models.AutoField(primary_key=True, unique=True)
status = models.ForeignKey(Prescription_status, models.SET_NULL, null=True)
I saved the following Prescription_status objects to the database, which I'd like to reference as users save or edit prescriptions:
status_id for "Draft" status = 1
status_id for "Ready for Signing" status = 2
status_id for "Signed and Authorized" status = 3
database chart showing PK for each status
forms.py
class PrescriptionForm(forms.ModelForm):
class Meta:
model = Prescription
fields = ('medication', 'quantity', 'directions', 'refills', 'earliest_permitted_fill_date', 'daw',)
widgets = {
'earliest_permitted_fill_date': DatePickerInput(), # default date-format %m/%d/%Y will be used
}
views.py
def new_rx(request):
if request.method == "POST":
form = PrescriptionForm(request.POST)
if form.is_valid():
prescription = form.save(commit=False)
prescription.status = Prescription_status.objects.get(pk=form.cleaned_data['1'])
prescription.save()
return redirect('home')
else:
form = PrescriptionForm()
return render(request, 'app/new_rx.html', {'form': form})
The above results in "NameError: name 'Prescription_status' is not defined." What is the right way to do this?

Related

Failure to save certain attributes from ModelForm to django database (Logic error)

I have a ModelForm called ListingForm. It takes data from a user but I have stopped some of the model attributes from appearing in this form as I want to feed data to those myself. I have put print statements in my createlisting function in views.py to inspect if the data is actually being saved correctltly, it turns out the data is being saved. Here is the createlisting function:
def create_listing(request):
if request.method == 'POST':
import datetime
listing_form = ListingForm(request.POST, request.FILES)
if listing_form.is_valid():
bid = listing_form.cleaned_data['starting_bid']
print(bid)
listing_form.save(commit=False)
listing_form.user = request.user
print(listing_form.user)
listing_form.date_made = datetime.datetime.today()
listing_form.is_active = True
listing_form.category = Category.objects.get(name=listing_form.cleaned_data['listing_category'])
print(listing_form.category)
#The form is being saved correctly here, and the print statements give the correct results in my terminal
listing_form.save()
Bid.objects.create(user= request.user, value=bid, listing=listing_form.instance)
all_listings = Listing.objects.all()
return render(request, 'auctions/index.html', {
'all_listings': all_listings })
else:
listing_form = ListingForm()
return render(request, 'auctions/createlisting.html',{
'listing_form':listing_form
})
However, when I try to access the data from the model Listing from which the ListingForm is inheriting, the print statements I have put for debugging return the default values for certain fields (category and user) instead of the values I have saved in the ListingForm.
Here is the code that allows me to view the data for the model instance I have created. Mind you, all the other fields have saved correctly except for the fields category and user:
def view_listing(request, listing_id):
listing = Listing.objects.get(pk=listing_id)
#the print results return the default values for the fields category and user instead of the values I saved in my ModelForm
print(listing.category)
print(listing.user)
if request.user == listing.user:
return render(request, 'auctions/view_listing.html', {
'listing': listing,
'flag':True,
'count': listing.bids.all().count()
})
else:
return render(request, 'auctions/view_listing.html',{
'listing':listing,
'count': listing.bids.all().count()
})
What could be the problem with my code?
Also, let me provide the code for some of my models and a form as the error might be embedded in those:
Listing Model:
class Listing(models.Model):
NAME_CHOICES = [
('Fashion', 'Fashion'),
('Toys','Toys'),
('Electronics','Electronics'),
('Home', 'Home'),
('Other', 'Other')
]
title = models.CharField(max_length= 64)
date_made = models.DateTimeField(auto_now_add=True)
description = models.TextField()
user = models.ForeignKey(User, to_field='username', on_delete=models.CASCADE, related_name='user_listings', null=True)
starting_bid = models.DecimalField(decimal_places=2, max_digits=264, default=10.00)
upload_image = models.ImageField(blank=True, upload_to='media/media')
category = models.ForeignKey(Category, on_delete=models.CASCADE, to_field='name', related_name='category_listings', default=NAME_CHOICES[4][0], db_constraint=False)
listing_category = models.CharField(max_length=12, choices=NAME_CHOICES, null=True, default=NAME_CHOICES[4][0])
is_active = models.BooleanField(default=True)
watchlist = models.ForeignKey('Watchlist', on_delete=models.DO_NOTHING, related_name='listings', null=True)
Category Model:
class Category(models.Model):
NAME_CHOICES = [
('Fashion', 'Fashion'),
('Toys','Toys'),
('Electronics','Electronics'),
('Home', 'Home'),
('Other', 'Other')
]
name = models.CharField(max_length=12, choices= NAME_CHOICES, unique=True)
User Model:
class User(AbstractUser):
def __str__(self):
return f'{self.username} '
ListingForm`` (ModelForm```):
class ListingForm(ModelForm):
class Meta:
model = Listing
exclude = [
'date_made',
'user',
'category',
'is_active',
'watchlist'
]
Any form of help would be greatly appreciated.
When you call listing_form.save(commit=False) it returns an unsaved model instance with the submitted values. If you assign that to a variable, you can use it to set the other field values and save:
def create_listing(request):
if request.method == 'POST':
import datetime
listing_form = ListingForm(request.POST, request.FILES)
if listing_form.is_valid():
bid = listing_form.cleaned_data['starting_bid']
listing = listing_form.save(commit=False)
listing.user = request.user
listing.date_made = datetime.datetime.today()
listing.is_active = True
listing.category = Category.objects.get(name=listing_form.cleaned_data['listing_category'])
listing.save()
Bid.objects.create(user=request.user, value=bid, listing=listing)
# You should probably use HttpResponseRedirect to an `all_listings` page, rather than displaying them here
all_listings = Listing.objects.all()
return render(request, 'auctions/index.html', {
'all_listings': all_listings })
Here's a link to the ModelForm.save() docs.

Django is not populating correctly an specific form using a Queryset

I have created two models Leads and Deals, and I have coded some logic such that if you click a button the Lead becomes a Deal, so what I want it is that a new form is presented to the user but that form already contains the information from the Leads model.
#login_required
def close_lead(request):
if request.method == 'POST':
deal_form = DealForm(request.POST)
if deal_form.is_valid():
deal_form.save()
messages.success(request, 'You have successfully updated the status from open to Close')
id = request.GET.get('project_id', '')
obj = Leads.objects.get(project_id=id)
obj.status = "Closed"
obj.save(update_fields=['status'])
return HttpResponseRedirect(reverse('dashboard'))
else:
messages.error(request, 'Error updating your Form')
else:
id = request.GET.get('project_id', '')
obj = get_object_or_404(Leads, project_id=id)
print(obj.expected_revenue)
form = NewDealForm(request.POST or None, instance=obj)
return render(request,
"account/close_lead.html",
{'form':form})
I have done some debug and printed to the console the queryset and the information is fine, so the queryset is no the problem, the problem is that the NewForm doesn't prepopulate the new values.
models.py (only 2 models shown)
class Leads(models.Model):
CHOICES = (
('Illumination Studies','Illumination Studies'),
('Training','Training'),
('Survey Design','Survey Design'),
('Software License','Software License')
)
STATUS = (('Open','Open'),
('Closed','Closed'),
('Canceled', 'Canceled')
)
project_id = models.BigAutoField(primary_key=True)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
agent = models.ForeignKey(Profile, on_delete=models.CASCADE, default="agent")
created_at = models.DateTimeField(auto_now_add=True)
point_of_contact = models.ForeignKey(Client, on_delete=models.CASCADE)
expected_revenue = MoneyField(max_digits=14, decimal_places=2, default_currency='USD')
expected_licenses = models.IntegerField(blank=True)
country = CountryField(blank_label='(select country)')
status = models.CharField(max_length=10,choices=STATUS)
estimated_closing_date = models.DateField(blank=True)
services = models.CharField(max_length=20,choices=CHOICES)
def __str__(self):
return f'{self.company}'
class Deal(models.Model):
project_id = models.ForeignKey(Leads, on_delete=models.CASCADE, default='id')
agent = models.ForeignKey(Profile, on_delete=models.CASCADE, default="agent")
service = models.ForeignKey(Leads, on_delete=models.CASCADE, related_name='service')
closing_date = models.DateField(auto_now_add=True)
client = models.ForeignKey(Client, on_delete=models.CASCADE,default='client')
licenses = models.ForeignKey(Leads,on_delete=models.CASCADE, related_name='licenses')
revenue = MoneyField(max_digits=14, decimal_places=2, default_currency='USD')
comments = models.TextField(blank=True,null=True)
Now, it could be that I have to inherit from a different form?
forms.py (only NewDealForm)
class NewDealForm(forms.ModelForm):
class Meta:
model = Deal
fields = ['agent','client','project_id','service', 'licenses','revenue', 'comments']
Obviously, worst-case scenario is to create a dictionary to extract the data from the queryset and then pass it to the form, but I'm sure Django has a more elegant way to handle this process.
Well, I guess sometimes Stack Overflow pushes you to solve your own issues, this is the solution.
Essentially, the initial=queryset value was not initializing the form mainly because I have very specific relationships in my model, so what I did is to create a dictionary (key:value) with the form field as key, and my queryset from my model as the value, the code is as below:
'''
def close_lead(request):
if request.method == 'POST':
deal_form = DealForm(request.POST)
if deal_form.is_valid():
deal_form.save()
messages.success(request, 'You have successfully updated the status from open to Close')
id = request.GET.get('project_id', '')
obj = Leads.objects.get(project_id=id)
obj.status = "Closed"
obj.save(update_fields=['status'])
return HttpResponseRedirect(reverse('dashboard'))
else:
messages.error(request, 'Error updating your Form')
else:
id = request.GET.get('project_id', '')
obj = get_object_or_404(Leads, project_id=id)
m = obj.__dict__
keys = Leads.objects.get(project_id=m['project_id'])
form_dict = {'project_id':keys.project_id,
'agent':keys.agent,
'client':keys.point_of_contact,
'company':keys.company,
'service':keys.services
}
form = NewDealForm(request.POST or None,initial = form_dict)
return render(request,
"account/close_lead.html",
{'form':form})
'''
As you can see, I create an object dictionary because the forms are different, so they share some common values not all, and then I simply adapt the dictionary, nice and easy, but I somehow expected that Django somehow finds relationships by name?, but maybe the batteries are not included for this.

Django related model not updating on form submission

How do I update a non existing related object through Django model forms ?
I have two objects: Participant and Emergency. Emergency is a child of participant like if run the query: participant = ParticipantInfo.objects.get(pk = prk) I can access emergency = participant.emergency.
I cannot update emergency with data from a form using a POST request.
Can anyone help me please.
Thanks
Here's my models.py for clarity.
models.py
class EmergencyInfo(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
phone_number = models.CharField(max_length=50)
email = models.EmailField(max_length=100, blank=True, verbose_name="Emergency Contact Email")
relationship = models.CharField(max_length=100)
class ParticipantInfo(models.Model):
first_name = models.CharField(max_length=100)
middle_initial = models.CharField(max_length=1, blank=True)
emergency = models.ForeignKey(EmergencyInfo, on_delete = models.CASCADE, editable= False, null=True, blank=True)
views.py
def update_participant(request, pk):
# this function comes after update_specific
if request.method == "GET":
forms = get_participant_form_data(pk)
context = {'forms': forms, 'pk': pk}
return render(request, 'core/participantinfo_update_form.html', context)
if request.method == "POST":
return update_specific_form(request, pk)
def update_specific_form(request, pk):
participant = ParticipantInfo.objects.get(pk = pk)
# if the object didn't exist create it like normal
if participant.emergency is None:
emergencyform =EmergencyForm(request.POST)
if (emergencyform.is_valid):
emergencyform.save()
messages.success(request, 'saved')
return redirect(request.path_info)
# if the object exists, update it
if participant.emergency is not None:
emergencyform = EmergencyForm(request.POST, instance = participant.emergency)
if (emergencyform.is_valid):
emergencyform.save()
messages.success(request, 'saved')
return redirect(request.path_info)
Your problem seems to be with the is_valid method. Replace it with is_valid(). So your lines would be:
if (emergencyform.is_valid()):
#code
I have found an answer. Not only I needed to call the is_valid() instead of is_valid
but I also needed to tie the created object with it's parent like:
Save the new child object
Save the parent objects (updates the null
foreign key to a value)
*#get the existing parent object*
participant = ParticipantInfo.objects.get(pk = pk)
*#if no child object exists*
if participant.emergency is None:
emergencyform =EmergencyForm(request.POST)
if (emergencyform.is_valid()):
emergency = emergencyform.save(commit=False)
participant.emergency = emergency
emergencyform.save()
participant.save()
messages.success(request, 'saved')
return redirect(request.path_info)

Unable to find newly saved instances in database

I'm making a stock portfolio app as a personal project. I have a form StockSymbolForm used for buying stocks. It has the fields: username, stock_symbol, and stock_qty.
I've set username to be the current user that's currently using the app - so they only need to fill stock_symbol and stock_qty.
After a valid form is submitted, I go to my admin page to check, but I don't see my new stock_symbol and stock_qty added to my model.
Here's my code:
views.py:
class PortfolioStockListView(ListView):
model = StockPortfolio
template_name = 'stocks.html'
def post(self, request):
current_user = StockPortfolioUser.objects.filter(username=request.user).first()
if request.method == 'POST':
symbol_form = StockSymbolForm(request.POST, initial={'username': current_user})
if symbol_form.is_valid():
symbol_form = StockSymbolForm(request.POST, instance=current_user)
model_instance = symbol_form.save(commit=True)
model_instance.timestamp = timezone.now()
model_instance.save()
return redirect('/')
else:
return render(request, 'stocks.html', {'symbol_form': symbol_form})
else:
symbol_form = StockSymbolForm()
return render(request, 'stocks.html', {'symbol_form': symbol_form})
models.py:
class StockPortfolioUser(models.Model):
username = models.OneToOneField(User, on_delete=models.CASCADE)
usercash = models.PositiveIntegerField(default=100000)
class StockPortfolio(models.Model):
username = models.ForeignKey(StockPortfolioUser, on_delete=models.CASCADE)
stock_symbol = models.CharField(max_length=5)
stock_qty = models.PositiveIntegerField(default=0)
forms.py:
class StockSymbolForm(ModelForm):
class Meta:
model = StockPortfolio
fields = ('stock_symbol' , 'stock_qty')
labels = {'stock_symbol': 'Stock Symbol', 'stock_qty': 'Quantity'}
How do I save the model instance properly? and why is it not saving at the moment?
In your views.py file change this
model_instance = symbol_form.save(commit=False)
model_instance.username = request.user.id
model_instance.timestamp = timezone.now()
model_instance.save()
In StockSymbolForm change this
fields = ('username', 'stock_symbol' , 'stock_qty')
Well, you don't ever seem to be setting the username. You set a timestamp, which doesn't exist as a field, but not the actual username field.
model_instance = symbol_form.save(commit=True)
model_instance.userame = request.user
model_instance.save()
As an aside, that field should be called user, as it points to the whole User object not just the username.

Dynamically alter form fields in views.py file of django

I was wondering if there is a way that I can alter a model form within the views.py file to create a multiple choice dropdown field for form choices. I want to set each option on the choice field from the results of a queryset.
for example:
I want to from_acct field to have a scroll down option with the following list..
wells fargo
chase
tabz
bank of america
the list of banks are results of a query set
Here is what i have so far in the views.py file.
form = TransferForm()
form.fields['from_acct'].queryset = Accounts.objects.filter(user = currentUser).all()
message = 'please fill out the below form'
parameters = {
'form':form,
'currentUser':currentUser,
'message':message,
}
return render(request, 'tabs/user_balance.html', parameters)
here is the forms.py file
class TransferForm(forms.ModelForm):
class Meta:
model = Transfers
fields = ['from_acct', 'to_acct', 'amount', 'memo']
labels = {
'from_acct':'from',
'to_acct':'to',
}
here is the model.py file
class Transfers(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
from_acct = models.CharField(max_length=150, default='account')
to_acct = models.CharField(max_length=150, default='accont')
amount = models.DecimalField(decimal_places=2, max_digits=9, default=0)
memo = models.CharField(max_length=200, default='memo')
frequency = models.SmallIntegerField(default=1)
status = models.SmallIntegerField(default=1)
create = models.DateTimeField(auto_now_add=True)
You can try to set choices arg for CharField by function.
Like that:
class Transfers(models.Model):
field = models.CharField(max_length=255, choices=result_query())
def result_query(self):
# you can use that with self if u need transfers.pk for querying
return Something.objects.exclude(bank_id__in=[bank.id for bank in self.banks.all())
def result_query():
# or there if not
return Something.objects.filter(any_field__gte=123)
For sure, you can realize any logic in the function, so you can dynamically change options for char field.
UPDATE:
Sure, u haven't pass request into the function.
That should be like that:
view.py:
def my_view(request):
if request.method == 'GET':
form = TransferForm(user=request.user)
...
return something here
forms.py
class TransferForm(ModelForm):
class Meta:
model = Transfer
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(TransferForm, self).__init__(*args, **kwargs)
self.fields['accounts'].choices = Accounts.objects.filter(user = currentUser).all()

Categories