Форма не сохраняется в модели с двумя внешними ключами - Django

У меня проблемы с сохранением формы в модели, которая имеет два внешних ключа:

  1. User who is submitting the form
  2. The current price of the Crypto submitted.

Значения формы проходят через AssetView, но не сохраняются. Может ли кто-нибудь помочь, почему они не сохраняются. Я предоставил модели, представления, форму, 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 class="container">
      <h1>My Dashboard</h1>
        <p>
          <form method="post">
          {% csrf_token %}
          {{ form_a.as_p }}
          <button type="submit">Submit</button>
      </form>
    </p>
</div>
    {% endblock %}

позвольте мне объяснить вам ошибки:

AttributeError: 'dict' object has no attribute 'save'

Эта ошибка возникает потому, что вы пытаетесь сохранить таким образом:

post = form_a.cleaned_data
post.save()

Это неправильно, потому что clean_data - это dict, он содержит значения вашей формы в виде пар fieldname:value.

Правильным способом является:

post = form_a.save()

Следующая ошибка гласит, что требуется значение поля crypto_prices, но вы передаете нулевое значение.

django.db.utils.IntegrityError: null value in column "crypto_prices_id" of relation "coinprices_cryptoassets" violates not-null constraint

Это происходит потому, что в вашей форме AssetForm вы выбираете только эти поля:

fields = (
            'symbol',
            'amount',
            'purchase_price'
        )

Где находится crypto_prices? Поле определено как требуемое в вашем models.py в этой строке:

crypto_prices = models.ForeignKey(CryptoPrices, on_delete=models.CASCADE)

Решение: необходимо включить поле 'crypto_prices' в ваши формы или установить его перед сохранением формы в AssetView. Вот так:

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'
    )

Или так:

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)
Вернуться на верх