Home > database >  Form not saving to model with two Foreign Keys - Django
Form not saving to model with two Foreign Keys - Django

Time:03-15

I'm having trouble saving my form to a model that has two foreign keys:

  1. User who is submitting the form
  2. 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)
  • Related