How to pass argument from previous View to a Form? - python

Im trying to pass the "test" argument from this View to a Form:
class ListCreateFormView(CreateView):
template_name = 'armybuilder_list_create.html'
model = List
form_class = CreateListForm
def form_valid(self, form):
form.instance.author = self.request.user
self.test = Faction.objects.get(title="Blood Angels")
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy('add_unit_to_list', kwargs={'pk': self.object.pk, 'test': self.test.id})
To this View and Form:
class AddUnitsToListFormView(LoginRequiredMixin,CreateView):
model = SoldierToList
form_class = SoldierToListForm
template_name = 'armybuilder_add_unit_to_list.html'
def form_valid(self, form):
form.instance.author = self.request.user
form.instance.list_id = self.kwargs['pk']
return super().form_valid(form)
class SoldierToListForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# factions_obj = Faction.objects.get(pk=my_test)
self.fields['soldier'].queryset = Soldier.objects.filter(factions=4)
class Meta:
model = SoldierToList
fields = ('soldier',)
My urls:
urlpatterns = [
path('list/create', ListCreateFormView.as_view(), name='create_list'),
path('list/own/<int:pk>/<int:test>/addunit', AddUnitsToListFormView.as_view(), name='add_unit_to_list'),
]
Im hardcoding the value 4 in my form but I would like to use the argument test that I defined in the previous View ListCreateFormView, can you please tell me how to do it ?
Thanks

Related

how to use if in django class based view

i want to use if and i need to have a variable and that variable needs kwords
class ResetPassword(FormView):
template_name = 'reset_password.html'
form_class = ResetPasswordForm
def get_context_data(self, **kwargs):
context = super(ResetPassword, self).get_context_data(**kwargs)
context['uuid'] = kwargs.get('uuid')
context['base64'] = kwargs.get('base64')
return context
if (get_context_data['context']['uuid'] and get_context_data['context']['base64']) == (url_uuid and url_base64):
def form_valid(self, form):
user = User.objects.get(id= self.request.user.id)
user.set_password(form.cleaned_data['password'])
user.save()
return redirect('/login')

How to get requested user in clean function in django forms?

Well i want to get requested user in clean function of django forms but i'm unable to do that. I'm trying to get that by simply saying self.request.user , it works in views but not working in forms.py, anybody have an idea how to get requested user in djnago forms ?
forms.py
class KycModelForm(forms.ModelForm):
class Meta:
model = KycModel
fields = '__all__'
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(KycModelForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super().clean()
user = User.objects.get(username=self.request.user)
print(user)
views.py
class KycFormCreateView(CreateView):
form_class = KycModelForm
model = KycModel
template_name = "accounts/kyc/new_kyc.html"
def form_valid(self, form):
user_kyc = form.save(commit=False)
user_kyc.owner = self.request.user
user_kyc.save()
return super().form_valid(form)
You never construct a form with a request in the first place. You should pass this with:
class KycFormCreateView(CreateView):
form_class = KycModelForm
model = KycModel
template_name = 'accounts/kyc/new_kyc.html'
def get_form_kwargs(self, *args, **kwargs):
form_kwargs = super().get_form_kwargs(*args, **kwargs)
form_kwargs['request'] = self.request
return form_kwargs
def form_valid(self, form):
user_kyc = form.save(commit=False)
user_kyc.owner = self.request.user
user_kyc.save()
return super().form_valid(form)
In the clean function, you do not need to query for a user self.request.user is a user object, so you can work with self.request.user directly:
class KycModelForm(forms.ModelForm):
class Meta:
model = KycModel
fields = '__all__'
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(KycModelForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super().clean()
user = self.request.user
print(user)
return cleaned_data

Standardising get_success_url

For my classes PostCreateView and PostUpdateView I have the same get_success_url. Is there a way of standardising your get_success_url, I want to avoid writing the code twice?
def get_success_url(self):
return reverse('post-detail', args=[self.object.pk])
I was working through a tutorial. A limitation of the tutorial though was you were only shown how to load posts by using the posts primary key (https://rossdjangoawesomeapp2.herokuapp.com/post/6/). I modified the code in the tutorial so you could access posts using their title (https://rossdjangoawesomeapp2.herokuapp.com/post/another-test-please-let-it-work/). Which has resulted in me having duplicate code.
models.py
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now())
author = models.ForeignKey(User, on_delete=models.CASCADE)
url = models.SlugField(max_length=500, blank=True)
def save(self, *args, **kwargs):
self.url= slugify(self.title)
super().save(*args, **kwargs)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
views.py
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'content']
def get_success_url(self):
return reverse('post-detail', args=[self.object.pk])
def form_valid(self, form):
form.instance.author = self.request.user
# will save the form and redirect to the success_url
return super().form_valid(form)
class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Post
fields = ['title', 'content']
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
return False
def get_success_url(self):
return reverse('post-detail', args=[self.object.pk])
For my classes PostCreateView and PostUpdateView I have the same get_success_url. Is there a way of standardising your get_success_url, I want to avoid writing the code twice?
Yes, not writing it at all. If you do not specify a get_success_url, or success_url, Django will take the get_absolute_url of the object (so here the Post object). Hence if you do not specify it, then it will already redirect to the correct url, this is specified in the documentation for the get_success_url method [Django-doc]:
Determine the URL to redirect to when the form is successfully validated. Returns django.views.generic.edit.ModelFormMixin.success_url if it is provided; otherwise, attempts to use the get_absolute_url() of the object.
So we can remove the get_success_url methods:
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'content']
# no get_success_url
def form_valid(self, form):
form.instance.author = self.request.user
class PostUpdateView(LoginRequiredMixin, UpdateView):
model = Post
fields = ['title', 'content']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).filter(
author=self.request.user
)
# no get_success_url

