Django 1.5 saving form issue, value always null - django

i'm having some trouble with forms in django 1.5.
i'm trying to write a form that saves new comments on my database.
But it doesn't matter what i write in the comment textspace, it's always considered null
this is my model
class Comment(BaseModel):
auction_event = models.ForeignKey(AuctionEvent, related_name='comments')
commenter = models.ForeignKey(User, related_name='comments')
comment = models.CharField(max_length=200, default='commento', null=True, blank=True)
def __unicode__(self):
return u'Placed on %s by %s' % (self.auction_event.item.title, self.commenter.username)
this is the form
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['comment']
def __init__(self, data=None, auction_event=None, commenter=None, *args, **kwargs):
self.auction_event = auction_event
self.commenter = commenter
super(CommentForm, self).__init__(data, *args, **kwargs)
def clean_comment(self):
cleaned_data = self.cleaned_data
cleaned_comment = cleaned_data.get('comment',Decimal('0.00'))
def clean(self):
cleaned_data = self.cleaned_data
current_time = timezone.now()
if current_time > self.auction_event.end_time:
raise ValidationError('This auction event has expired.')
return cleaned_data
def save(self, force_insert=False, force_update=False, commit=False):
comment = super(CommentForm, self).save(commit=False)
comment.auction_event = self.auction_event
comment.commenter = self.commenter
comment.save()
self.auction_event.save()
return comment
and in the end this is my view
#login_required
def view_comment_history(request, auction_event_id):
try:
auction_event = AuctionEvent.objects.get(pk=auction_event_id)
except AuctionEvent.DoesNotExist:
raise Http404
comments = auction_event.comments.all()
if request.method == 'POST':
form = CommentForm(data=request.POST, auction_event=auction_event, commenter=request.user.user,)
if form.is_valid():
comments = form.save()
return HttpResponseRedirect(request.get_full_path())
else:
form = CommentForm()
return render_to_response('lebay/view_comment_history.html', {
'auction_event': auction_event,
'form': form,
'comments': comments,
}, context_instance=RequestContext(request))
anyone knows why?

You need to return your cleaned comment.
def clean_comment(self):
cleaned_data = self.cleaned_data
cleaned_comment = cleaned_data.get('comment',Decimal('0.00'))
return cleaned_comment

Related

How do i make update function in Django

My project is a discussion forum using Django and here are my create and update functions. The method of update_post should provide update functionality but every time I try to update a post it adds a new post. How can I update a resource?
#login_required
def create_post(request):
context = {}
form = PostForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
print("\n\n its valid")
author = Author.objects.get(user=request.user)
new_post = form.save(commit=False)
new_post.user = author
new_post.save()
form.save_m2m()
return redirect("home")
context.update({
"form": form,
"title": "Create New Post"
})
return render(request, "create_post.html", context)
#login_required
def update_post(request):
context = {}
author = Author.objects.get(user=request.user)
form = PostForm(request.POST , instance=author)
if request.method == "POST":
if form.is_valid():
print("\n\n its valid")
new_post = form.save(commit=False)
# new_post.user = author
new_post.save()
form.save_m2m()
return redirect("home")
context.update({
"form": form,
"title": "UpdatePost",
})
return render(request, "update_post.html", context)
In model total there are 4 classes Post , comment , reply and category and this is Post -
class Post(models.Model):
title = models.CharField(max_length=400)
slug = models.SlugField(max_length=400, unique=True, blank=True)
user = models.ForeignKey(Author, on_delete=models.CASCADE)
content = HTMLField()
categories = models.ManyToManyField(Category)
date = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=True)
hit_count_generic = GenericRelation(HitCount, object_id_field='object_pk',
related_query_name='hit_count_generic_relation'
)
tags = TaggableManager()
comments = models.ManyToManyField(Comment, blank=True)
closed = models.BooleanField(default=False)
state = models.CharField(max_length=40, default="zero")
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
def __str__(self):
return self.title
def get_url(self):
return reverse("detail", kwargs={
"slug":self.slug
})
#property
def num_comments(self):
return self.comments.count()
#property
def last_reply(self):
return self.comments.latest("date")
form = PostForm(request.POST , instance=author)
instance feels like it should be passed an instance of Post instead of an instance of Author. I assume that PostForm is a pretty standard ModelForm with model = Post in the Meta.

