django forms and __init__ function: unexpected keyword argument 'user' - django

I follow kenneth love crash course and I get unexpected error which I can not solve:
"init() got an unexpected keyword argument 'user'"
here is the form class:
class TalkTalkListForm(forms.ModelForm):
class Meta:
model = models.Talk
fields = ('talk_list',)
def __init__(self, *args, **kwargs):
super(TalkTalkListForm, self).__init__(*args, **kwargs)
self.fields['talk_list'].queryset = (
self.instance.talk_list.user.lists.all())
self.helper = FormHelper()
self.helper.layout = Layout(
'talk_list',
ButtonHolder(
Submit('move', 'Move', css_class='btn-primary')
)
)
and here is Talk model:
class Talk(models.Model):
ROOM_CHOICES = (
('BS1_O', 'BS1_O'),
('BS1TC', 'BS1TC'),
('BS3_O', 'BS3_O'),
('BS3TC', 'BS3TC'),
)
talk_list = models.ForeignKey(TalkList, related_name='talks')
name = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, blank=True)
when = models.DateTimeField()
room = models.CharField(max_length=5, choices=ROOM_CHOICES)
host = models.CharField(max_length=255)
talk_rating = models.IntegerField(blank=True, default=0)
speaker_rating = models.IntegerField(blank=True, default=0)
notes = models.TextField(blank=True, default='')
notes_html = models.TextField(blank=True, default='', editable=False)
class Meta:
ordering = ('when', 'room')
unique_together = ('talk_list', 'name')
def __unicode__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
self.notes_html = mistune.markdown(self.notes)
super(Talk, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('talks:talks:detail', kwargs={'slug': self.slug})
#property
def overall_rating(self):
if self.talk_rating and self.speaker_rating:
return (self.talk_rating + self.speaker_rating) / 2
return 0
I can see Talk has not got an attribute 'user' but I pass 'user' attribute to init somehow. Is it the reason of the problem ?
I know kwargs are named arguments so a named argument not expected will throw an error but I do not know how to get rid off the error.
UPDATE:
class TalkDetailView(views.LoginRequiredMixin, generic.DetailView):
http_method_names = ['get', 'post']
model = models.Talk
def get_queryset(self):
return self.model.objects.filter(talk_list__user=self.request.user)
def get_context_data(self, **kwargs):
context = super(TalkDetailView, self).get_context_data(**kwargs)
obj = context['object']
rating_form = forms.TalkRatingForm(self.request.POST or None,instance=obj)
list_form = forms.TalkTalkListForm(self.request.POST or None,instance=obj)
context.update({
'rating_form': rating_form,
'list_form': list_form
})
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
if 'save' in request.POST:
talk_form = forms.TalkRatingForm(request.POST or None,
instance=self.object)
if talk_form.is_valid():
talk_form.save()
if 'move' in request.POST:
list_form = forms.TalkTalkListForm(request.POST or None,
instance=self.object,
user=request.user)
if list_form.is_valid():
list_form.save()
return redirect(self.object)

I don't understand why do you put request.user in init if you have already filtered queryset by request.user == return self.model.objects.filter(talk_list__user=self.request.user)
Anyway ...
1) If you want access kwarg in form __init__ you should pop it before call super...
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', False)
# now you have removed it from kwargs and `super` call will work as expected
super(TalkTalkListForm, self).__init__(*args, **kwargs)
# do smth with `user`
2) If you want save request.user to object do smth like this in your view:
if list_form.is_valid():
obj = list_form.save()
obj.talk_list.user = request.user
obj.save()

Related

How to get rid of redundant requests ord django

class Post(models.Model):
cat_post = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True,null=True)
top_post = models.ForeignKey(TopicsCategory, on_delete=models.CASCADE, blank=True,null=True)
sub_post = models.ForeignKey(SubTopicsCategory, on_delete=models.CASCADE, blank=True,null=True)
class CreatePostView(CreateView):
model = Post
template_name = 'blog/create.html'
form_class = CreatePostForm
def get_context_data(self, *args, **kwards):
print(self.kwargs)
context = super(CreatePostView, self).get_context_data(**kwards)
context['btn'] = 'Add'
return context
def form_valid(self, form, *args, **kwargs):
if self.kwargs.get('category_slug') and len(self.kwargs) == 1:
category = Category.objects.get(slug=self.kwargs['category_slug'])
form.instance.cat_post = category
return super(CreatePostView, self).form_valid(form)
# передача в форму kwargs view
def get_form_kwargs(self):
kwargs = super(CreatePostView, self).get_form_kwargs()
kwargs.update({'view_kwargs': self.kwargs})
return kwargs
def get_success_url(self):
return reverse('topics_category_list', kwargs={'category_slug': self.kwargs['category_slug'], })
class CreatePostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['name', 'text', 'discussion']
# widgets = {
# 'cat_post': forms.HiddenInput(),
# }
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("view_kwargs")
super(CreatePostForm, self).__init__(*args, **kwargs)
def clean_name(self):
name = self.cleaned_data['name']
if self.request.get('category_slug') and len(self.request) == 1:
category = Category.objects.get(slug=self.request['category_slug'])
unique = Post.objects.filter(slug=slugify(self.cleaned_data['name']), cat_post=category.pk,discussion=False).exists()
if unique:
raise ValidationError(f'Post is not unique')
return name
**
I have duplicate sources in db here form_valid and clean_name.
How do I pass the form in the view form form_valid class instance that I got from the database to clean_name.
There will be posts for 2 models and requests will increase

