Django is giving me this weird AttributeeError :
'Tour' object has no attribute 'check_if_requested_beds_are_avaliable'
However, I have the method check_if_requested_beds_are_avaliable() in my Tour class of my model. The other method - set_new_number_of_beds() works fine. I have never experienced this with with Django, can anybody tell me what the solution is?
This is the model :
from django.db import models
from django.urls import reverse
class Tour(models.Model):
destination = models.CharField(max_length=256)
country = models.CharField(max_length=256)
date_of_arrival = models.DateField()
total_days = models.IntegerField()
price = models.DecimalField(decimal_places=2,max_digits=6)
available_beds = models.IntegerField()
photo = models.ImageField(upload_to='photos',default='photos/def.png')
description = models.TextField(blank=True)
def set_new_number_of_beds(self,number_of_guests):
self.available_beds -= number_of_guests
return self.available_beds
def check_if_requested_beds_are_available(self,numb_of_guests):
if self.available_beds < numb_of_guests:
return False
else:
return True
def __str__(self):
return f'{self.destination} , {self.country} , {self.total_days} days for $ {self.price}'
class Client(models.Model):
name = models.CharField(max_length=256)
surname = models.CharField(max_length=256)
email = models.CharField(max_length=256)
number_of_guests =models.IntegerField()
tour = models.ForeignKey(Tour,on_delete=models.CASCADE)
total_price = models.DecimalField(decimal_places=2,max_digits=6,default=0)
def get_total_price(self):
return self.number_of_guests * self.tour.price
def get_absolute_url(self):
return reverse('tour_list')
def __str__(self):
return f'{self.name} {self.surname}, {self.tour}'
and this is the view:
from django.shortcuts import render
from aplikacija.models import Tour,Client,ContactMessage
from django.views.generic import ListView,DetailView,TemplateView,CreateView
from aplikacija.forms import ClientForm,ContactForm
def HomeView(request):
if request.method=="GET":
return render(request,'aplikacija/home.html')
else:
form= ClientForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
surname=form.cleaned_data['surname']
email=form.cleaned_data['email']
tour_id=form.cleaned_data['tour'].pk
number_of_guests=form.cleaned_data['number_of_guests']
total_price=number_of_guests*form.cleaned_data['tour'].price
tour_name=form.cleaned_data['tour'].destination
client = Client.objects.create(name=name,surname=surname,email=email,number_of_guests=number_of_guests,tour_id=tour_id,total_price=total_price)
client.save()
tour=Tour.objects.get(destination=tour_name)
beds_available = tour.check_if_requested_beds_are_avaliable(number_of_guests)
if beds_available:
tour.set_new_number_of_beds(number_of_guests)
tour.save()
message =f'thank you {name} ! Your reservation to {tour} for {number_of_guests} guests , with a total price of {total_price} has been booked successfully.'
return render(request,'aplikacija/home.html',{'msg':message})
else:
form = ClientForm()
return render(request,'aplikacija/client_form.html',{'infoMsg':f"sorry, there are less than {number_of_guests} beds available for {tour_name}",'form':form})
def thanksView(request):
form=ContactForm(request.POST)
if form.is_valid():
sender=form.cleaned_data['sender']
title=form.cleaned_data['title']
body=form.cleaned_data['body']
message=ContactMessage.objects.create(sender=sender,title=title,body=body)
message.save()
return render(request,'aplikacija/thanks.html')
class TourListView(ListView):
model = Tour
def get_queryset(self):
return Tour.objects.all()
class TourDetailView(DetailView):
model = Tour
class CreateClientView(CreateView):
redirect_field_name = "/aplikacija/home.html"
model = Client
form_class = ClientForm
class contactView(CreateView):
redirect_field_name="/aplikacija/thanks.html"
model = ContactMessage
form_class=ContactForm
So , Its pretty clear that I have the method that gives the AttributeError. And like I said the other method in the class works fine. What am I missing?
It is due to the typo: check_if_requested_beds_are_avaliable. Can be discovered with search or by using IDE with code completion
Related
I created the following model in my django app:
class Post(models.Model):
title = models.CharField(max_length=125, unique=True)
slug_title = models.SlugField(max_length=255, unique=True)
body = models.TextField()
published_date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.BooleanField(default=False)
class Meta:
ordering = ['-published_date']
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug_title = slugify(self.title)
super(Post, self).save(*args, **kwargs)
I want to be able to use an API to do POST/GET requests later on, so I decided to use graphene-django. Everything is installed properly and working.
As per the tutorials, I created my schema.py file as follow:
# define schema
class PostType(DjangoObjectType):
class Meta:
model = Post
fields = ('title', 'body', 'author', 'published_date', 'status', 'slug_title')
class UserType(DjangoObjectType):
class Meta:
model = get_user_model()
class PostInput(graphene.InputObjectType):
title = graphene.String()
slug_title = graphene.String()
body = graphene.String()
author = graphene.Int()
published_date = graphene.DateTime()
status=graphene.Boolean()
class CreatePost(graphene.Mutation):
class Arguments:
input = PostInput(required=True)
post = graphene.Field(PostType)
#classmethod
def mutate(cls, root, info, input):
post = Post()
post.title = input.title
post.slug_title = input.slug_title
post.body = input.body
post.author = input.author
post.published_date = input.published_date
post.status = input.status
post.save()
return CreatePost(post=post)
class Query(graphene.ObjectType):
all_posts = graphene.List(PostType)
author_by_username = graphene.Field(UserType, username=graphene.String())
posts_by_author = graphene.List(PostType, username=graphene.String())
posts_by_slug = graphene.List(PostType, slug=graphene.String())
def resolve_all_posts(root, info):
return Post.objects.all()
def resolve_author_by_username(root, info, username):
return User.objects.get(username=username)
def resolve_posts_by_author(root, info, username):
return Post.objects.filter(author__username=username)
def resolve_posts_by_slug(root, info, slug):
return Post.objects.filter(slug_title=slug)
class Mutation(graphene.ObjectType):
create_post=CreatePost.Field()
schema = graphene.Schema(query=Query, mutation=Mutation)
The query part is working as expected, but my mutation section doesn't seem to be working. When I try to create a mutation, I get the below:
{
"data": {
"create_post": {
"post": null
}
}
}
I created a quick test to see if any errors would output when I run the mutation, but everything seems ok there.
def test_mutation_1(self):
response = self.query(
'''
mutation {
createPost(input:{
title:"Test Title",
body:"Test body",
author:1,
publishedDate:"2016-07-20T17:30:15+05:30",
status:false
})
{
post {
title
}
}
}
'''
)
self.assertResponseNoErrors(response)
I get no error messages.
Any help would be appreciated!
The error: errors=[GraphQLError('Cannot assign "1": "Post.author" must be a "User" instance.'
The solution: Alter my CreatePost class to the following:
post.author = User.objects.get(pk=input.author_id)
Instead of:
post.author = input.author_id
I want to give users ten point each time they fill out one Survey , so i have this code above and now how to add the 10 point to self user after he fill out one
models.py :
class User(AbstractUser):
user_pic = models.ImageField(upload_to='img/',default="",null=True, blank=True)
coins = models.IntegerField(default=10)
def get_image(self):
if self.user_pic and hasattr(self.user_pic, 'url'):
return self.user_pic.url
else:
return '/path/to/default/image'
def give_coins(user, count):
user.coins = F('coins') + count
user.save(update_fields=('coins',))
user.refresh_from_db(fields=('coins',))
class Survey(models.Model):
name = models.CharField(max_length=200)
published_on = models.DateTimeField('Published DateTime')
def __str__(self):
return self.name
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.published_on <= now
was_published_recently.admin_order_field = 'published_on'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
class Participant(models.Model):
survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
participation_datetime = models.DateTimeField('Participation DateTime')
def __str__(self):
return "Participant "+str(self.participation_datetime)
class Question(models.Model):
survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
question_text = models.CharField(max_length=200)
created_on = models.DateTimeField('Creation DateTime')
def __str__(self):
return self.question_text
views.py :
#register.inclusion_tag('survey/survey_details.html', takes_context=True)
def survey_details(context, survey_id):
survey = Survey.objects.get(id=survey_id)
return {'survey': survey}
#require_http_methods(["POST"])
def submit_survey(request):
form_data = request.POST.copy()
form_items = list(form_data.items())
print("form_items", form_items)
form_items.pop(0) # the first element is the csrf token. Therefore omit it.
survey = None
for item in form_items:
# Here in 'choice/3', '3' is '<choice_id>'.
choice_str, choice_id = item
choice_id = int(choice_id.split('/')[1])
choice = Choice.objects.get(id=choice_id)
if survey is None:
survey = choice.question.survey
choice.votes = choice.votes + 1
choice.save()
if survey is not None:
participant = Participant(survey=survey, participation_datetime=timezone.now())
participant.save()
return redirect('/submit_success/')
so what i must to do if i want to add 10 point to user after he complete one survey
If submit_survey is a call that requires authentication the user will be present on the request request.user.
Add the coins by adding request.user.give_coins(count=10) to the submit_query method.
you have 2 way
work with event driven tools(maybe hard but principled)
set give_coin befor participant.save() on submit_survey
anyway I din't notice, coin is on your absUser model but your Participant has nothing to do with it or relations
I am facing a strange problem while implementing ChoiceField and UpdateView in django. I have made a small clip showing the problem that I am facing. Please watch it with subtitles/cc enabled. It will give an idea about the problem I am facing. https://youtu.be/M36TnlJvrZs. The problem goes like this.....
During CreateView, I set the 'gender' ChoiceField as 'Female'. But in UpdateView it pre-populates the 'gender' ChoiceField as Male.
However, The ListView renders the 'gender' field properly as 'Female'.
And strangely, the django admin panel, displays no value at all for the 'gender' field.
Here are all the codes:
models.py:
from django.db import models
from django.core.urlresolvers import reverse
gender_choices = (('Male', 'Male'), ('Female', 'Female'))
class Birth(models.Model):
full_name = models.CharField(max_length = 100)
gender = models.CharField(max_length=6, choices=gender_choices)
date_of_birth = models.DateField()
place_of_birth = models.CharField(max_length = 50)
mother_name = models.CharField(max_length = 50)
father_name = models.CharField(max_length = 50)
address_at_time_of_birth = models.TextField(max_length = 500)
permanent_address = models.TextField(max_length = 500)
registration_no = models.CharField(max_length = 50)
remarks = models.CharField(max_length = 200)
registration_date = models.DateField()
issue_date = models.DateField()
def get_absolute_url(self):
return reverse('birth:birth_update', kwargs={'pk':self.pk})
#return reverse('birth:birth_home')
def __str__(self):
return self.full_name
forms.py:
from django import forms
from .models import *
class BirthForm(forms.ModelForm):
full_name = forms.CharField()
gender = forms.ChoiceField(choices = gender_choices, widget=forms.Select())
date_of_birth = forms.DateField(widget = forms.DateInput(attrs = {'placeholder':'DD/MM/YYYY'}))
place_of_birth = forms.CharField()
mother_name = forms.CharField()
father_name = forms.CharField()
address_at_time_of_birth = forms.CharField(widget = forms.Textarea())
permanent_address = forms.CharField(widget = forms.Textarea())
registration_no = forms.CharField(required = False)
registration_date = forms.DateField(required = False, widget = forms.DateInput(attrs = {'placeholder':'DD/MM/YYYY'}))
remarks = forms.CharField(required = False)
issue_date = forms.DateField(required = False, widget = forms.DateInput(attrs = {'placeholder':'DD/MM/YYYY'}))
class Meta:
model = Birth
fields = '__all__'
views.py:
from django.views.generic import ListView, CreateView, UpdateView
from .models import *
from .forms import *
from datetime import date
class BirthHome(ListView):
template_name = 'birth/birth_home.html'
model = Birth
context_object_name = 'birth_objects'
paginate_by = 20
def get_queryset(self):
return Birth.objects.all().order_by('-id')
class NewBirth(CreateView):
model = Birth
form_class = BirthForm
#fields = '__all__'
template_name = 'birth/birth_add.html'
def form_valid(self, form):
obj = form.save(commit = False)
if not obj.registration_date:
obj.registration_date = date.today()
if not obj.issue_date:
obj.issue_date = date.today()
if not (date(1900, 1, 1) <= obj.date_of_birth <= date.today()):
form.add_error('date_of_birth', 'Please enter a valid date')
return super(NewBirth, self).form_invalid(form)
obj.full_name = obj.full_name.upper()
obj.gender = obj.gender.upper()
obj.place_of_birth = obj.place_of_birth.upper()
obj.mother_name = obj.mother_name.upper()
obj.father_name = obj.father_name.upper()
obj.address_at_time_of_birth = obj.address_at_time_of_birth.upper()
obj.permanent_address = obj.permanent_address.upper()
if obj.remarks:
obj.remarks = obj.remarks.upper()
self.object = form.save()
return super(NewBirth, self).form_valid(form)
class BirthUpdate(UpdateView):
model = Birth
form_class = BirthForm
template_name = 'birth/birth_update.html'
def form_valid(self, form):
obj = form.save(commit = False)
if not obj.registration_date:
obj.registration_date = date.today()
if not obj.issue_date:
obj.issue_date = date.today()
if not (date(1900, 1, 1) <= obj.date_of_birth <= date.today()):
form.add_error('date_of_birth', 'Please enter a valid date')
return super(BirthUpdate, self).form_invalid(form)
obj.full_name = obj.full_name.upper()
obj.gender = obj.gender.upper()
obj.place_of_birth = obj.place_of_birth.upper()
obj.mother_name = obj.mother_name.upper()
obj.father_name = obj.father_name.upper()
obj.address_at_time_of_birth = obj.address_at_time_of_birth.upper()
obj.permanent_address = obj.permanent_address.upper()
if obj.remarks:
obj.remarks = obj.remarks.upper()
self.object = form.save()
return super(BirthUpdate, self).form_valid(form)
I searched a lot and experimented a lot as well, but to no avail. Seriously need help. Also if this approach is not correct, what should be the correct working approach??
Solved!
So after lots of experimenting, I realized what the problem was!! It was in models.py file:
Since, I was converting all my inputs to uppercase, the 'choices' tuple also needed to have the values in uppercase. Initially the gender_choices tuple read like this:
gender_choices = (('Male', 'Male'), ('Female', 'Female'))
And in my views, I was making the gender as uppercase, thus causing mis-match in the declared tuple data and form data.
So, I changed the tuple to this:
gender_choices = (('MALE', 'MALE'), ('FEMALE', 'FEMALE'))
Works like a Charm!! Cheers.... And thanx for all the help and suggestions. Any feedback is always welcome :)
I have been working on a project in which I have to point out the expenses that the workers of a company have.
For this I have created two models, workers and expenses, in which expenses has a foreign key to workers, in the field: "nomTreballador".
When I try to save it in the db I get the error: "Cannot assign "u'Joan Manel'": "despesa.nomTreballador" must be a "treballador" instance."
My models.py:
from __future__ import unicode_literals
from django.db import models
from django.core.validators import RegexValidator
KILOMETRATGE = 'KM'
DINAR = 'DIN'
AUTOPISTA = 'AP'
MANTENIMENTPC = 'PC'
GASTOS = (
(KILOMETRATGE, 'Kilometres'),
(DINAR, 'Dinar'),
(AUTOPISTA, 'Autopista peatge'),
(MANTENIMENTPC, 'Manteniment de pc')
)
NIF = 'NIF'
NIE = 'NIE'
DNI = 'DNI'
TIPUSDOC = (
(DNI, 'DNI'),
(NIF, 'NIF'),
(NIE, 'NIE')
)
class treballador(models.Model):
nom = models.CharField(max_length=150, null=False, unique=True)
cognom = models.CharField(max_length=150, null=False)
tipusDocID = models.CharField(max_length=3, choices=TIPUSDOC, null=False)
docId = models.CharField(max_length=9, null=False)
tlf_regex = RegexValidator(regex=r'^\d{9,9}$',message="Phone number must be entered in the format: '+999999999'. Up to 9 digits allowed.")
tlf = models.CharField(validators=[tlf_regex], blank=True, max_length=9) # validators should be a list
correu = models.EmailField(max_length=254)
ciutat = models.CharField(max_length=150)
dataDAlta = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return unicode(self.nom) or 'u'
class despesa(models.Model):
nomTreballador = models.ForeignKey(treballador, to_field='nom')
tipusDeGast = models.CharField(max_length=3, choices=GASTOS)
quantia = models.DecimalField(max_digits=5, decimal_places=2)
data = models.DateTimeField()
def __unicode__(self):
return unicode(self.nomTreballador) or 'u'
My forms.py:
from django import forms
from functools import partial
from .models import despesa, treballador
DateInput = partial(forms.DateInput, {'class':'datepicker'})
class desModelForm(forms.ModelForm):
data = forms.DateField(widget=DateInput(format='%d/%m/%Y'), label="Data de la despesa", input_formats=['%d/%m/%Y'])
iquery = treballador.objects.values_list('nom', flat=True).distinct()
iquery_choices = [('','None')] + [(treballador,treballador) for treballador in iquery]
nomTreballador = forms.ChoiceField(choices=iquery_choices)
class Meta:
model= despesa
fields= ["nomTreballador","tipusDeGast","quantia","data"]
def clean_despesa(self):
despeses = self.cleaned_data.get("tipusDeGast")
return despeses
def clean_date(self):
date = self.cleaned_data.get("data")
return date
def clean_quantia(self):
quantia = self.cleaned_data.get("quantia")
return quantia
def clean_nom(self):
nomTreballador = self.cleaned_data.get("nomTreballador")
return nomTreballador
My views.py:
from django.shortcuts import render
from .forms import desModelForm, treballadorForm
from .models import treballador, despesa
def home(request):
form = desModelForm(request.POST or None)
context = {
"gast_form": form
}
if form.is_valid():
desp = form.save(commit=False)
desp.save()
return render(request, "imputacioDespeses.html", context)
I've tried solutions of similar questions but I have not managed to solve it
Thank you!!
You are getting this error because you are passing a text string to be used as the nomTreballador foreign key, while you should be passing a treballador instance.
It looks like you're trying to restrict the available choices to a set of distinct trebelladors by using a forms.ChoiceField, but a better way to do this with a ModelForm is to change the queryset attribute of the nomTreballador field. You do this in the form's init method:
self.fields['nomTreballador'].queryset = treballador.objects.all().distinct()
Also you should check the clean methods you've implemented because not all of them map to an existing field.
I am trying to filter a form selection so that a user can only select players from certain competitions. I have changed the _init_ function in the form as follows but nothing changes
forms.py
from django.forms import ModelForm
from matchdaycentremodel.models import FantasyTeam
from playerteamstats.models import Player
class FantasySeasonForm(ModelForm):
class Meta:
model = FantasyTeam
def _init_(self,*args,**kwargs):
super(FantasySeasonForm,self)._init_(**kwargs)
self.fields['player1'].queryset = playerteamstats.models.Player.objects.filter(team__competition__pk=2)
The relevant models are..
models.py (playerteamstats)
class Competition(models.Model):
COMP_ID = models.AutoField(primary_key=True)
season = models.ForeignKey(Season) #Foreign Key
competition_id = models.IntegerField()
competition_name = models.CharField(max_length=200)
competition_code = models.CharField(max_length=6)
def __str__(self):
return '%s (%s)' % (self.competition_name, self.season.season_id) #e.g. 'English Barclays Premier League (2014)'
class Team(models.Model):
team_id = models.IntegerField(primary_key=True)
competition = models.ForeignKey(Competition) #Foreign Key
team_name = models.CharField(max_length=200)
def __str__(self):
return self.team_name
class Player(models.Model):
player_id = models.IntegerField(primary_key=True)
team = models.ForeignKey(Team) #Foreign Key
player_name = models.CharField(max_length=140)
def __str__(self):
return self.player_name
models.py (matchdaycentremodel)
class FantasyTeam(models.Model):
FANTASY_TEAM_ID = models.AutoField(primary_key=True)
player1 = models.ForeignKey(Player, related_name='player1')
player2 = models.ForeignKey(Player, related_name='player2')
player3 = models.ForeignKey(Player, related_name='player3')
views.py
#login_required
def entry(request):
fantasyTeamForm = FantasySeasonForm() #Form to store each player in the fantasy team
if request.method == 'POST':
fantasyTeamForm = FantasySeasonForm(request.POST or None)
fantasyTeamForm.fields
if fantasyTeamForm.is_valid():
fantasyTeamForm.save()
return HttpResponseRedirect('/season/entrysuccess') #page on success
args = {}
args.update(csrf(request))
args['form'] = fantasyTeamForm
return render_to_response('entry.html', args, context_instance=RequestContext(request))
How do I filter the form's player1 so that it can only be selected from a certain competition?
Your init is defined as def _init_ whereas it should be def __init__ (double underscores)
Also, as crhodes mentions, you should be doing something like:
self.fields['player1'].queryset = Player.objects.filter(team__competition_id=2)
The reason this was not raising an exception was, these lines of code were never executed.
If your import statements are correct, should
self.fields['player1'].queryset = playerteamstats.models.Player.objects.filter(team__competition__pk=2)
not be
self.fields['player1'].queryset = Player.objects.filter(team__competition__pk=2)