Problem z zapisem danych pobranych z formularza crispy-form

0

Jestem początkujący w Django i mam problem z zapisaniem do bazy danych informacji pobranych z formularza crispy-form.
Chciałem w mojej aplikacji mieć fajniej wyglądający formularz dla użytkownika i znalazłem info o crispy-form. Zainstalowałem crispy-form, zrobiłem formularz i nawet ładnie mi się wyświetla na stronie. Problem pojawiła się kiedy chcę zapisać dane z formularza do bazy.
Wyskakuje mi strona z błedami, jest komunikat 'FormNowaFirma' object has no attribute 'save'
W views.py jest funkcja która powinna zapisać dane do bazy danych. Na standartowym formularzu Django normalnie zapisywała dane do bazy, teraz na crispy-form pokazuje komunikat o błędzie. Nie wiem o co chodzi. Na stronach internetowych gdzie są jakieś projekty z wykorzystaniem crispy-form normalnie jest wykorzystana metoda save formularza i jest ok. Może coś w importach do pliku views.py dałem za dużo lub za mało (jeszcze tego do końca nie ogarniam).

Może mi coś pomożecie?

forms.py

from django.forms import ModelForm
from crispy_forms.helper import FormHelper
from .models import Firma, DaneKsiegowe
from django import forms
from django.urls import reverse
from crispy_forms.bootstrap import Field, TabHolder, Tab
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Layout, Fieldset

class FormNowaFirma(forms.Form):
    nazwa = forms.CharField(required=True, max_length=120)
    typ_ksiegowosc = forms.ChoiceField(
        choices=(("ryczałt ewidencjonowany","ryczałt ewidencjonowany"),("ryczałt ewidencjonowany bez VAT","ryczałt ewidencjonowany bez VAT"),
                 ("KPiR skala podatkowa","KPiR skala podatkowa"),("KPiR skala podatkowa bez VAT","KPiR skala podatkowa bez VAT"),
                 ("KPiR podatek liniowy","KPiR podatek liniowy"),("KPiR podatek liniowy bez VAT","KPiR podatek liniowy bez VAT"),
                 ("pełna księgowość","pełna księgowość"),("pełna księgowość bez VAT","pełna księgowość bez VAT")),
        widget=forms.Select,
        initial='2',
        required=True
    )
    nip = forms.CharField(required=True, max_length=20)
    imie = forms.CharField(max_length=30)
    nazwisko = forms.CharField(max_length=50)
    pesel = forms.CharField(max_length=11)
    ulica = forms.CharField(required=True, max_length=50)
    nr_budynek = forms.CharField(required=True, max_length=4)
    nr_lokal = forms.CharField(max_length=4)
    miasto = forms.CharField(required=True, max_length=50)
    kod_p = forms.CharField(required=True, max_length=6)
    gmina = forms.CharField(required=True, max_length=50)
    powiat = forms.CharField(required=True, max_length=50)
    wojewodztwo = forms.ChoiceField(
        choices=(("Dolnośląskie","Dolnośląskie"), ("Kujawsko-pomorskie","Kujawsko-pomorskie"), ("Lubelskie","Lubelskie"),
                 ("Lubuskie","Lubuskie"),("Łódzkie","Łódzkie"),("Małopolskie","Małopolskie"),("Mazowieckie","Mazowieckie"),
                 ("Opolskie","Opolskie"),("Podkarpackie","Podkarpackie"),("Podlaskie","Podlaskie"),("Pomorskie","Pomorskie"),
                 ("Śląskie","Śląskie"),("Świętokrzyskie","Świętokrzyskie"),("Warmińsko-mazurskie","Warmińsko-mazurskie"),
                 ("Wielkopolskie","Wielkopolskie"),("Zachodniopomorskie","Zachodniopomorskie")),
        widget=forms.Select,
        initial='0',
        required=True
    )
    segregator = forms.CharField(required=True, max_length=3)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_id = 'id_nowa_firma'
        self.helper.form_method = 'post'
        self.helper.form_action = reverse('nowa_firma')
        self.helper.add_input(Submit('submit','Zapisz firmę', css_class='btn-success'))
        self.helper.form_class = 'form-horizontal'
        self.helper.layout = Layout(
            TabHolder(Tab('Dane firmy',
            Fieldset('Dane firmy',
                Field('typ_ksiegowosc', placeholder='Wybierz rodzaj księgowości',css_class="form-control"),
                Field('nazwa', placeholder='Wpisz nazwę firmy',css_class="form-control"),
                Field('segregator', placeholder='Wpisz nr segregatora',css_class="form-control"),
                Field('nip', placeholder='Wpisz NIP firmy',css_class="form-control"),
                Field('imie', placeholder='Wpisz imię włąściciela firmy',css_class="form-control"),
                Field('nazwisko', placeholder='Wpisz nazwisko właściciela firmy',css_class="form-control"),
                Field('pesel', placeholder='Wpisz PESEL właściciela firmy',css_class="form-control"))),
            Tab('Adres',
            Fieldset('Adres firmy',
                     Field('ulica', placeholder='Wpisz ulicę firmy',css_class="some-class"),
                     Field('nr_budynek', placeholder='Wpisz nr budynku firmy',css_class="some-class"),
                     Field('nr_lokal', placeholder='Wpisz nr lokalu firmy',css_class="some-class"),
                     Field('miasto', placeholder='Wpisz miasto firmy',css_class="some-class"),
                     Field('kod_p', placeholder='Wpisz kod pocztowy firmy',css_class="some-class"),
                     Field('gmina', placeholder='Wpisz gminę firmy',css_class="some-class"),
                     Field('powiat', placeholder='Wpisz powiat firmy',css_class="some-class"),
                     Field('wojewodztwo', placeholder='Wpisz województwo firmy',css_class="some-class")))
            )
        )

