Reputation: 1
I am making a Django Gym app following this tutorial https://www.youtube.com/watch?v=Mag1n3MFDFk&list=PL2aJidc6QnyOe-fp1m4yKHjcInCRTF53N&index=3 I wanted to write a form page that the user (once logged in) can fill and become a subscriber. In the tutorial he used a new model Enrollment to fill the data with but I have a model Pretplatnik (Subscriber in english) that has a OneToOne relationship with django user model. Also two other models that are FK to Pretplatnik for Plan that the user can subscribe to and a model for Trainer that the user can choose.
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Oznaka(models.Model):
naziv = models.CharField(max_length=200)
def __str__(self):
return self.naziv
class Plan(models.Model):
naziv=models.CharField(max_length=150)
cijena=models.IntegerField()
max_clanova=models.IntegerField(null=True)
oznake=models.ManyToManyField(Oznaka, default=None, blank=True, related_name='oznake')
def __str__(self):
return '%s' % self.naziv
class Trener(models.Model):
ime=models.CharField(max_length=150)
image=models.ImageField(upload_to='static/assets/img/team', default=None)
def __str__(self):
return self.ime
class Pretplatnik(models.Model):
korisnik=models.OneToOneField(User, on_delete=models.CASCADE)
trener=models.ForeignKey(Trener, on_delete=models.CASCADE, related_name='pretplatnici')
plan=models.ForeignKey(Plan, on_delete=models.CASCADE, null=True)
datum_r=models.DateField(blank=True,null=True)
spol=models.CharField(max_length=25, default=None)
adresa=models.CharField(max_length=150)
def __str__(self):
return str(self.korisnik)
class Pretplata(models.Model):
pretplatnik=models.ForeignKey(Pretplatnik, on_delete=models.CASCADE, null=True)
plan=models.ForeignKey(Plan, on_delete=models.CASCADE, null=True)
class CustomModelName(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
from django import forms
from django.forms import ModelForm
from teretana.models import *
class PretplatnikForm(forms.ModelForm):
plan = forms.ModelChoiceField(queryset=Plan.objects.all(),
to_field_name = 'naziv',
empty_label="Select Plan")
trener = forms.ModelChoiceField(queryset=Trener.objects.all(),
to_field_name = 'ime',
empty_label="Select Trainer")
class Meta:
model = Pretplatnik
fields = ['trener', 'plan', 'datum_r', 'spol', 'adresa']
GENDER_CHOICES = (
('', 'Select a Gender'),
('Female', 'Female'),
('Male', 'Male'),
)
widgets = {
'trener':forms.TextInput(attrs={'class':'form-control','placeholder':'Select Trainer'}),
'plan':forms.TextInput(attrs={'class':'form-control','placeholder':'Select Plan'}),
'datum_r':forms.DateInput(attrs={'class':'form-control','placeholder':'Enter Date of Birth'}),
'spol':forms.Select(choices=GENDER_CHOICES,attrs={'class': 'form-control'}),
'adresa':forms.TextInput(attrs={'class':'form-control','placeholder':'Enter Address'}),
}
labels={
'plan':'Select Plan',
'trener':'Select Trainer',
'datum_r':'Datum_r',
}
views.py
def enroll(request):
if request.method == 'POST':
form = PretplatnikForm(request.POST)
if form.is_valid():
form.save()
form = PretplatnikForm()
return render(request, 'enroll.html', {'form': form})
enroll.html
{% extends 'base.html' %}
{% block title %} Enrollment for Gym {% endblock title%}
{% block head %}
<h2>Join The Best Gym In Rijeka</h2>
<div class="container mt-2">
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-6">
{% for message in messages %}
<div
class="alert alert-{{message.tags}} alert-dismissible fade show"
role="alert"
>
<strong></strong> {{message}}
<button
type="button"
class="btn-close"
data-bs-dismiss="alert"
aria-label="Close"
></button>
</div>
{% endfor %}
<form action="/enroll" method="post">{% csrf_token %}
{% csrf_token %}
<div class="form-group">
<label class="form-label">{{form.trener.label_tag}}</label>
{{form.trener}}
</div>
<form action="/enroll" method="post">{% csrf_token %}
{% csrf_token %}
<div class="form-group">
<label class="form-label">{{form.plan.label_tag}}</label>
{{form.plan}}
</div>
<form action="/enroll" method="post">{% csrf_token %}
{% csrf_token %}
<div class="form-group">
{{form.spol}}
</div>
<br>
<form action="/enroll" method="post">{% csrf_token %}
{% csrf_token %}
<div class="form-group">
{{form.adresa}}
</div>
<br>
<form action="/enroll" method="post">{% csrf_token %}
{% csrf_token %}
<div class="form-group">
{{form.datum_r}}
</div>
<br>
<div class="form-group">
<input
type="number"
class="form-control mt-2"
value="{{user.username}}"
name="PhoneNumber"
placeholder="Enter Your Number"
readonly
required
/>
</div>
</div>
<br>
<div class="d-grid gap-2">
<button class="btn btn-warning" type="submit">Enroll</button>
</div>
</form>
</div>
<div class="col-md-3"></div>
</div>
</div>
{% endblock head %}
He is using HTML form to get the data but I've tried to and it doesn't work for FK (or it does but I don't know how to implement it) so I've tried with ModelForm. But now I get this error since I presume the ModelForm doesn't know that the django user data which is PK for Pretplatnik is already filled (the user cannot fill the form unless logged in). I've tried to change the views file like I've seen on another question posted here but then I get the error: AttributeError at /enroll
'Pretplatnik' object has no attribute 'is_valid'
views.py
def enroll(request):
if not request.user.is_authenticated:
messages.warning(request,"Please Login and Try Again")
return redirect('/login')
if request.method == 'POST':
form = PretplatnikForm(request.POST)
form = form.save(commit=False)
if form.is_valid():
form.save()
form = PretplatnikForm()
return render(request, 'enroll.html', {'form': form})
EDIT:
I forgot to add the forms.py so here it is
forms.py
from django import forms
from django.forms import ModelForm
from teretana.models import *
class PretplatnikForm(forms.ModelForm):
plan = forms.ModelChoiceField(queryset=Plan.objects.all(),
to_field_name = 'naziv',
empty_label="Select Plan")
trener = forms.ModelChoiceField(queryset=Trener.objects.all(),
to_field_name = 'ime',
empty_label="Select Trainer")
class Meta:
model = Pretplatnik
fields = ['trener', 'plan', 'datum_r', 'spol', 'adresa']
GENDER_CHOICES = (
('', 'Select a Gender'),
('Female', 'Female'),
('Male', 'Male'),
)
widgets = {
'trener':forms.TextInput(attrs={'class':'form-control','placeholder':'Select Trainer'}),
'plan':forms.TextInput(attrs={'class':'form-control','placeholder':'Select Plan'}),
'datum_r':forms.DateInput(attrs={'class':'form-control','placeholder':'Enter Date of Birth'}),
'spol':forms.Select(choices=GENDER_CHOICES,attrs={'class': 'form-control'}),
'adresa':forms.TextInput(attrs={'class':'form-control','placeholder':'Enter Address'}),
}
labels={
'plan':'Select Plan',
'trener':'Select Trainer',
'datum_r':'Datum_r',
}
def __init__(self, *args, **kwargs):
super(PretplatnikForm, self).__init__(*args, **kwargs)
# Add first_name and last_name fields from the User model
self.fields['first_name'] = forms.CharField(max_length=150, widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter First Name'}))
self.fields['last_name'] = forms.CharField(max_length=150, widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter Last Name'}))
def save(self, commit=True):
# Save the User instance first
user = super(PretplatnikForm, self).save(commit=False)
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
if commit:
user.save()
# Save the Pretplatnik instance
pretplatnik = super(PretplatnikForm, self).save(commit=False)
pretplatnik.korisnik = user
if commit:
pretplatnik.save()
return pretplatnik
I also changed the view
views.py
def enroll(request):
if not request.user.is_authenticated:
messages.warning(request, "Please login and try again")
return redirect('/login')
if request.method == 'POST':
form = PretplatnikForm(request.POST)
if form.is_valid():
# Create a new Pretplatnik instance
pretplatnik_instance = form.save(commit=False)
pretplatnik_instance.korisnik = request.user
# Set first_name and last_name based on the logged-in user
pretplatnik_instance.first_name = request.user.first_name
pretplatnik_instance.last_name = request.user.last_name
pretplatnik_instance.save()
messages.success(request, "You have successfully enrolled.")
return redirect('/') # Redirect to a success page or dashboard
else:
messages.error(request, "Form submission failed. Please check the errors.")
else:
form = PretplatnikForm()
return render(request, 'enroll.html', {'form': form})
But now I get a message after I logout saying "Form submission failed". I don't get redirected after filling the form, it keeps me on the /enroll page and most importantly the data doesn't save.
Upvotes: 0
Views: 28
Reputation: 1118
This is not necessarily the answer but something looks strange here:
if request.method == 'POST':
form = PretplatnikForm(request.POST)
form = form.save(commit=False) # not sure why this is here
if form.is_valid():
form.save()
Normally one would see this pattern, where commit=False follows validation. It's not clear to me how you wanted to use this, or how you're adding the One-to-One for the korisnik field, but here's an example of something that might normally be used.
if request.method == 'POST':
form = PretplatnikForm(request.POST)
if form.is_valid():
new_sub = form.save(commit=False)
new_sub.korisnik = korisnik_object # queried elsewhere
new_sub.save() # no need to call form.save()
Upvotes: 0