MultiValueDictKeyError hen adding lines with inlineformset

I am trying to add more lines on the inline formset factory using the same methodology that I used before on a formset factory but is getting an error:
MultiValueDictKeyError form-TOTAL_FORMS'
models.py:
class ttransactions(models.Model):
transaction_type = models.CharField(max_length=10, choices=tx_choices)
description = models.CharField(max_length=50, null=False, blank=False, default='Description')
transaction_date = models.DateField(default=datetime.today, db_index=True)
company = models.ForeignKey(tcompany, on_delete=models.PROTECT, db_index=True)
def __str__(self):
return self.description
class ttransaction_lines(models.Model):
transaction = models.ForeignKey(ttransactions, on_delete=models.PROTECT, db_index=True)
sequence = models.IntegerField()
transaction_type = models.CharField(max_length=6, choices=debit_credit)
ledger_account = models.ForeignKey(tledger_account, on_delete=models.PROTECT, db_index=True)
amount = models.DecimalField(max_digits=14, decimal_places=2, default=0.0)
vat_amount = models.DecimalField(max_digits=14, decimal_places=2, default=0.0)
vat_code = models.ForeignKey(tvat, on_delete=models.PROTECT, blank=True, null=True)
quantity = models.IntegerField(blank=True, null=True)
posted = models.BooleanField(default=True)
forms.py:
class TransactionsForm(forms.ModelForm):
transaction_date = forms.DateField(widget=forms.SelectDateWidget(years=year_range), initial=datetime.today)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(TransactionsForm, self).__init__(*args, **kwargs)
class Meta:
model = ttransactions
fields = ['description',
'transaction_date']
class TransactionLinesForm(forms.ModelForm):
class Meta:
model = ttransaction_lines
fields = ['transaction_type', 'ledger_account', 'amount']
class BaseTransactionLinesFormSet(BaseModelFormSet):
def clean(self):
super(BaseTransactionLinesFormSet, self).clean()
# Check errors dictionary first, if there are any error, no point in validating further
if any(self.errors):
return
balance = 0
for form in self.forms:
if form.cleaned_data['DELETE'] == True or form.cleaned_data['DELETE'] == '':
continue
if form.cleaned_data['transaction_type']=='Debit':
balance = balance + form.cleaned_data['amount']
else:
balance = balance - form.cleaned_data['amount']
if balance != 0:
message = 'Transactions not balanced (excluding deleting lines)'
raise forms.ValidationError(message)
TransactionLineFormset = inlineformset_factory(ttransactions,
ttransaction_lines,
form=TransactionLinesForm,
can_order=True, can_delete=True)
views.py
class JournalCreateView(LoginRequiredMixin, CreateView):
template_name = 'accounting/journal.html'
model = ttransactions
formset = TransactionLineFormset
form_class = TransactionsForm
success_url = '/accounting/transaction_list'
def get_form_kwargs(self):
kwargs = super(JournalCreateView, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = TransactionLineFormset(queryset=ttransaction_lines.objects.none())
formset.form.base_fields['ledger_account'].queryset = \
tledger_account.objects.filter(company=request.user.current_company)
return self.render_to_response(
self.get_context_data(form=form, formset=formset))
def post(self, request, *args, **kwargs):
extra_forms = 1
if 'additems' in request.POST and request.POST['additems'] == 'true':
formset_dictionary_copy = self.request.POST.copy()
formset_dictionary_copy['form-TOTAL_FORMS'] = \
int(formset_dictionary_copy['form-TOTAL_FORMS']) + extra_forms
formset = TransactionLineFormSet(formset_dictionary_copy)
return self.render_to_response(
self.get_context_data(form=form,
formset=formset))
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = TransactionLineFormset(self.request.POST)
if (form.is_valid() and formset.is_valid()):
return self.form_valid(form, formset)
else:
return self.form_invalid(form, formset)
def form_valid(self, form, formset):
form.instance.company = self.request.user.current_company
self.object = form.save()
sequence = 1
for line in formset:
line.instance.sequence = sequence
sequence += 1
formset.instance = self.object
formset.save()
return super().form_valid(form)
def form_invalid(self, form, formset):
return self.render_to_response(
self.get_context_data(form=form,
formset=formset))
I get the error on the line that dictionary copy line. The code for adding the line is added in the post function. I am not sure if that is the correct place to add this code. Help will be appreciated.
This error occurs if the form submitted is missing the key.
The .get() method allows for a default when accessing a missing key in a dict.
formset_dictionary_copy['form-TOTAL_FORMS'] = \
int(formset_dictionary_copy.get('form-TOTAL_FORMS', 1)) + extra_forms
It appears that, the formset is not getting all it's hidden values or a different form is submitted.
I would consider a frontend solution or sending a single initial formset with the add button values.
A frontend / js example:
https://www.brennantymrak.com/articles/django-dynamic-formsets-javascript

UNIQUE constraint failed: auth_user.username while updating user info

I am trying to give a user the option to change his/her first/last name through a ModelForm. When I press submit, I get hit with the UNIQUE constraint failed: auth_user.username error. Here are my codes:
students/forms.py:
class EditProfileForm(UserChangeForm):
def clean_password(self):
# Overriding the default method because I dont want user to change
# password
pass
class Meta:
model = User
fields = (
'first_name',
'last_name',
)
students/views.py:
User = get_user_model()
def student_profile_view(request, slug):
if request.method == 'GET':
# forms
edit_name_form = EditProfileForm(instance=request.user)
context = {
'edit_name_form': edit_name_form,
}
return render(request, "students/profile.html", context)
class ChangeNameView(SuccessMessageMixin, UpdateView):
template_name = 'students/edit_profile.html'
model = User
form_class = EditProfileForm
success_message = "Your name has been updated"
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
form.instance.student_profile = StudentProfile.objects.get(slug=request.user.student_profile.slug)
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
"""If the form is valid, save the associated model."""
form.instance.username = self.request.user
self.object = form.save(commit=False)
return super().form_valid(form)
def get_success_url(self):
return reverse('students:student_profile_view', kwargs={'slug': self.object.student_profile.slug})
also fyi, User model is foreign key with StudentProfile.
students/models.py:
class StudentProfile(models.Model):
user = models.OneToOneField(User, related_name='student_profile', on_delete=models.CASCADE)
slug = models.SlugField(blank=True, unique=True)
avatar = models.ImageField(upload_to='student_profile/', null=True, blank=True)
description = models.CharField(max_length=120, null=True, blank=True)
objects = models.Manager()
def __str__(self):
return self.user.username
def get_absolute_url(self):
return reverse("students:student_profile_view", kwargs={"slug": self.slug})
I am pretty new to class based view so maybe I'm doing something wrong there?
I assume you do not have the user within the form so you need the form
def get_context_data (self, *args, **kwargs)
ctx = super().get_context_data(*args, **kwargs)
if self.request.method == 'POST':
ctx['form'] = EditProfileForm(instance=self.request.user)
and remove def form_valid()

Form not saved in database by POST request in django view

My form was working fine but suddenly it stops working and I'm stuck here, help me please!
When I prints form.errors in case of form not valid then it prints
user is a required field.
models.py
class TarWithDocker(models.Model):
name = models.CharField(max_length=255)
user = models.ForeignKey(User, related_name='deployments')
slug = AutoSlugField(populate_from='name', unique=True, name='slug')
archive = models.FileField(upload_to='archives', name='archive')
created_at = models.DateTimeField(default=timezone.now, editable=False)
class Meta:
ordering = ['-created_at']
views.py
class AwdDeployment(LoginRequiredMixin, CreateView):
template_name = 'deployments/awdDeployment.html'
def get(self, request, *args, **kwargs):
return render(request, 'deployments/awdDeployment.html', {})
def post(self, request, *args, **kwargs):
if request.method == 'POST':
form = AwdDeploymentForm(request.POST, request.FILES)
if form.is_valid():
deployment = TarWithDocker()
deployment.name = form.cleaned_data['name']
deployment.user = self.request.user
deployment.archive = form.cleaned_data['archive']
deployment.save()
return HttpResponse("Submitted")
else:
print("not saved")
else:
print("something happnes wrong")
form = AwdDeploymentForm()
return HttpResponseRedirect(reverse('users:deployments:awd'))
You have user in request, but may be not in post data
May be it help you:
post_data = request.POST.copy()
post_data.update({'user': request.user.pk})
form = AwdDeploymentForm(post_data, request.FILES)

Django UpdateView with related model

I have the following situation and I don't know how to do an update:
#models.py
class Task(models.Model):
creation_date = models.DateField(
default=None,
)
name = models.CharField(
max_length=255,
)
description = models.TextField(
max_length=500,
blank=True,
null=True,
)
class TaskDetails(models.Model):
PEND = 1
COMP = 2
TASK_STATUS = (
(PEND, 'pending'),
(COMP, 'completed'),
)
task = models.OneToOneField(
Task,
primary_key=True,
on_delete=models.CASCADE
)
solution = models.CharField(
max_length=255,
)
due_date = models.DateField(
null=True,
default=None,
blank=True,
)
status = models.PositiveSmallIntegerField(
default=1,
choices=TASK_STATUS,
)
And now my view
#views.py
class TaskUpdate(UpdateView):
model = Task
second_model = TaskDetails
form_class = TaskForm
second_form_class = TaskDetailsForm
pk_url_kwarg = 'task_id'
def get_context_data(self, **kwargs):
context = super(TaskUpdate, self).get_context_data(**kwargs)
if self.request.method == 'POST':
details_form = self.second_form_class(self.request.POST, prefix='details')
else:
details_object = self.second_model.objects.get(pk=self.kwargs.get(self.pk_url_kwarg))
details_form = self.second_form_class(instance=details_object, prefix='details')
context['details_form'] = details_form
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.form_class(request.POST)
details_form = self.second_form_class(request.POST, prefix='details')
if form.is_valid() and details_form.is_valid():
return self.form_valid(form, details_form)
else:
return self.form_invalid(form, details_form)
def form_valid(self, form, details_form):
form.instance.creation_date = datetime.now().date()
self.object = form.save()
details_form.instance.task = self.object
details_form.save()
return HttpResponseRedirect(self.success_url)
def form_invalid(self, form, details_form):
return self.render_to_response(self.get_context_data(form=form, details_form=details_form))
I also have the ModelForms: TaskForm and TaskDetailsForm. Not relevant here.
The 2 forms are displayed and submitted at once.
But instead of updating the existing record in Task and TaskDetails tables, it creates a new one in both tables
I think my problem is in form_valid. What should I put there?
Thanks a lot
In the post method forms are created without instance. You have to pass you instances there.
def post(self, request, *args, **kwargs):
# get current task
obj = self.get_object()
#initiate the task form with this object as instance
form = self.form_class(request.POST, instance=obj)
#get realted details object or None.
#I can't check if this string works, but it should.
details_obj = getattr(object, 'taskdetails', None)
#initiate the details_form with this details_object as instance
details_form = self.second_form_class(request.POST, prefix='details',
instance=details_obj)
if form.is_valid() and details_form.is_valid():
return self.form_valid(form, details_form)
else:
return self.form_invalid(form, details_form)
def form_valid(self, form, details_form):
#save object
obj = form.save(commit=False)
obj.creation_date = datetime.now().date()
obj.save()
#save details_object
details_obj = details_form.save(commit=False)
details_obj.task = obj
details_obj.save()
return HttpResponseRedirect(self.success_url)
I think this should work. You don't need the form_valid and form_invalid methods in this case,
def post(self, request, *args, **kwargs):
response = super(TaskUpdate, self).post(request, *args, **kwargs)
details_form = self.second_form_class(self.request.POST, prefix='details')
if details_form.is_valid():
task = self.get_object()
self.second_model.objects.filter(task=task)
.update(**details_form.cleaned_data)
return response
return render(request, self.template_name, {
'form': self.get_form(self.get_form_class()),
'details_form': details_form,
})
PS: put related_name=task_details for the OneToOneField and auto_now_add=True for the creation date of your task
Nevertheless, why don't you include the Task Details into task and stop using this OneToOneKey?