views.py

from django.shortcuts import render, redirect, get_object_or_404
from .forms import FormDane, FormNowaFirma
from .models import Firma, DaneKsiegowe
from django.template import loader
from django.template.context_processors import csrf
from crispy_forms.utils import render_crispy_form

def nowa_firma(request):
    form_dane = FormNowaFirma(request.POST or None)
    if form_dane.is_valid():
        form_dane.save()
        return redirect(index)

    return render(request, 'form_nowa_firma.html', {'form_nowa_firma':form_dane})

Bug report

AttributeError at /nowa_firma/
'FormNowaFirma' object has no attribute 'save'
Request Method:	POST
Request URL:	http://127.0.0.1:8000/nowa_firma/
Django Version:	5.0.4
Exception Type:	AttributeError
Exception Value:	
'FormNowaFirma' object has no attribute 'save'
Exception Location:	C:\Users\Marcin\django\biuro\biuroTax\pulpitBiuro\views.py, line 41, in nowa_firma
Raised during:	pulpitBiuro.views.nowa_firma
Python Executable:	C:\Users\Marcin\django\biuro\venv\Scripts\python.exe
Python Version:	3.12.2
Python Path:	
['C:\\Users\\Marcin\\django\\biuro\\biuroTax',
 'C:\\Users\\Marcin\\AppData\\Local\\Programs\\Python\\Python312\\python312.zip',
 'C:\\Users\\Marcin\\AppData\\Local\\Programs\\Python\\Python312\\DLLs',
 'C:\\Users\\Marcin\\AppData\\Local\\Programs\\Python\\Python312\\Lib',
 'C:\\Users\\Marcin\\AppData\\Local\\Programs\\Python\\Python312',
 'C:\\Users\\Marcin\\django\\biuro\\venv',
 'C:\\Users\\Marcin\\django\\biuro\\venv\\Lib\\site-packages']
Server time:	Sun, 28 Apr 2024 05:36:45 +0000
0

Może spróbuj class FormNowaFirma(forms.ModelForm): zamiast class FormNowaFirma(forms.Form):

bo z dokumentacji wynika ze form to
Class Field When you create a Form class, the most important part is defining the fields of the form. Each field has custom validation logic, along with a few other hooks.

