There is a form that is rendered by url
url(r'kredit/(?P<credit_slug>[-\.\w\d]+)/$', CreditDetail.as_view(), name='credit_detail'),
urls
url(r'kredit/(?P<credit_slug>[-\.\w\d]+)/$', CreditDetail.as_view(), name='credit_detail'),
url(r'kredit_request/$', CreditOnlineRequestView.as_view(), name='credit_request'),
The form is processed in the CreditOnlineRequestView(CreateView) view.
It is necessary to pull out the credit_slug from CreditDetail view in it (here the form was drawn)
views
class CreditDetail(FormView):
form_class = CreditPaymentForm
template_name = 'credits/credit_detail.html'
def get_initial(self):
initial = super(CreditDetail, self).get_initial()
initial['request'] = self.request
return initial
def get(self, *args, **kwargs):
request_form = CreditOnlineRequestForm(self.request.GET or None, prefix="request")
class CreditOnlineRequestView(CreateView):
form_class = CreditOnlineRequestForm
model = CreditOnlineRequest
template_name = 'credits/credit_listing.html'
prefix = 'request'
def form_valid(self, form, **kwargs):
credit_request = form.save(commit=False)
credit_request.credit = credit #???
return super(CreditOnlineRequestView, self).form_valid(form)
def form_invalid(self, form):
errors = dict([(k, v[0]) for k, v in form.errors.items()])
return errors
forms
class CreditOnlineRequestForm(forms.ModelForm):
class Meta:
model = CreditOnlineRequest
exclude = ['credit'] #this field must be define
def __init__(self, *args, **kwargs):
super(CreditOnlineRequestForm, self).__init__(*args, **kwargs)
#???
What are the options? I think, either through the cache, or through pulling out the previous page to do, but this is somehow not very humane, as for me. The best option, as for me, is to transfer the credit instance to a hidden form field in the CreditDetail view, but I don’t know how to do it yet.
The problem is that internally the form_valid function is doing the following:
def form_valid(self, form):
"""If the form is valid, save the associated model."""
self.object = form.save()
return super().form_valid(form)
So it does not matter what you're doing in your override that the super will try to save the form directly. You can solve your problem by doing:
def form_valid(self, form, **kwargs):
credit_request = form.save(commit=False)
credit_request.credit = credit
credit_request.save()
return HttpResponseRedirect(self.get_success_url())
urls
url(r'kredit_request/(?P<credit_slug>[-\.\w\d]+)/$', CreditOnlineRequestView.as_view(), name='credit_request'),
html
<form action="{% url 'credit_request' credit.slug %}" method="post">
view
class CreditOnlineRequestView(CreateView):
form_class = CreditOnlineRequestForm
model = CreditOnlineRequest
slug_url_kwarg = 'credit_slug'
prefix = 'request'
def post(self, request, *args, **kwargs):
form = self.get_form()
credit = Credit.objects.get(slug=kwargs.get('credit_slug'))
cache.set('credit_for_request', credit)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
credit_request = form.save(commit=False)
credit = cache.get('credit_for_request')
cache.clear()
credit_request.credit = credit
credit_request.save()
return HttpResponseRedirect(reverse('credit_detail', kwargs={'credit_slug': credit.slug}))
Related
I have two views, PostCreateView and PostUpdateView. They both route through the same html template, post_form.html. I want to create a Copy button that only appears if I am accessing a record through PostUpdateView. Pressing the Copy button will create a new record pre-filled with all the data from record that I was just on.
PostCreateView code:
class PostCreateView(LoginRequiredMixin, FormView):
template_name = 'trucking/post_form.html'
form_class = RecordForm
def form_valid(self, form):
form.instance.author = self.request.user
obj = form.save(commit=False)
obj.save()
messages.success(self.request, f'RECORD: {obj.container_no} was saved')
return super().form_valid(form)
def get_success_url(self):
if self.request.POST.get('Save_Exit'):
return reverse('close')
elif self.request.POST.get('Save'):
return reverse('post-create')
else:
return reverse('database')
PostUpdateView code:
class PostUpdateView(LoginRequiredMixin, UpdateView):
form_class = RecordForm
model = Post
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
history = Post.objects.filter(id = self.object.id).first().history.all().reverse()
data['history'] = get_status_changes(history)
return data
# checks to make sure the user is logged in
def form_valid(self, form):
form.instance.author = self.request.user
obj = form.save(commit=False)
messages.success(self.request, f'RECORD: {obj.container_no} was updated')
return super().form_valid(form)
def get_success_url(self):
if self.request.POST.get('Save_Exit'):
return reverse('close')
# return render(self.request, 'trucking/email_close.html')
elif self.request.POST.get('Save'):
return reverse('post-update', kwargs={'pk': self.object.id})
else:
return reverse('database')
Based on this post I tried creating a view like so:
def copy(request):
post = Post.objects.get(pk = request.users.post.id)
my_form = RecordForm(instance = post)
return render(request, 'trucking/post_form.html', {'form': my_form})
However, I get an error saying 'WSGIRequest' object has no attribute 'users'. I think that's not the only issue with this approach.
Should it be a part of PostUpdateView, since it takes the form information from an existing record? Should it be part of PostCreateView since you take the preexisting info and fill out a new form with it? Should it be a new view altogether? Any help is appreciated
I would like to get initial value on the following form but i get error : name 'user' is not defined. I don't know how to get user.username.
class InvoiceForm(ModelForm):
date = forms.DateField(widget=DateInput)
company = forms.CharField(initial={"company": user.username})
class Meta:
model = Invoice
fields = "__all__"
and the view to create the invoice is :
class InvoiceCreate(CreateView):
form_class = InvoiceForm
model = Invoice
template_name = "sales/invoice_form.html"
def get_success_url(self, request):
return reverse_lazy('invoice_details', kwargs={'pk' : self.object.pk})
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = InvoiceItemFormSet()
products = list(Product.objects.values())
return self.render_to_response(
self.get_context_data(form=form,formset=formset, products=products))
def post(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = InvoiceItemFormSet(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):
self.object = form.save()
formset.instance = self.object
formset.save()
try:
addmore = self.request.GET["addmore"]
if addmore == "True":
return redirect("update_invoice", pk=self.object.id)
except Exception as e:
pass
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form, formset):
return self.render_to_response(self.get_context_data(form=form, formset=formset))
I would like to get initial value on the following form but i get error : name 'user' is not defined. I don't know how to get user.username.
You had that error because there is no user at that point in the class level definition:
company = forms.CharField(initial={"company": user.username})
change to:
company = forms.CharField()
then is views.py add this method to InvoiceCreate class:
def get_initial(self):
return {"company": self.request.user}
i want to filter the comments by user and by post. would you like to tell me how can i filter the comment using get_context_data. i am getting this error with that code 'NewsDetailView' object has no attribute 'get_object_or_404' how can i solve this issue?
models.py
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
commentator = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.TextField(max_length=200)
created_on = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.article.title
views.py
class NewsDetailView(LoginRequiredMixin, DetailView):
model = Article
form_class = CommentForm
template_name = 'news/news_detail.html'
def get(self, request, *args, **kwargs):
self.object = self.get_object_or_404(User, username=self.kwargs.get('username'))
self.object = self.get_object_or_404(Article, pk=self.kwargs.get('pk'))
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = self.object
context['form'] = CommentForm()
return context
def post(self, request, *args, **kwargs):
if request.method == 'POST':
form = CommentForm(request.POST)
form.instance.article = Article.objects.get(
pk=self.kwargs.get('pk'))
form.instance.commentator = self.request.user
form.save()
return redirect('news:news-detail', pk=self.kwargs.get('pk'))
else:
return redirect('news:news-detail', pk=self.kwargs.get('pk'))
The NewsDetailView indeed has no get_object_or_404, so using self.get_object_or_404 does not make any sense. Furthermore it is not necessary at all.
You can obtain the Comments that belong to a user with the username with self.object.comment_set.filter(commentator__username=username)
You can further use the FormMixin [Django-doc] to avoid some boilerplate code to construct the form and redirect to the success url:
from django.urls import reverse
from django.views.generic.edit import FormMixin
class NewsDetailView(LoginRequiredMixin, FormMixin, DetailView):
model = Article
form_class = CommentForm
template_name = 'news/news_detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = self.object.comment_set.filter(
commentator__username=self.kwargs['username']
)
return context
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
form.instance.article_id = self.kwargs['pk']
form.instance.commentator = self.request.user
form.save()
return super().form_valid(form)
def form_invalid(self, form):
self.object = self.get_object()
return super().form_invalid(form)
def get_success_url(self):
return reverse('news:news-detail', kwargs={'pk': self.kwargs['pk']})
I am new in Django (1.9)
I have a NOT NULL constraint failed when I save my ModelForm and i don't understand why ...
I propose to the user a form to post a comment and the only field include in the form is "text", i want to set the excluded fields in my view after the validation and before save in database
Models.py :
class Commentaire(models.Model):
text = RichTextField()
pub_date = models.DateTimeField()
author = models.ForeignKey(User)
post = models.ForeignKey(Post)
publish = models.BooleanField()
def __str__(self):
return "/%s/%s" % (self.pub_date,self.author.username)
class Meta:
ordering = ["-pub_date"]
Forms.py :
class CommentaireForm(forms.ModelForm):
class Meta:
model = Commentaire
fields = ['text']
Views.py :
class PostDetail(View):
def get(self, request, *args, **kwargs):
view = PostDisplay.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = PostComment.as_view()
return view(request, *args, **kwargs)
class PostDisplay(DetailView):
model = Post
def get_context_data(self, **kwargs):
context = super(PostDisplay, self).get_context_data(**kwargs)
context['form'] = CommentaireForm()
return context
class PostComment(SingleObjectMixin, FormView):
template_name = 'blogengine/post_detail.html'
form_class = CommentaireForm
model = Post
def post(self, request, *args, **kwargs):
#if not request.user.is_authenticated():
# return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
"""
If the form is valid, redirect to the supplied URL
"""
form.save(commit=False)
form.post = self.object
form.author = self.request.user
form.pub_date = datetime.now()
form.publish = True
form.save()
return HttpResponseRedirect(self.get_success_url())
When Django save the form, i have this exception :
NOT NULL constraint failed: blogengine_commentaire.pub_date
The values i set for the excluded fields (author, post, pub_date) in "form_valid" are not taken into account, they seem to stay NULL
Could you explain me why because i am lost ?
Thanks
You need to rewrite form_valid method like that
def form_valid(self, form):
"""
If the form is valid, redirect to the supplied URL
"""
model_instance = form.save(commit=False)
model_instance.post = self.object
model_instance.author = self.request.user
model_instance.pub_date = datetime.now()
model_instance.publish = True
model_instance.save()
return HttpResponseRedirect(self.get_success_url())
Because save(commit=False) will return you an Post instance that you then need to populate and save.
I have following code where I want to update another table from an updateView. I am using following code however in method - form_valid its ending up creating new records and not updating the record being edited.
form.instance = form.save(commit=False)
super(AssetInfoUpdateView, self).form_valid(form)
I am using get_context_data method to add context data that I can use in form_valid to update the "other table".
Can anyone point me how to update the current record in form_valid or what I am doing wrong? I have included relevant code from my views.py - for what its worth similar approach in Create is working great, but I can't seem to figure out how to get Update to work.
class AssetInfoUpdateView(LoginRequiredMixin, UpdateView):
model = AssetInfo
context_object_name = 'asset_info'
success_url = '/asset/list/'
template_name = 'asset_mgmt/assetinfo_update.html'
form_class = AssetInfoUpdateForm
def get_context_data(self, **kwargs):
context = super(AssetInfoUpdateView, self).get_context_data(**kwargs)
alarm_dispatch_current = AlarmDispatchInfo.objects.filter(asset=self.object)
alarm_dispatch = AlarmNotificationReceiverInfo.objects.all()
context['alarm_dispatch_current'] = alarm_dispatch_current
context['alarm_dispatch'] = alarm_dispatch
return context
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super(AssetInfoUpdateView, self).get(request, *args, **kwargs)
def get_object(self, queryset=None):
obj = AssetInfo.objects.get(pk=self.kwargs['pk'])
return obj
def form_valid(self, form,request):
clean = form.cleaned_data
form.instance = form.save(commit=False)
super(AssetInfoUpdateView, self).form_valid(form)
....
...
def post(self, request, *args, **kwargs):
form = AssetInfoUpdateForm(request.POST)
if( form.is_valid() ):
return self.form_valid(form,request)
else:
return self.form_invalid(form)