In my Django application, I want to subtract 1 "free_places" field in the "Event" model using the "EventDetailView" view where the form is located. Each time the form is OK (when the user subscribes to the event), the "free_places" field should decrease by 1.
I do not know why my code does not work.
My view:
class EventDetailView(DetailView, ModelFormMixin):
model = models.Event
form_class = forms.RegisterForm
context_object_name = 'event'
def get_success_url(self):
return reverse('events:list')
def get_initial(self):
return {'event': self.kwargs['pk']}
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
self.object = self.get_object()
self.object.free_places - 1
self.object.save()
return self.form_valid(form)
else:
return self.form_invalid(form)
Models:
class Event(models.Model):
title = models.CharField(max_length=500)
date = models.DateField()
text = models.TextField()
image = FilerImageField(null=True, blank=True)
flag = models.ForeignKey(Flag)
free_places = models.IntegerField()
class Meta:
ordering = ['-date']
def __str__(self):
return self.title
#property
def slug(self):
return slugify(self.title)
def get_absolute_url(self):
return reverse('events:detail', args=[self.slug, self.id])
def get_model_id(self):
return self.id
class Register(models.Model):
event = models.ForeignKey(Event)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
company = models.CharField(max_length=30, blank=True)
street = models.CharField(max_length=50, blank=True)
post_code = models.CharField(max_length=30, blank=True)
city = models.CharField(max_length=30, blank=True)
email = models.EmailField()
phone_number = models.IntegerField()
def __str__(self):
return self.first_name
def get_event_name(self):
return self.event
You need to assign the result of self.object.free_places - 1. At the moment you are not doing anything with it.
Change the line to either:
self.object.free_places -= 1
or
self.object.free_places = self.object.free_places - 1
The code is vulnerable to race conditions if multiple users submit the form at the same time. You can fix that by using F() objects.
from django.db.models import F
self.object.free_places = F('free_places') - 1
self.object.save()
Related
I have this view:
#login_required
def addmeal(request):
if request.method == 'POST':
form = addMeal(user=request.user, data=request.POST)
if form.is_valid():
form.save(request)
return redirect('food:index')
else:
form = addMeal(user=request.user)
return render(request,'addmeal.html',{'form':form})
and this form:
class addMeal(forms.Form):
name = forms.CharField(
max_length=40,
widget=forms.TextInput(attrs={'class':'form-control','placeholder':'نام وعده'})
)
foods = forms.ModelMultipleChoiceField(
queryset=Food.objects.none(),
widget=forms.SelectMultiple(attrs={'class':'form-control'})
)
def save(self,request):
data = self.cleaned_data
meal = Meals(name=data['name'],user=request.user,foods=data['foods'])
meal.save()
def __init__(self, user=None,*args, **kwargs, ):
super().__init__(*args, **kwargs)
if user is not None:
self.fields['foods'].queryset = Food.objects.filter(user=user)
class Meta:
model = Meals
my models.py:
from django.db import models
from django.contrib.auth.models import User
class Food(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
name = models.CharField(max_length=155,default='')
colorie = models.BigIntegerField(default=0)
carbohidrat = models.IntegerField(default=0)
cholestrol = models.IntegerField(default=0)
fat = models.IntegerField(default=0)
fiber = models.IntegerField(default=0)
protein = models.IntegerField(default=0)
saturatedfat = models.IntegerField(default=0)
def __str__(self):
return self.name
class Meals(models.Model):
name = models.CharField(max_length=20)
user = models.ForeignKey(User,on_delete=models.CASCADE)
foods = models.ManyToManyField(Food)
def __str__(self):
return self.name
class Diet(models.Model):
name = models.CharField(max_length=20)
user = models.ForeignKey(User,on_delete=models.CASCADE)
date = models.DateField(auto_now_add=True)
meals = models.ManyToManyField(Meals)
def __str__(self):
return self.name
when i run server and fill out form and press submit django give me error(Direct assignment to the forward side of a many-to-many set is prohibited. Use foods.set() instead.).
what should i do to fix it?
I've two model. I would like to save data from ForeignKey model. I'm created a modelform and save with my main foreignkey model. But I got this error ValueError at /c/customer/1/
Cannot assign "'1'": "BillingData.customer" must be a "CustomerData" instance.
I created Django model form and hocked up with view.
models.py file
class CustomerData(models.Model):
customer_name = models.CharField(max_length=100)
customer_no = models.CharField(max_length=100, default='', blank=True)
mobile_number = models.IntegerField()
alternative_phone = models.IntegerField(null=True, blank=True)
union_name = models.ForeignKey(UnionName, on_delete=models.SET_NULL, null=True)
word_name = models.ForeignKey(UnionWordName, on_delete=models.SET_NULL, null=True)
full_address = models.CharField(max_length=200, null=True, blank=True)
create_date = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s, Mobile: %s' % (self.customer_name, self.mobile_number)
def get_absolute_url(self):
return reverse('customer_data', kwargs={'pk': self.pk})
class BillingData(models.Model):
bill_no = models.CharField(max_length=100, default='', blank=True)
customer = models.ForeignKey(CustomerData, on_delete=models.CASCADE)
sales_person = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
customer_money = models.IntegerField()
create_date = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s %s' % (self.customer.customer_name, self.create_date.date())
def get_absolute_url(self):
return reverse('customers.views.BillingPage', kwargs={'pk': self.pk})
forms.py file
class BillCreateForms(forms.ModelForm):
bill_no = forms.CharField(max_length=100)
customer = forms.ChoiceField(choices=[(x.id, x.customer_name) for x in CustomerData.objects.all()])
customer_money = forms.IntegerField()
def save(self, commit=True):
instance = super(BillCreateForms, self).save(commit=False)
customer_pk = self.cleaned_data['customer']
instance.customer = CustomerData.objects.get(pk=customer_pk)
instance.save(commit)
return instance
class Meta:
model = BillingData
fields = ('bill_no', 'customer', 'customer_money',)
views.py file
class CustomerDataView(FormMixin, generic.DetailView):
model = CustomerData
form_class = BillCreateForms
template_name = "customers/customerdata_detail.html"
print(form_class)
success_url = '/c/'
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
I expect data save with foreignkey relation data. But doesn't save here.
You can't fix this problem in the save method, because the error happens before it gets that far.
You should be using a ModelChoiceField, not a ChoiceField. Not only would this fix the problem, it would also let you remove your entire save method.
customer = forms.ModelChoiceField(queryset=CustomerData.objects.all())
Change this line
instance.customer = CustomerData.objects.get(pk=customer_pk)
to
instance.customer_id = CustomerData.objects.get(pk=customer_pk).pk
Model:
class Blog(models.Model):
# ...
pass
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, null=True)
Set object
b = Blog.objects.get(id=1)
e = Entry.objects.get(id=234)
b.entry_set.add(e)
I want to use a field in the Profile model of a logged in user to restrict the queryset used in a Django class based view.
My models are:
# User profile info
class Profile(models.Model):
# Relationship Fields
user = models.OneToOneField(User, on_delete=models.CASCADE)
school = models.ForeignKey('eduly.School', default=1)
notes = models.TextField(max_length=500, blank=True)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
and
class School(models.Model):
# Fields
name = models.CharField(max_length=255)
address = models.TextField(max_length=500, blank=True)
email = models.CharField(max_length=30)
phone = models.CharField(max_length=15)
contactName = models.CharField(max_length=30)
slug = extension_fields.AutoSlugField(populate_from='name', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.slug
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('eduly_school_detail', args=(self.slug,))
def get_update_url(self):
return reverse('eduly_school_update', args=(self.slug,))
class Teacher(models.Model):
SCHOOL_ADMIN = 0
CLASS_ADMIN = 1
TASK_ADMIN = 2
ROLES = {
(SCHOOL_ADMIN, "School administrator"),
(CLASS_ADMIN, "Class administrator"),
(TASK_ADMIN, "Task administrator")
}
# Fields
name = models.CharField(max_length=255)
slug = extension_fields.AutoSlugField(populate_from='name', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
email = models.CharField(max_length=30)
roles = models.IntegerField("Role", choices=ROLES, default=1)
# Relationship Fields
school = models.ForeignKey('eduly.School', )
class Meta:
ordering = ('-created',)
def __str__(self):
return self.name
def __unicode__(self):
return u'%s' % self.slug
def get_absolute_url(self):
return reverse('eduly_teacher_detail', args=(self.slug,))
def get_update_url(self):
return reverse('eduly_teacher_update', args=(self.slug,))
The view whose queryset I am trying to restrict is:
#method_decorator(login_required, name='dispatch')
class TeacherListView(ListView):
model = Teacher
def get_queryset(self):
return Teacher.objects.filter(user=self.request.user)
But instead of return Teacher.objects.filter(user=self.request.user) I want to only list Teachers who have a school the same as the school in the logged in user's Profile.
Seems like this would work:
Teacher.objects.filter(school=self.request.user.profile.school)
I have 2 models in 1 form. in this form data can be changed.
For 1 model (Sloep_core) the content only have to update, this is working.
for the other model (Sloep_gegevens) the content normaly will update.
Only if the value 'sloepnaam' changed in the form for model 'Sloep_gegevens', the record for the model 'Sloep_gegevens' must enter a new record and not update the old one.
The save() must change from update to insert, but how??
I have tried to put soms code together (with some search actions). I come to the code below but now it is always a insert the code. Is someone have a idea to get it right?
model.py:
class Sloep_core(models.Model):
FSN_nummer = models.IntegerField(unique=True)
HT_nummer = models.IntegerField(unique=True, blank=True, null=True)
SRNL_nummer = models.IntegerField(blank=True, null=True)
sloep_type = models.CharField(max_length=128, blank=True)
werf = models.CharField(max_length=255, blank=True)
info = models.TextField(blank=True)
objects = SloepManager()
def __str__(self):
return str(self.FSN_nummer)
class Sloep_gegevens(models.Model):
sloep = models.ForeignKey(Sloep_core, on_delete=models.CASCADE, default='')
sloepnaam = models.CharField(max_length=128)
thuishaven = models.CharField(max_length=128, blank=True)
date = models.DateField(auto_now=True)
__original_sloepnaam = None
def __init__(self, *args, **kwargs):
super(Sloep_gegevens, self).__init__(*args, **kwargs)
self.__original_sloepnaam = self.sloepnaam
def save(self, force_insert=False, force_update=False, *args, **kwargs):
if self.sloepnaam != self.__original_sloepnaam:
# then do this
force_insert = True
else:
# do that
force_update = True
super(Sloep_gegevens, self).save(force_insert, force_update, *args, **kwargs)
self.__original_sloepnaam = self.sloepnaam
class Meta:
ordering = ["date"]
def __str__(self):
return self.sloepnaam
form.py:
class SloepGegevensForm(forms.ModelForm):
class Meta:
model = Sloep_gegevens
exclude = ['pk', 'sloep']
class SloepCoreForm(forms.ModelForm):
class Meta:
model = Sloep_core
exclude = ['pk', 'SRNL_nummer']
views.py:
def sloep_edit(request, pk):
sloep = Sloep_core.objects.get(pk=pk)
sloep_sg = Sloep_gegevens.objects.filter(sloep=pk).order_by('-date')[0]
if request.method == "POST":
formSG = SloepGegevensForm(request.POST)
formSC = SloepCoreForm(request.POST, instance=sloep)
if all([formSG.is_valid(), formSC.is_valid()]):
sloep = formSC.save()
SG = formSG.save(commit=False)
SG.sloep = sloep
SG.save()
return redirect('sloep_detail', pk=sloep.pk)
else:
formSG = SloepGegevensForm(instance=sloep_sg)
formSC = SloepCoreForm(instance=sloep)
return render(
request,
'sloepen/sloep_edit.html',
{'formSG': formSG, 'formSC': formSC,})
I found the answer for my problem. In the view I didn't give a pk with the SloepGegevensForm in the POST request.model.
I changed: formSG = SloepGegevensForm(request.POST)into formSG = SloepGegevensForm(request.POST, instance=sloep_sg)
This makes the save() working.
This code works perfectly, which is a User model with one to many relationship with UserRating model.
View:
def index(request):
user_list = User.objects.order_by('-userrating')[:5]
city_list = City.objects.order_by('-name')[:5]
context_dict = {"users": user_list, "cities" : city_list}
return render(request, "index.html", context_dict)
Models:
# this is model for user
class User(models.Model):
username = models.CharField(max_length=128, unique=True)
email = models.EmailField(max_length=128, unique=True)
profilepic = models.ImageField(null=True)
firstname = models.CharField(max_length=128, null=True)
secondname = models.CharField(max_length=128, null=True)
city = models.ForeignKey(City)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
# Uncomment if you don't want the slug to change every time the name changes
# if self.id is None:
# self.slug = slugify(self.name)
self.slug = slugify(self.username)
super(User, self).save(*args, **kwargs)
def __unicode__(self):
return self.username
#property
def avg_rating(self):
return self.userrating_set.all().aggregate(Avg('rating'))['rating__avg']
# this is the model for user ratings - one to many relationship with User
class UserRating(models.Model):
user = models.ForeignKey(User)
comment = models.CharField(max_length=500)
for_username = models.CharField(max_length=128)
rating = models.IntegerField(default=5)
def __unicode__(self):
return unicode(self.rating)
However, it breaks once I use Django's built in User model as below (User model with one to one relationship with a UserProfile model and a one to many relationship with UserRating)
# this is model for user
class UserProfile(models.Model):
user = models.OneToOneField(User)
profilepic = models.ImageField(blank=True)
city = models.ForeignKey(City)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.user.username)
super(User, self).save(*args, **kwargs)
def __unicode__(self):
return self.user.username
#property
def avg_rating(User):
return self.userrating_set.all().aggregate(Avg('rating'))['rating__avg']
# this is the model for user ratings - one to many relationship with User
class UserRating(models.Model):
user = models.ForeignKey(User)
comment = models.CharField(max_length=500)
for_username = models.CharField(max_length=128)
rating = models.IntegerField(default=5)
def __unicode__(self):
return unicode(self.rating)
it generates this error when adding a user profile via admin page:
super(type, obj): obj must be an instance or subtype of type
You must call the actual superclass in your super call; it is UserProfile, not User.
def save(self, *args, **kwargs):
self.slug = slugify(self.user.username)
super(UserProfile, self).save(*args, **kwargs)