a to drugie to tworzy
ModelForm If you’re building a database-driven app, chances are you’ll have forms that map closely to Django models. For instance, you might have a BlogComment model, and you want to create a form that lets people submit comments. In this case, it would be redundant to define the field types in your form, because you’ve already defined the fields in your model.For this reason, Django provides a helper class that lets you create a Form class from a Django model.

no i jak jest importowany model to wtedy itp:

class Meta:
        model = Firma 
        fields = ['nazwa', 'typ_ksiegowosc', 'nip', 'imie', 'nazwisko', 'pesel', 'ulica', 'nr_budynek', 'nr_lokal', 'miasto', 'kod_p', 'gmina', 'powiat', 'wojewodztwo', 'segregator'] 

jezszcze pisze ze Every ModelForm also has a save() method. This method creates and saves a database object from the data bound to the form. czyli jak używasz klase Form to nie ma metody save() bo nie operuje się na modelu.

tylko nie wiem czy to będzie dobre bo ja korzystałem z wersji dokumentacji Django 5.0

2

hmm no to może stwórz obiekt modelu w view ale nie wiem czy to do końca poprawne rozwiazanie ... ( ze zwgledu na jakość...) no bo lepiej

czyli twój forms.py pozostaje bez zmian
a zmieni się tylko views.py

def nowa_firma(request):
    form_dane = FormNowaFirma(request.POST or None)
    if form_dane.is_valid():
        # tworzenie nowej instancji modelu 
        firma = Firma(
            nazwa=form_dane.cleaned_data['nazwa'],
            typ_ksiegowosc=form_dane.cleaned_data['typ_ksiegowosc'],
            nip=form_dane.cleaned_data['nip'],
            imie=form_dane.cleaned_data['imie'],
            nazwisko=form_dane.cleaned_data['nazwisko'],
            pesel=form_dane.cleaned_data['pesel'],
            ulica=form_dane.cleaned_data['ulica'],
            nr_budynek=form_dane.cleaned_data['nr_budynek'],
            nr_lokal=form_dane.cleaned_data['nr_lokal'],
            miasto=form_dane.cleaned_data['miasto'],
            kod_p=form_dane.cleaned_data['kod_p'],
            gmina=form_dane.cleaned_data['gmina'],
            powiat=form_dane.cleaned_data['powiat'],
            wojewodztwo=form_dane.cleaned_data['wojewodztwo'],
            segregator=form_dane.cleaned_data['segregator'],
        )

        # i jak stworzy sie model to powinna być metoda dostepna
        firma.save()

        # no i jeszcze zostaja dane ksiegowe ale tego juz nie pisze bo nie wiem o co chodzi 

        return redirect(index)

    return render(request, 'form_nowa_firma.html', {'form_nowa_firma':form_dane})

lub tak jak wcześniej pisałem
a w tym wyżej przykładzie co wcześniej pisałem chodziło mi o tylko o zmianę forms.py