Django key error "request" when using inlineformset

I created a Class Based(CreateView) with in inlineformset. I need to pass the request.user to the form to enable a filter function on one of the form fields. I however get a Key Error: request on the line:
self.request = kwargs.pop('request') in the def __init__(self, *args, **kwargs): of the form. Assistance will be appreciated.
Tips on my programming also welcome.
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.CASCADE, 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)
quantity = models.IntegerField(blank=True, null=True)
posted = models.BooleanField(default=True)
forms.py:
class TransactionLinesForm(forms.ModelForm):
class Meta:
model = ttransaction_lines
fields = ['transaction_type', 'ledger_account', 'amount']
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(TransactionLinesForm, self).__init__(*args, **kwargs)
user = self.request.user
current_company = user.current_company
self.fields['ledger_account'].queryset = tledger_account.objects.filter(
company=current_company)
TransactionLineFormset = inlineformset_factory(ttransactions,
ttransaction_lines,
# fields=['transaction_type', 'ledger_account', 'amount'] ,
form=TransactionLinesForm,
can_order=True, can_delete=True)
views.py:
class JournalCreateView(LoginRequiredMixin, CreateView):
template_name = 'accounting/journal.html'
model = ttransactions
transaction_lines_form = 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)
transaction_lines_form = TransactionLineFormset()
return self.render_to_response(
self.get_context_data(form=form, transaction_lines_form=transaction_lines_form))
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
transaction_lines_form = TransactionLinesFormSet(formset_dictionary_copy)
return self.render_to_response(
self.get_context_data(form=form,
transaction_lines_form=transaction_lines_form))
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
transaction_lines_form = TransactionLineFormset(self.request.POST)
if (form.is_valid() and transaction_lines_form.is_valid()):
return self.form_valid(form, transaction_lines_form)
else:
return self.form_invalid(form, transaction_lines_form)
def form_valid(self, form, transaction_lines_form):
form.instance.company = self.request.user.current_company
self.object = form.save()
sequence = 1
for line in transaction_lines_form:
line.instance.sequence = sequence
sequence += 1
transaction_lines_form.instance = self.object
transaction_lines_form.save()
return super().form_valid(form)
def form_invalid(self, form, transaction_lines_form):
return self.render_to_response(
self.get_context_data(form=form,
transaction_lines_form=transaction_lines_form))
Your form may be initialized at multiple places. It is difficult to find where the error happened without seeing the Traceback.
So, it is better to keep the filtering logic in the view rather than passing 'request' to form. Remove __init__ method in form and try the below code in the view
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
transaction_lines_form = TransactionLineFormset()
transaction_lines_form.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, transaction_lines_form=transaction_lines_form))

Generic UpdateView isn't working with slug

