I'm having trouble saving my form to a model that has two foreign keys:
- User who is submitting the form
- The current price of the Crypto submitted.
The form values seem to through the AssetView but not being saved. Could anyone help to why they aren't saving. I've provided Models, Views, Form, HTML.
Django Models
from django.contrib.auth.models import User
class CryptoPrices(models.Model):
symbol = models.CharField(max_length=20)
current_price = models.FloatField(default=0.0)
class CryptoAssets(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
symbol = models.CharField(max_length=20)
amount = models.FloatField(default=0.0)
purchase_price = models.FloatField(default=0.0)
crypto_prices = models.ForeignKey(CryptoPrices, on_delete=models.CASCADE)
Django View
from coinprices.forms import AssetForm
class AssetView(TemplateView):
template_name = 'coinprices/my-dashboard.html'
def get(self, request):
form_a = AssetForm(prefix='form_a')
return render(request, self.template_name, {'form_a': form_a})
def post(self, request):
form_a = AssetForm(request.POST, prefix='form_a')
if form_a.is_valid():
post = form_a.cleaned_data
post.save()
form = AssetForm()
args = {'form': form}
return render(request, self.template_name, args)
args = {'form_a': form_a}
return render(request, self.template_name, args)
Django Form
from coinprices.models import CryptoPrices
tickers = (('BTC', 'BTC'), ('ETH', 'ETH'))
class AssetForm(forms.ModelForm):
symbol = forms.ChoiceField(choices=tickers, required=True, label='')
amount = forms.DecimalField(decimal_places=2, max_digits=20, required=True, label='')
purchase_price = forms.DecimalField(decimal_places=2, max_digits=20, required=True, label='')
class Meta:
model = CryptoAssets
fields = (
'symbol',
'amount',
'purchase_price'
)
HTML
{% extends 'base.html' %}
{% block head %}
<title>My Dashboard</title>
{% endblock %}
{% block body %}
<br>
<div >
<h1>My Dashboard</h1>
<p>
<form method="post">
{% csrf_token %}
{{ form_a.as_p }}
<button type="submit">Submit</button>
</form>
</p>
</div>
{% endblock %}
Errors
AttributeError: 'dict' object has no attribute 'save'
CodePudding user response:
let me explain you the errors:
AttributeError: 'dict' object has no attribute 'save'
This error happens because you are trying yo save this way:
post = form_a.cleaned_data
post.save()
That is wrong because cleaned_data is a dict, it contains the values of your form as a fieldname:value pairs.
The correct way is:
post = form_a.save()
The next error says that value of field crypto_prices is required but you are passing a null value.
django.db.utils.IntegrityError: null value in column "crypto_prices_id" of relation "coinprices_cryptoassets" violates not-null constraint
This happens because in your form AssetForm you are selecting only this fields:
fields = (
'symbol',
'amount',
'purchase_price'
)
Where is crypto_prices? The field is defined as required in your models.py in this line:
crypto_prices = models.ForeignKey(CryptoPrices, on_delete=models.CASCADE)
The solution: you need to include the field 'crypto_prices' in your forms or set it before save the form in AssetView. As this:
class AssetForm(forms.ModelForm):
symbol = forms.ChoiceField(choices=tickers, required=True, label='')
amount = forms.DecimalField(decimal_places=2, max_digits=20, required=True, label='')
purchase_price = forms.DecimalField(decimal_places=2, max_digits=20, required=True, label='')
class Meta:
model = CryptoAssets
fields = (
'symbol',
'amount',
'purchase_price',
'crypto_prices'
)
Or this way:
class AssetView(TemplateView):
template_name = 'coinprices/my-dashboard.html'
def get(self, request):
form_a = AssetForm(prefix='form_a')
return render(request, self.template_name, {'form_a': form_a})
def post(self, request):
form_a = AssetForm(request.POST, prefix='form_a')
if form_a.is_valid():
post = form_a.save(commit=False)
post.crypto_prices = CryptoPrices.objects.get(id=someid) # this way with object
post.crypto_prices_id = 1 # or this way with a integer
post.save()
form = AssetForm()
args = {'form': form}
return render(request, self.template_name, args)
args = {'form_a': form_a}
return render(request, self.template_name, args)