I am currently making a flashcard web application with Django.
There is a 'set' page (dashboard) and a 'card' page (set-edit). When I fill in and submit the form on the card page (set-edit) to add a new card to the set which has been selected for editing, I received a value error ' Cannot assign "2": "Card.set" must be a "Set" instance.'
I'm unsure why this is happening because there is an instance of Set with an id of 2.
Any suggestions of how to rectify this issue?
views.py
###################
##Dashboard views##
###################
def dashboard(request):
set = Set.objects.all()
set_count = set.count()
if request.method == 'POST':
form = SetForm(request.POST)
if form.is_valid():
form.save()
set_name = form.cleaned_data.get('name')
messages.success(request, f'{set_name} has been added')
return redirect('dashboard-dashboard')
else:
form = SetForm()
context = {
'set': set,
'form': form,
}
return render(request, 'dashboard/dashboard.html', context)
#############
##Set views##
#############
#Cards is for when you are adding cards to a set or looking at the content of a set
def set_edit(request, pk):
set_title = Set.objects.get(id=pk)
card = Set.objects.get(id=pk).card_set.all()
set_id = pk
set = Set.objects.get(id=pk)
if request.method == 'POST':
form = CardForm(request.POST)
print('Entered Post condition')
if form.is_valid():
obj = form.save(commit=False)
obj.set = pk
obj.save()
card_name = form.cleaned_data.get('kanji')
messages.success(request, f'{card_name} has been added')
return redirect('dashboard-set-edit',pk)
else:
form = CardForm()
context = {
'card': card,
'form': form,
}
return render(request, 'dashboard/set_edit.html', context)
```
**models.py**
```
class Set(models.Model):
name = models.CharField(max_length=100, null=True)
quantity = models.PositiveIntegerField(null=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f'{self.id}'
class Card(models.Model):
kanji = models.CharField(max_length=100, null=True)
kana = models.CharField(max_length=100, null=True)
english = models.CharField(max_length=100, null=True)
set = models.ForeignKey(Set, on_delete=models.CASCADE,default=3)
def __str__(self):
return f'{self.id}'
```
**forms.py**
```
class CardForm(forms.ModelForm):
class Meta:
model = Card
# fields = '__all__'
exclude = ('set',)
class SetForm(forms.ModelForm):
class Meta:
model = Set
fields = '__all__'
```
**urls.py**
urlpatterns = [
#########
##Sets###
#########
path('sets/edit/<int:pk>/', views.set_edit,
name='dashboard-set-edit'),
path('sets/delete/<int:pk>/', views.set_delete,
name='dashboard-set-delete'),
#########
##Cards##
#########
path('card/delete/<int:pk>/', views.card_delete,
name='dashboard-cards-delete'),
path('cards/detail/<int:pk>/', views.card_detail,
name='dashboard-cards-detail'),
path('cards/edit/<int:pk>/', views.card_edit,
name='dashboard-cards-edit'),
#############
##Dashboard##
#############
path('dashboard/', views.dashboard, name='dashboard-dashboard'),
]
```
You should assign it to .set_id, not .set:
if form.is_valid():
# use set_id ↓
form.instance.set_id = pk
obj = form.save()
card_name = form.cleaned_data.get('kanji')
messages.success(request, f'{card_name} has been added')
return redirect('dashboard-set-edit',pk)
Related
I have a ModelForm called ListingForm. It takes data from a user but I have stopped some of the model attributes from appearing in this form as I want to feed data to those myself. I have put print statements in my createlisting function in views.py to inspect if the data is actually being saved correctltly, it turns out the data is being saved. Here is the createlisting function:
def create_listing(request):
if request.method == 'POST':
import datetime
listing_form = ListingForm(request.POST, request.FILES)
if listing_form.is_valid():
bid = listing_form.cleaned_data['starting_bid']
print(bid)
listing_form.save(commit=False)
listing_form.user = request.user
print(listing_form.user)
listing_form.date_made = datetime.datetime.today()
listing_form.is_active = True
listing_form.category = Category.objects.get(name=listing_form.cleaned_data['listing_category'])
print(listing_form.category)
#The form is being saved correctly here, and the print statements give the correct results in my terminal
listing_form.save()
Bid.objects.create(user= request.user, value=bid, listing=listing_form.instance)
all_listings = Listing.objects.all()
return render(request, 'auctions/index.html', {
'all_listings': all_listings })
else:
listing_form = ListingForm()
return render(request, 'auctions/createlisting.html',{
'listing_form':listing_form
})
However, when I try to access the data from the model Listing from which the ListingForm is inheriting, the print statements I have put for debugging return the default values for certain fields (category and user) instead of the values I have saved in the ListingForm.
Here is the code that allows me to view the data for the model instance I have created. Mind you, all the other fields have saved correctly except for the fields category and user:
def view_listing(request, listing_id):
listing = Listing.objects.get(pk=listing_id)
#the print results return the default values for the fields category and user instead of the values I saved in my ModelForm
print(listing.category)
print(listing.user)
if request.user == listing.user:
return render(request, 'auctions/view_listing.html', {
'listing': listing,
'flag':True,
'count': listing.bids.all().count()
})
else:
return render(request, 'auctions/view_listing.html',{
'listing':listing,
'count': listing.bids.all().count()
})
What could be the problem with my code?
Also, let me provide the code for some of my models and a form as the error might be embedded in those:
Listing Model:
class Listing(models.Model):
NAME_CHOICES = [
('Fashion', 'Fashion'),
('Toys','Toys'),
('Electronics','Electronics'),
('Home', 'Home'),
('Other', 'Other')
]
title = models.CharField(max_length= 64)
date_made = models.DateTimeField(auto_now_add=True)
description = models.TextField()
user = models.ForeignKey(User, to_field='username', on_delete=models.CASCADE, related_name='user_listings', null=True)
starting_bid = models.DecimalField(decimal_places=2, max_digits=264, default=10.00)
upload_image = models.ImageField(blank=True, upload_to='media/media')
category = models.ForeignKey(Category, on_delete=models.CASCADE, to_field='name', related_name='category_listings', default=NAME_CHOICES[4][0], db_constraint=False)
listing_category = models.CharField(max_length=12, choices=NAME_CHOICES, null=True, default=NAME_CHOICES[4][0])
is_active = models.BooleanField(default=True)
watchlist = models.ForeignKey('Watchlist', on_delete=models.DO_NOTHING, related_name='listings', null=True)
Category Model:
class Category(models.Model):
NAME_CHOICES = [
('Fashion', 'Fashion'),
('Toys','Toys'),
('Electronics','Electronics'),
('Home', 'Home'),
('Other', 'Other')
]
name = models.CharField(max_length=12, choices= NAME_CHOICES, unique=True)
User Model:
class User(AbstractUser):
def __str__(self):
return f'{self.username} '
ListingForm`` (ModelForm```):
class ListingForm(ModelForm):
class Meta:
model = Listing
exclude = [
'date_made',
'user',
'category',
'is_active',
'watchlist'
]
Any form of help would be greatly appreciated.
When you call listing_form.save(commit=False) it returns an unsaved model instance with the submitted values. If you assign that to a variable, you can use it to set the other field values and save:
def create_listing(request):
if request.method == 'POST':
import datetime
listing_form = ListingForm(request.POST, request.FILES)
if listing_form.is_valid():
bid = listing_form.cleaned_data['starting_bid']
listing = listing_form.save(commit=False)
listing.user = request.user
listing.date_made = datetime.datetime.today()
listing.is_active = True
listing.category = Category.objects.get(name=listing_form.cleaned_data['listing_category'])
listing.save()
Bid.objects.create(user=request.user, value=bid, listing=listing)
# You should probably use HttpResponseRedirect to an `all_listings` page, rather than displaying them here
all_listings = Listing.objects.all()
return render(request, 'auctions/index.html', {
'all_listings': all_listings })
Here's a link to the ModelForm.save() docs.
I've this two models:
MODEL
class File(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
filename = models.CharField(max_length=250)
file_upload = models.FileField(upload_to=path)
upload_date = models.DateField(default=datetime.now)
def __str__(self):
return self.user.name + 'file'
class Dataset(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
file_uploaded = models.OneToOneField(File, on_delete=models.CASCADE)
name_user_A = models.CharField(max_length=250)
code_user_A = models.PositiveIntegerField(null=True)
total_user_A = models.PositiveIntegerField(null=True)
sd_user_A = models.PositiveIntegerField(null=True)
name_user_B = models.CharField(max_length=250)
code_user_B = models.PositiveIntegerField(null=True)
total_user_B = models.PositiveIntegerField(null=True)
sd_user_B = models.PositiveIntegerField(null=True)
With File model it should be uploaded a csv file and then the information in the file should be saved in the Dataset model. After that I'd like to show some chart to my user so I need my File and Dataset models linked. This is my view:
VIEWS
def file_upload(request):
data = None
if request.method == 'POST':
form = FileForm(request.POST, request.FILES)
raw_file= request.FILES
if form.is_valid():
form.instance.user = request.user.profile
form.instance.filename = raw_file['file_upload'].name
form.save()
data = request.FILES['file_upload']
data = pd.read_csv(data, header=0, encoding="UTF-8")
data_form.instance.user = request.user.profile
Dataset.objects.create(
name_user_A = data.iloc[0,1],
name_user_B = data.iloc[1,1],
[...]
)
return redirect('upload_file')
else:
return redirect('home')
else:
form = FileForm()
context = {
'data': data,
'form': form,
}
return render(request, 'upload_file.html', context)
When I try to access the Dataset database in the admin area I get this error: 'NoneType' object has no attribute 'user'.
I cannot also access the html page with results and the chart because I'm getting this error: Dataset matching query does not exist.
These are the view and the url code on how I'm reaching the html page
def results(request, id):
results = File.objects.filter(user=request.user.profile).filter(pk=id)
context = {
'results': results
}
return render(request, 'results.html', context)
urlpatterns = [
path('chart/<id>', views.results, name="file"),
]
Can someone kindly help me and explain to me how can I fix my code? Thank you
I want to save data in two models from a single POST request. Two different models (OF, Encours)
Here's my models.py:
class OF(models.Model):
Id_OF= models.BigAutoField(primary_key=True)
Numero_Of = models.BigIntegerField(unique=True,blank=False)
class Dimension_OF(models.TextChoices):
PD_inférieur_à_500mm="PD"
MD_Entre_500_et_1500mm="MD"
GD_supérieur_à_1500mm="GD"
Dimension_OF = models.CharField(max_length=20, blank=False,choices=Dimension_OF.choices)
class Machine(models.TextChoices):
MGP1="MGP1"
MGP2="MGP2 "
MGP3="MGP3"
MGP4="MGP4"
MGP5="MGP5"
MGP6="MGP6"
MGP7="MGP7"
MGP8="MGP8"
Machine=models.CharField(max_length=10,choices=Machine.choices, blank=False)
class Scenario(models.TextChoices):
Ajustage_Controle="scenario1"
Ajustage_Redressage_Controle="scenario2"
Ajustage_Formage_Controle="scenario3"
Ajustage_Redressage_Formage_Controle="scenario4"
Scenario = models.CharField(max_length=50,choices=Scenario.choices, blank=False)
Date_E_initial=models.DateTimeField(auto_now_add=True,auto_now=False)
Date_S_Final=models.DateTimeField(null=True, blank=True)
Etat_OF=models.CharField(max_length=50, null=True, blank=True)
Nb_jrs_att_Usin=models.DurationField(null=True, blank=True)
Nb_jrs_att_TM=models.DurationField(null=True, blank=True)
Nb_jrs_att_total=models.DurationField(null=True, blank=True)
def _str_(self):
return self.Scenario
class Encours(models.Model):
Id_encours=models.IntegerField(primary_key=True)
OF = models.ForeignKey(OF, on_delete=models.CASCADE )
class Nom_encours(models.TextChoices):
EN_MGP1="Encours MGP1"
EN_MGP2="Encours MGP2"
EN_MGP3="Encours MGP3"
EN_MGP4="Encours MGP4"
EN_MGP5="Encours MGP5"
EN_MGP6="Encours MGP6"
EN_MGP7="Encours MGP7"
EN_MGP8="Encours MGP8"
EN_AJU_GD="Encours Ajustage GD"
EN_AJU_MD="Encours Ajustage MD"
EN_AJU_PD="Encours Ajustage PD"
EN_RED="Encours Redressage"
EN_For="Encours Formage"
EN_Contr_GD="Encours Contrôle GD"
EN_Contr_MD="Encours Contrôle MD"
EN_Contr_PD="Encours Contrôle PD"
Nom_encours = models.CharField(max_length=30,choices=Nom_encours.choices)
Capacite = models.IntegerField(default=0)
Date_E_Encours=models.DateTimeField(null=True, blank=True)
Date_S_Encours=models.DateTimeField(null=True, blank=True)
def _str_(self):
return self.Nom_encours
But before saving data into Encours I want to define some functions to test field
for exemple ; if OF.Machine=='MGP1' then create a row in Encours model with Nom_Encours='Encours MGP1' and Date_E_Encours = Date_E_initial that automatically added.
views.py
def lancerOF(request):
form = OFLancementForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
form.save()
messages.success(request, 'OF lancé avec succès', extra_tags='alert')
return redirect('lancer')
else:
messages.warning(request, 'Verifiez les données saisies')
return render(request, "lancerOF.html",{'form':form})
and i use a simple form
class OFLancementForm(forms.ModelForm):
class Meta:
model = OF
fields = {
'Numero_Of',
'Dimension_OF',
'Machine',
'Scenario'
}
widgets = { "Dimension_OF": forms.RadioSelect ,"Machine": forms.RadioSelect ,"Scenario": forms.RadioSelect}
if this is possible, where can i do test to check OF attributes and save data into my models.
PS: this is my first real project with django.
Can anyone help me please?
def lancerOF(request):
form = OFLancementForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
myobject = form.save()
# here you can do your logic
if myobject.Machine == "MPG1":
...
messages.success(request, 'OF lancé avec succès', extra_tags='alert')
return redirect('lancer')
else:
messages.warning(request, 'Verifiez les données saisies')
return render(request, "lancerOF.html",{'form':form})
Or another method is using Django's post_save signal.
Or you can override OF's save() method:
class OF(models.Model):
def save(self, *args, **kwargs):
super(OF, self).save(*args, **kwargs)
if self.Machine == "MPG1":
# your logic here.
Please Help!
I am trying to update a group of formsets that are related the main form (Project Information) by the main forms pk. The create form works fine, but I am finding it extremely difficult to implement the update version.
It's the save as an update part that I can't figure out for the formsets. The main form updates the database correctly. The formsets just create new records instead of updating the existing ones. I do not know how to instance the formsets.
Here the code.
view.py
#login_required
def edit_project(request):
SampleInformationFormSet = formset_factory(SampleInformationForm, extra=1)
DissolutionMethodsFormSet = formset_factory(DissolutionMethodsForm, extra=1)
form = ProjectInformationForm(request.POST or None)
si_formset = SampleInformationFormSet(request.POST or None, prefix='si')
d_formset = DissolutionMethodsFormSet(request.POST or None, prefix='d')
if request.method == 'POST':
form = ProjectInformationForm(request.POST or None)
si_formset = SampleInformationFormSet(request.POST or None, prefix='si')
d_formset = DissolutionMethodsFormSet(request.POST or None, prefix='d')
pi_pk = ''
p = ''
if form.is_valid():
pi_pk = form.cleaned_data['hd']
p = ProjectInformation.objects.get(pk=pi_pk)
form = ProjectInformationForm(request.POST, instance=p)
form.save() # This form saves correctly
for si_form in si_formset:
si_form.save() # I do not know how to attach an instance to these formsets
for d_form in d_formset:
d_form.save()
messages.success(request, 'Your project has been updated!')
return redirect('edit_project')
else:
pass
form = ProjectInformationForm(request.POST or None)
si_formset = SampleInformationFormSet(request.POST or None, prefix='si')
messages.warning(request, 'There was an error saving your form.')
study_id_select = list(
ProjectInformation.objects.values('dissolution_study_id', 'id').filter())
context = {'form': form, 'si_formset': si_formset, 'd_formset': d_formset, 'study_id_select': study_id_select}
return render(request, 'main/edit_project.html', context)
models.py I'm just going to include part of three of the seven models to keep this a little shorter.
class ProjectInformation(models.Model):
username = models.ForeignKey(User, on_delete=models.CASCADE)
compound_code = models.CharField(max_length=60)
product_type = models.ForeignKey(ProductType, on_delete=models.CASCADE)
main_component = models.CharField(max_length=100)
class SampleInformation(models.Model):
sample_index = models.CharField(max_length=30)
sample_type_purpose = models.ForeignKey(SampleTypePurpose, on_delete=models.CASCADE)
specification_number = models.CharField(max_length=20, blank=True, null=True)
project = models.ForeignKey(ProjectInformation, on_delete=models.CASCADE, blank=True, null=True)
class DissolutionMethods(models.Model):
number_of_methods = models.IntegerField(default=1,
validators=[MaxValueValidator(10), MinValueValidator(1)],
blank=True, null=True)
dissolution_method_index = models.CharField(max_length=10)
project = models.ForeignKey(ProjectInformation, on_delete=models.CASCADE, blank=True, null=True)
forms.py
class ProjectInformationForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['hd'] = forms.CharField(widget=forms.HiddenInput, required=False)
class Meta:
model = ProjectInformation
fields = '__all__'
class SampleInformationForm(forms.ModelForm):
class Meta:
model = SampleInformation
fields = '__all__'
Please help if you can. This project has been a trial by fire and the flames are hot!
Finally solved it myself.
#login_required
def edit_project(request):
SampleInformationFormSet = formset_factory(SampleInformationForm, extra=1)
DissolutionMethodsFormSet = formset_factory(DissolutionMethodsForm, extra=1)
form = ProjectInformationForm(request.POST or None)
si_formset = SampleInformationFormSet(request.POST or None, prefix='si')
d_formset = DissolutionMethodsFormSet(request.POST or None, prefix='d')
if request.method == 'POST':
form = ProjectInformationForm(request.POST or None)
si_formset = SampleInformationFormSet(request.POST or None, prefix='si')
d_formset = DissolutionMethodsFormSet(request.POST or None, prefix='d')
pi_pk = ''
p = ''
if form.is_valid():
pi_pk = form.cleaned_data['hd']
p = ProjectInformation.objects.get(pk=pi_pk)
form = ProjectInformationForm(request.POST, instance=p)
form.save()
si = p.sampleinformation_set.all() # All the Methods related to the instance
d = p.dissolutionmethods_set.all()
si_cnt = 0
for si_form in si_formset:
if si_form.is_valid():
update = si_form.save(commit=False)
update.pk = si[si_cnt].pk
update.save()
si_cnt += 1
d_cnt = 0
for d_form in d_formset:
if d_form.is_valid():
update = d_form.save(commit=False)
update.pk = d[d_cnt].pk
update.save()
d_cnt += 1
I have a form in my application which has a hidden form field, the value of which I want to set in my corresponding view after submitting the form.
forms.py
class EvangelizedForm(forms.ModelForm):
first_name = forms.CharField(help_text="First Name")
last_name = forms.CharField(help_text="Last Name")
email = forms.CharField(help_text="Email ID")
mobile_no = forms.CharField(help_text="Mobile number")
twitter_url = forms.CharField(help_text="Twitter URL")
twitter_followers = forms.CharField(widget = forms.HiddenInput()) #Hidden form field
class Meta:
model = Evangelized
fields = ('first_name','last_name', 'twitter_url', 'email', 'mobile_no')
models.py
class Evangelized(models.Model):
first_name = models.CharField(max_length=128)
last_name = models.CharField(max_length=128)
email = models.EmailField()
mobile_no = models.CharField(unique=True, max_length = 10, validators=[RegexValidator(regex='^\w{10}$', message='Mobile number should be strictly of 10 digits.')])
twitter_url = models.CharField(unique=True, max_length=128)
twitter_followers = models.CharField(max_length = 128)
views.py
def fillform(request):
follower_count = '250'
if request.method == 'POST':
form = EvangelizedForm(request.POST)
if form.is_valid():
form.fields['twitter_followers'] = follower_count
form.save(commit=True)
return index(request)
else:
form.errors
else:
#form = EvangelizedForm()
if request.user.is_authenticated():
form = EvangelizedForm(initial={'first_name': request.user.first_name,
'twitter_url': 'https://twitter.com/' + request.user.username,
'last_name': request.user.last_name})
else:
form = EvangelizedForm()
context = RequestContext(request,
{'request': request,
'user': request.user, 'form':form})
#return render(request, 'rango/fillform.html', {'form': form, 'context_instance':context})
return render_to_response('rango/fillform.html',
context_instance=context)
Basically, I'm trying to set the value of twitter_followers (which is a hidden form field in forms.py) in my index view, by:
follower_count = '250'
..
..
form.fields['twitter_followers'] = follower_count
By doing this, I'm expecting the value of 'twitter_followers' in the database after submitting the form to be '250'. However, this approach doesn't seem to be working.
What's the right way to set values to certain attributes in the database manually using views?
You need to set it on the model instance, which is the result of form.save. That's the main reason for the commit argument in the first place.
if form.is_valid()
obj = form.save(commit=True)
obj.twitter_follower = follower_count
obj.save()
You can override the save method of the form, with something like this:
def save(self, *args, **kwargs)
twitter_followers = kwargs.pop('twitter_followers', 0)
self.instance.twitter_followers = twitter_followers
super(Evangelized, self).save(args, kwargs)
And then in the view just have to call in this way:
form.save(twitter_followers=250)