I'm pretty new to django.I am trying to update a post with generic UpdateView. But the post isn't updating after filling up the form.Im accessing the update view through slug url.
My model:
class Post(models.Model):
title = models.CharField(max_length=60)
post_body = models.TextField()
time_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete= models.CASCADE)
slug = models.SlugField(null=False,unique=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('postdetail', kwargs={'slug': self.slug})
def save(self,*args,**kwargs):
if not self.slug:
author_id = str(self.author.id)
self.slug = slugify(self.title +'-'+author_id)
return super().save(*args, **kwargs)
My view:
class postupdate(LoginRequiredMixin,UserPassesTestMixin,UpdateView):
model = Post
fields = ['title','post_body']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
else:
return False
My url:
path('post/<slug:slug>/updatepost/', postupdate.as_view(),name = 'updatepost'),
It seems the save() method is not getting called every time.
class Post(models.Model):
# rest of your code
def save(self, *args, **kwargs):
if not self.slug:
author_id = str(self.author.id)
self.slug = slugify(self.title + '-' + author_id)
return super().save(*args, **kwargs) # outside the `if...` clause

prevent sql duplicates by inline formset factory in django 3.0.5

i have a problem with inline formset factory in django 3.0.5. i have models like this:
class Resume(models.Model):
user = models.ForeignKey(User, verbose_name=_('User'), on_delete=models.CASCADE)
website = models.URLField(verbose_name=_('Web Site'), blank=True, null=True)
...
class Expertise(models.Model):
name = models.CharField(_('name'), max_length=100)
...
class ResumeExpertise(models.Model):
resume = models.ForeignKey(Resume, on_delete=models.CASCADE, related_name='resume_expertise')
expertise = models.OneToOneField(Expertise, on_delete=models.CASCADE, verbose_name=_('Expertise'), related_name='resume_expertise_item')
score = models.PositiveSmallIntegerField(_('Score'))
def __str__(self):
return self.expertise.name
in this case user must edit the form. i used inline formset factory. my forms.py:
class ResumeForm(forms.ModelForm):
class Meta:
model = Resume
fields = ('website',)
def __init__(self, *args, **kwargs):
super(ResumeForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = True
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-md-3 create-label'
self.helper.field_class = 'col-md-9'
self.helper.layout = Layout(
Div(
Field('website'),
Fieldset('Expertise',
Formset('expertise')),
HTML("<br>"),
ButtonHolder(Submit('submit', 'save')),
)
)
class ResumeExpertiseForm(forms.ModelForm):
class Meta:
model = ResumeExpertise
fields = ('expertise', 'score')
ResumeExpertiseFormSet = inlineformset_factory(Resume, ResumeExpertise, form=ResumeExpertiseForm, fields=['expertise', 'score'], extra=1, can_delete=True)
for views i used class based views like this:
class ResumeEdit(LoginRequiredMixin, UpdateView):
model = Resume
template_name = "user/resume_form.html"
form_class = ResumeForm
success_url = reverse_lazy('user:profile')
def get_object(self, queryset=None):
return Resume.objects.get(user=self.request.user)
def get_context_data(self, *args, **kwargs):
context = super(ResumeEdit, self).get_context_data(**kwargs)
context['title'] = _('Edit Resume')
if self.request.POST:
context['expertise'] = ResumeExpertiseFormSet(self.request.POST, instance=self.object)
else:
context['expertise'] = ResumeExpertiseFormSet(instance=self.object)
return context
def form_valid(self, form):
context = self.get_context_data()
expertise = context['expertise']
with transaction.atomic():
form.instance.user = self.request.user
self.object = form.save()
if expertise.is_valid():
expertise.instance = self.object
expertise.save()
return super(ResumeEdit, self).form_valid(form)
my problem is, when i load the ResumeEdit form in browser, debug_toolbar shows:
SELECT ••• FROM `user_expertise`
26 similar queries. Duplicated 26 times.
i'm new to inline formset factory and so confused. what i did wrong? is there any way to prevent this duplicats?

How do I get my Django generic view to work

Am I going about this the right way? Having never used 'generic views' I am tying to use Django's generic.UpdateView view. When I 'hit' the 'update' button on the form, I get an invalid form response with message 'Library with this Slide name already exists'
Grateful for any help.
View:
class Slideview(generic.UpdateView):
model = Library
template_name = 'app1/slide_update.html'
fields = ['slide_name', 'reference_value','esd',
'current_mean', 'counts_averaged', 'status']
context_object_name = 'qc_slide'
#def get_queryset(self):
#slide_id = self.kwargs['pk']
#return Library.objects.filter(slide_name=slide_id)
def get_success_url(self):
return reverse('Slideview', args=[self.kwargs['pk']])
def get_context_data(self, **kwargs):
context = super(Slideview, self).get_context_data(**kwargs)
#form = self.get_form(self.get_form_class())
#context['form'] = form
return context
def post(self, request, *args, **kwargs):
print("Im in post")
form = self.get_form(self.get_form_class())
if form.is_valid():
#Code will go here which will query a second model
#perform a series of math calculations and then
#return the updated information
self.object = self.get_object()
self.object.save()
return self.form_valid(form)
else:
print("Form not valid")
self.object = self.get_object()
return self.form_invalid(form)
Model:
class Library(models.Model):
slide_name = models.CharField(max_length=5, primary_key=True)
reference_value = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal(0))
esd = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal(0))
current_mean = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal(0))
counts_averaged = models.IntegerField(default=0)
status = models.CharField(max_length=9)
def __str__(self):
return self.slide_name