#zmiana forms.Form na ModelForm 
class FormNowaFirma(ModelForm):
    nazwa = forms.CharField(required=True, max_length=120)
    typ_ksiegowosc = forms.ChoiceField(
        choices=(("ryczałt ewidencjonowany","ryczałt ewidencjonowany"),("ryczałt ewidencjonowany bez VAT","ryczałt ewidencjonowany bez VAT"),
                 ("KPiR skala podatkowa","KPiR skala podatkowa"),("KPiR skala podatkowa bez VAT","KPiR skala podatkowa bez VAT"),
                 ("KPiR podatek liniowy","KPiR podatek liniowy"),("KPiR podatek liniowy bez VAT","KPiR podatek liniowy bez VAT"),
                 ("pełna księgowość","pełna księgowość"),("pełna księgowość bez VAT","pełna księgowość bez VAT")),
        widget=forms.Select,
        initial='2',
        required=True
    )
    nip = forms.CharField(required=True, max_length=20)
    imie = forms.CharField(max_length=30)
    nazwisko = forms.CharField(max_length=50)
    pesel = forms.CharField(max_length=11)
    ulica = forms.CharField(required=True, max_length=50)
    nr_budynek = forms.CharField(required=True, max_length=4)
    nr_lokal = forms.CharField(max_length=4)
    miasto = forms.CharField(required=True, max_length=50)
    kod_p = forms.CharField(required=True, max_length=6)
    gmina = forms.CharField(required=True, max_length=50)
    powiat = forms.CharField(required=True, max_length=50)
    wojewodztwo = forms.ChoiceField(
        choices=(("Dolnośląskie","Dolnośląskie"), ("Kujawsko-pomorskie","Kujawsko-pomorskie"), ("Lubelskie","Lubelskie"),
                 ("Lubuskie","Lubuskie"),("Łódzkie","Łódzkie"),("Małopolskie","Małopolskie"),("Mazowieckie","Mazowieckie"),
                 ("Opolskie","Opolskie"),("Podkarpackie","Podkarpackie"),("Podlaskie","Podlaskie"),("Pomorskie","Pomorskie"),
                 ("Śląskie","Śląskie"),("Świętokrzyskie","Świętokrzyskie"),("Warmińsko-mazurskie","Warmińsko-mazurskie"),
                 ("Wielkopolskie","Wielkopolskie"),("Zachodniopomorskie","Zachodniopomorskie")),
        widget=forms.Select,
        initial='0',
        required=True
    )
    segregator = forms.CharField(required=True, max_length=3)

    class Meta:
        model = Firma
        fields = ['nazwa', 'typ_ksiegowosc', 'nip', 'imie', 'nazwisko', 'pesel', 'ulica',
                  'nr_budynek', 'nr_lokal', 'miasto', 'kod_p', 'gmina', 'powiat', 'wojewodztwo',
                  'segregator']
      #wypisanie wszystkie fieldy 

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_id = 'id_nowa_firma'
        self.helper.form_method = 'post'
        self.helper.form_action = reverse('nowa_firma')
        self.helper.add_input(Submit('submit','Zapisz firmę', css_class='btn-success'))
        self.helper.form_class = 'form-horizontal'
        self.helper.layout = Layout(
            TabHolder(Tab('Dane firmy',
            Fieldset('Dane firmy',
                Field('typ_ksiegowosc', placeholder='Wybierz rodzaj księgowości',css_class="form-control"),
                Field('nazwa', placeholder='Wpisz nazwę firmy',css_class="form-control"),
                Field('segregator', placeholder='Wpisz nr segregatora',css_class="form-control"),
                Field('nip', placeholder='Wpisz NIP firmy',css_class="form-control"),
                Field('imie', placeholder='Wpisz imię włąściciela firmy',css_class="form-control"),
                Field('nazwisko', placeholder='Wpisz nazwisko właściciela firmy',css_class="form-control"),
                Field('pesel', placeholder='Wpisz PESEL właściciela firmy',css_class="form-control"))),
            Tab('Adres',
            Fieldset('Adres firmy',
                     Field('ulica', placeholder='Wpisz ulicę firmy',css_class="some-class"),
                     Field('nr_budynek', placeholder='Wpisz nr budynku firmy',css_class="some-class"),
                     Field('nr_lokal', placeholder='Wpisz nr lokalu firmy',css_class="some-class"),
                     Field('miasto', placeholder='Wpisz miasto firmy',css_class="some-class"),
                     Field('kod_p', placeholder='Wpisz kod pocztowy firmy',css_class="some-class"),
                     Field('gmina', placeholder='Wpisz gminę firmy',css_class="some-class"),
                     Field('powiat', placeholder='Wpisz powiat firmy',css_class="some-class"),
                     Field('wojewodztwo', placeholder='Wpisz województwo firmy',css_class="some-class")))

Czyli albo pierwsze albo drugie ja tak to rozumiem. Ciekawe czy teraz zadziała.

1 użytkowników online, w tym zalogowanych: 0, gości: 1