How can i get the pk from a cloned model instance in form_valid to use in get_success_url in an UpdateView?

class DomainRegistrationItemUpdateView(UpdateView):
model = DomainRegistrationItem
form_class = DomainAddYearsForm
template_name = "add_years.html"
def get_context_data(self, *args, **kwargs):
context = super(DomainRegistrationItemUpdateView,
self).get_context_data(**kwargs)
# tld_ppy Top Level Domain Price Per Year
context['tld_ppy'] = TLD.objects.get(
name='.%s' % (self.kwargs['domain_name'].split('.')[1])).yearly_price
return context
def get_object(self, queryset=None):
return DomainRegistrationItem.objects.get(domain=self.kwargs['domain_name'], purchased=True)
def get_success_url(self):
split_dn = self.kwargs['domain_name'].split('.')
namespace = split_dn[0]
sld = split_dn[1]
return reverse("domain_registraiton_item_detail", kwargs={
"pk": self.kwargs['pk'],
'namespace': namespace,
'second_level_domain': sld})
def form_valid(self, form):
f = form.save(commit=False)
working_dri = DomainRegistrationItem.objects.get(domain=self.kwargs['domain_name'])
working_dri.pk = None
working_dri.save()
working_dri.purchased = False
working_dri.years = f.years
f.save()
return super(DomainRegistrationItemUpdateView, self).form_valid(form)
The working_dri code is code that clones a DomainRegistrationItem under consideration by the view.
I want to get the pk from working_dri to usee in get_success_url. How can I do this? Thanks in advance for any and all help.
An UpdateView stores the object it saves to self.object, as we can see in the source code:
def form_valid(self, form):
"""If the form is valid, save the associated model."""
self.object = form.save()
return super().form_valid(form)
so we can make use of:
class DomainRegistrationItemUpdateView(UpdateView):
model = DomainRegistrationItem
form_class = DomainAddYearsForm
template_name = "add_years.html"
# …
def get_success_url(self):
split_dn = self.kwargs['domain_name'].split('.')
namespace = split_dn[0]
sld = split_dn[1]
return reverse("domain_registraiton_item_detail", kwargs={
"pk": self.object.pk,
'namespace': namespace,
'second_level_domain': sld})
def form_valid(self, form):
form.instance.pk = None
form.instance.purchased = False
form.instance.years = f.years
return super(DomainRegistrationItemUpdateView, self).form_valid(form)

How to set django many-to-many field to accept null

I am working on a python/django application. In my application there are 2 tables Store and Ad. That have many to many relation.
Class Store:
ads = models.ManyToManyField(Ad, null=True, blank=True)
Class Store:
ads = models.ManyToManyField(Ad)
I have tested it with both implementations given above but when i save my store without selecting an ad it gives me error:
ads: This field is required.
How can i set ads optional here???
View:
class StoreView(FormView):
form_class = StoreForm
success_url = "/"
template_name = 'store.html'
def __init__(self):
super(StoreView, self).__init__()
self.store = None
def get_form_kwargs(self):
kwargs = super(StoreView, self).get_form_kwargs()
kwargs['current_user'] = self.request.user
if 'store_id' in self.kwargs:
self.store = Store.objects.get(id=self.kwargs['store_id'])
kwargs['instance'] = self.store
kwargs['request'] = self.request
return kwargs
def get_context_data(self, **kwargs):
context = super(StoreView, self).get_context_data(**kwargs)
context['store_info'] = self.store
return context
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(StoreView, self).dispatch(*args, **kwargs)
def form_invalid(self, form):
return super(StoreView, self).form_invalid(form)
def form_valid(self, form):
self.object = form.save()
return super(StoreView, self).form_valid(form)
Form:
class StoreForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.fields['ads'] = forms.ModelMultipleChoiceField(
queryset=Ad.objects.filter(type=13),
widget=forms.CheckboxSelectMultiple,
label='Ads associated with this store'
)
def save(self, commit=False):
store = super(StoreForm, self).save(commit=True)
return store
class Meta:
model = Store
add required=False in definition ads field in the form. When you override a field in model form, no attributes are inherited from the model. You have to add all constraints to it like max_length, required etc.

Categories

Resources