form.is_valid method keeps failing - django

I'm trying to make an editing page for the users to update an object data. However, form.is_valid() keeps failing, I have no idea why.
My model:
class Thread(models.Model):
title = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
creator = models.ForeignKey(User, blank=True, null=True)
body = models.TextField(max_length=10000)
USER_TYPES = (
('INI','Iniciante'),
('INT','Intermediário'),
('AVA','Avançado')
)
user_type = models.CharField(max_length=20, choices = USER_TYPES, default='INI')
category = models.ForeignKey(Category)
orcamento = models.IntegerField(default=0)
slug = models.SlugField(max_length=40, unique=True)
def get_absolute_url(self):
return "/%s/" % self.slug
def __str__(self):
return self.title
def save(self, **kwargs):
slug_str = "%s %s" % (self.category, self.title)
unique_slugify(self, slug_str)
super(Thread, self).save(**kwargs)
My view:
def edit_thread(request, thread_slug):
thread = Thread.objects.get(slug=thread_slug)
if request.method == 'POST':
form = EditThread(request.POST)
if form.is_valid():
thread.title = form.cleaned_data['title']
thread.orcamento = form.cleaned_data['orcamento']
thread.user_type = form.cleaned_data['experiencia']
thread.body = form.cleaned_data['pergunta']
thread.save()
return HttpResponseRedirect('/thread' + thread.get_absolute_url())
else:
data = {'title' : thread.title, 'experiencia':thread.user_type, 'orcamento' : thread.orcamento, 'pergunta': thread.body}
form = EditThread(initial=data)
return render(request, 'edit_thread.html', {
'form': form })
My form:
class EditThread(forms.ModelForm):
title = forms.CharField(label='Título', max_length=200, error_messages=my_default_errors)
orcamento = forms.IntegerField(label='Preço máximo', error_messages=my_default_errors)
experiencia = forms.ChoiceField(label='Você é um usuário...', choices=Thread.USER_TYPES, error_messages=my_default_errors)
pergunta = forms.CharField(label='Pergunta', widget=forms.Textarea, error_messages=my_default_errors)
class Meta:
model = Thread
def __init__(self, *args, **kwargs):
super(EditThread, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Div('title',
'experiencia',
PrependedAppendedText('orcamento', 'R$', ',00', active=True),
'pergunta',
FormActions(
Submit('save', 'Salvar alterações'),
)))
When accessing the page, the form gets pre-populated with the object's data as it should.

Your form should be inherited from the simple forms.Form instead of the forms.ModelForm:
class EditThread(forms.Form):
...

I would suggest you look at django's class based UpdateView. It can generate an update form for you or you could give it a custom ModelForm by overriding the form_class attribute on your view. When using a ModelForm, you also have to specify which model the form is for eg:
class EditThread(forms.ModelForm):
"field definitions ..."
class Meta:
model = Thread
fields = ['my_field_1', 'my_field_2']

Related

Django UpdateView Two Seperate Form Save (included inlineformset_factory)

I have a specific problem with my forms. I think it would be better to share my codes instead of explaining the problem in detail.
However, to explain in a nutshell; inside my model I have field OneToOneField and model of that field has inlineformset_factory form. My new model also has a form and I want to save both forms.
I get the following error when I want to save the offer update form:
TypeError at /ru/mytarget/offer-update/T2GTTT053E9/
AdminOfferUpdateView.form_invalid() missing 2 required positional arguments: 'request_form' and 'request_item_formset'
Models:
request.py
class RequestModel(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name="customer_requests")
id = ShortUUIDField(primary_key=True, length=10, max_length=10, prefix="T", alphabet="ARGET0123456789", unique=True, editable=False)
status = models.BooleanField(default=True)
request_title = models.CharField(max_length=300)
......
updated_on = models.DateTimeField(auto_now=True)
published_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.request_title)
class Meta:
verbose_name_plural = "Requests"
verbose_name = "Request"
def get_absolute_url(self):
return reverse('mytarget:customer_request_details', kwargs={'pk': self.id})
class RequestItem(models.Model):
request_model = models.ForeignKey(RequestModel, on_delete=models.CASCADE, related_name="request_items")
product_name = models.CharField(max_length=300)
......
offer.py
class OfferModel(models.Model):
request_model_name = models.OneToOneField(RequestModel, on_delete=models.CASCADE, primary_key=True)
status = models.BooleanField(default=True)
offer_validity = models.CharField(max_length=50, blank=True)
......
updated_on = models.DateTimeField(auto_now=True)
published_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.request_model_name)
class Meta:
verbose_name_plural = "Offers"
verbose_name = "Offer"
def get_absolute_url(self):
return reverse('mytarget:admin_offer_update', kwargs={'pk': self.request_model_name})
Forms:
request_create_form.py
class CustomerRequestForm(forms.ModelForm):
disabled_fields = ("customer",)
class Meta:
model = RequestModel
fields = ("customer", "request_title", "delivery_time", "shipping_country", "shipping_address",
"preferred_currency", "shipping_term", "delivery_term")
widgets = {
'request_title': TextInput(attrs={'class': 'form-control tableFormInputs',
'placeholder': _('Example: Printers, Toner, and Cartridges')}),
......
}
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('customer')
super(CustomerRequestForm, self).__init__(*args, **kwargs)
self.fields['preferred_currency'].queryset = self.fields['preferred_currency'].queryset.translated().order_by("translations__currency_name")
self.fields['shipping_term'].queryset = self.fields['shipping_term'].queryset.translated().order_by("translations__shipping_term")
for field in self.disabled_fields:
self.fields[field].widget = forms.HiddenInput()
self.fields[field].disabled = True
class CustomerRequestItemForm(forms.ModelForm):
class Meta:
model = RequestItem
fields = ("product_name", "product_info", "target_price", "price", "quantity", "dimensions", "net_weight", "gross_weight",
"hs_or_tn_ved_code", "brand", "manufacturer", "origin_country", "manufacturer_address")
exclude = ()
widgets = {
'product_name': TextInput(attrs={'class': 'form-control tableFormInputs'}),
......
}
RequestItemInlineFormset = inlineformset_factory(RequestModel, RequestItem,
form=CustomerRequestItemForm,
extra=1,
can_delete=True
)
offer_update_form.py
class AdminOfferUpdateForm(forms.ModelForm):
disabled_fields = ()
hidden_fields = ("request_model_name",)
request_title = forms.CharField(required=False, widget=TextInput(attrs={'class': 'form-control tableFormInputs', 'placeholder': _('Example: Printers, Toner, and Cartridges')}))
......
class Meta:
model = OfferModel
fields = ("request_model_name", "offer_validity", ......
)
widgets = {'offer_validity': TextInput(attrs={'class': 'form-control tableFormInputs'}),
......
'is_detailed_offer': CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
super(AdminOfferUpdateForm, self).__init__(*args, **kwargs)
self.fields["preferred_currency"].choices = [(c.id, c.currency_name) for c in Currency.objects.all()]
self.fields["shipping_term"].choices = [(st.id, st.shipping_term) for st in ShippingTerm.objects.all()]
self.fields["delivery_term"].choices = [(dt.id, dt.delivery_term) for dt in DeliveryTerms.objects.all()]
self.fields["request_statuses"].choices = [(r.id, r.status) for r in RequestStatus.objects.all()]
for field in self.disabled_fields:
self.fields[field].disabled = True
for field in self.hidden_fields:
self.fields[field].widget = forms.HiddenInput()
Views:
offer_update_view.py
#method_decorator([login_required(login_url=reverse_lazy("accounts:signin")), user_is_superuser], name='dispatch')
class AdminOfferUpdateView(UpdateView):
model = OfferModel
form_class = AdminOfferUpdateForm
template_name = "mytarget/admin_offer_update.html"
def get_context_data(self, **kwargs):
context = super(AdminOfferUpdateView, self).get_context_data(**kwargs)
if self.request.POST:
context['request_form'] = AdminOfferUpdateForm(self.request.POST, instance=self.object.request_model_name)
context['request_item_formset'] = RequestItemInlineFormset(self.request.POST, instance=self.object.request_model_name)
else:
context['request_form'] = AdminOfferUpdateForm(instance=self.object.request_model_name)
context['request_item_formset'] = RequestItemInlineFormset(instance=self.object.request_model_name)
return context
def form_valid(self, form):
context = self.get_context_data()
request_form = context['request_form']
request_item_formset = context['request_item_formset']
with transaction.atomic():
self.object = form.save()
if request_form.is_valid() and request_item_formset.is_valid():
request_form.instance = self.object.request_model_name
request_form.save()
request_item_formset.instance = self.object.request_model_name
request_item_formset.save(commit=False)
for ri in request_item_formset:
ri.save(commit=False)
request_item_formset.save()
return super(AdminOfferUpdateView, self).form_valid(form)
def form_invalid(self, form, request_form, request_item_formset):
return self.render_to_response(
self.get_context_data(form=form, request_form=request_form, request_item_formset=request_item_formset)
)
def get_initial(self):
self.object = self.get_object()
if self.object:
return {"request_model": self.object.request_model_name, "request_item_formset": self.object.request_model_name}
return super().initial.copy()
def get_success_url(self):
return reverse('mytarget:admin_offer_update', kwargs={'pk': self.object.id})
I solved my problem. I created a button function that creates a new model with inheritance of other model fields. In this way, there is no need to edit the form of the other model inside the form of my current model.

Graphene/Django mutations return null

I created the following model in my django app:
class Post(models.Model):
title = models.CharField(max_length=125, unique=True)
slug_title = models.SlugField(max_length=255, unique=True)
body = models.TextField()
published_date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.BooleanField(default=False)
class Meta:
ordering = ['-published_date']
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug_title = slugify(self.title)
super(Post, self).save(*args, **kwargs)
I want to be able to use an API to do POST/GET requests later on, so I decided to use graphene-django. Everything is installed properly and working.
As per the tutorials, I created my schema.py file as follow:
# define schema
class PostType(DjangoObjectType):
class Meta:
model = Post
fields = ('title', 'body', 'author', 'published_date', 'status', 'slug_title')
class UserType(DjangoObjectType):
class Meta:
model = get_user_model()
class PostInput(graphene.InputObjectType):
title = graphene.String()
slug_title = graphene.String()
body = graphene.String()
author = graphene.Int()
published_date = graphene.DateTime()
status=graphene.Boolean()
class CreatePost(graphene.Mutation):
class Arguments:
input = PostInput(required=True)
post = graphene.Field(PostType)
#classmethod
def mutate(cls, root, info, input):
post = Post()
post.title = input.title
post.slug_title = input.slug_title
post.body = input.body
post.author = input.author
post.published_date = input.published_date
post.status = input.status
post.save()
return CreatePost(post=post)
class Query(graphene.ObjectType):
all_posts = graphene.List(PostType)
author_by_username = graphene.Field(UserType, username=graphene.String())
posts_by_author = graphene.List(PostType, username=graphene.String())
posts_by_slug = graphene.List(PostType, slug=graphene.String())
def resolve_all_posts(root, info):
return Post.objects.all()
def resolve_author_by_username(root, info, username):
return User.objects.get(username=username)
def resolve_posts_by_author(root, info, username):
return Post.objects.filter(author__username=username)
def resolve_posts_by_slug(root, info, slug):
return Post.objects.filter(slug_title=slug)
class Mutation(graphene.ObjectType):
create_post=CreatePost.Field()
schema = graphene.Schema(query=Query, mutation=Mutation)
The query part is working as expected, but my mutation section doesn't seem to be working. When I try to create a mutation, I get the below:
{
"data": {
"create_post": {
"post": null
}
}
}
I created a quick test to see if any errors would output when I run the mutation, but everything seems ok there.
def test_mutation_1(self):
response = self.query(
'''
mutation {
createPost(input:{
title:"Test Title",
body:"Test body",
author:1,
publishedDate:"2016-07-20T17:30:15+05:30",
status:false
})
{
post {
title
}
}
}
'''
)
self.assertResponseNoErrors(response)
I get no error messages.
Any help would be appreciated!
The error: errors=[GraphQLError('Cannot assign "1": "Post.author" must be a "User" instance.'
The solution: Alter my CreatePost class to the following:
post.author = User.objects.get(pk=input.author_id)
Instead of:
post.author = input.author_id

not enough values to unpack (expected 2, got 1)

I have a problem with a queryset in one view. My idea is show all users who are not registered in a program, I put here the models:
models.py
class UCAUser(AbstractUser):
dni_cif=models.CharField(
max_length=9,
blank=True,
verbose_name="DNI/CIF"
)
class InscripcionRealizada(models.Model):
formulario = models.ForeignKey(Formulario)
inscrito = models.ForeignKey(UCAUser,related_name="inscripciones_realizadas")
fecha_registro = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = "Inscripción realizada"
verbose_name_plural = "Inscripciones realizadas"
def __str__(self):
return "{} - {} - {}".format(self.formulario.programa, self.formulario.edicion, self.inscrito)
You can see UCAUser and InscripcionRealizada are connected by InscripcionRealizada.inscrito field.
view.py
class InscribirUsuariosListView(ListView):
template_name = "inscripciones/InscribirUsuariolist.html"
model = UCAUser
group_required = ['Administrador']
login_url = "auth-login"
def get_queryset(self):
qs = super(InscribirUsuariosListView, self).get_queryset()
return qs.filter(UCAUser.objects.filter(inscripciones_realizadas__formulario!=self.kwargs['formulario_id']))
def get_context_data(self, **kwargs):
context = super(InscribirUsuariosListView, self).get_context_data(**kwargs)
context['formulario_id'] = self.kwargs['formulario_id']
return context
When I try this, I get an error:
not enough values to unpack (expected 2, got 1)
Any idea?

FormView is not showing validation errors

My model.py looks:
class VehicleInquiry(TimeStampedModel):
inquiry_status = models.PositiveSmallIntegerField(_("inquiry status"), choices=INQUIRY_STATUS_CHOICES, default=1)
ip = models.GenericIPAddressField(_("IP"), blank=True, null=True)
full_name = models.CharField(_("full name"), max_length=100)
address = models.CharField(_("address"), max_length=200)
phone_code = models.PositiveSmallIntegerField(_("phone code")
)
phone = models.CharField(_("phone"), max_length=20)
email = models.EmailField(_("email"))
is_subscribed = models.BooleanField(_("subscribed"), default=True)
vehicle = models.ForeignKey(VehicleStock, on_delete=models.SET_NULL, blank=True, null=True,
related_name="inquiries", verbose_name=_("vehicle")
)
country = models.ForeignKey(Country, on_delete=models.SET_NULL, blank=True, null=True,
related_name="inquiries", verbose_name=_("country")
)
arrival_port = models.ForeignKey(CountryPorts, on_delete=models.SET_NULL, blank=True, null=True,
related_name="inquiries", verbose_name=_("arrival port")
)
current_price = models.PositiveIntegerField(_('current price'), null=True, blank=True)
inspection = models.BooleanField(_("pre-export inspection"), default=False)
insurance = models.BooleanField(_("insurance"), default=True)
total = models.PositiveIntegerField(_('total price'), null=True, blank=True)
my form.py:
class VehicleInquiryForm(forms.ModelForm):
country2 = forms.TypedChoiceField(
label=_("Country"),
choices=[('','Arrival Country')]+[(country.id, country.name) for country in Country.objects.all().filter(visible=True).order_by('name')],
required=True,
)
phone_code = ChoiceFieldWithTitles(
label=_("Country dialing code"),
choices=[('','Dailing Code', 'Dailing Code')]+[(country.id, '{} (+{})'.format(country.name, country.phone_code), '+{}'.format(country.phone_code)) for country in Country.objects.all().filter(visible=True).order_by('name')],
required=True,
)
arrival_port = forms.TypedChoiceField(
label=False,
widget=forms.RadioSelect
)
phone = forms.CharField(
label=_("Phone"),
max_length=20,
required=True,
validators=[phone_number_validator]
)
full_name = StrippedCharField(
label=_("Full name"),
max_length=30,
required=True,
validators=[full_name_validator]
)
address = StrippedCharField(
label=_("Address"),
max_length=200,
required=True
)
class Meta:
model = VehicleInquiry
exclude = ('inquiry_status', 'vehicle', 'current_price', 'total')
def clean_country2(self):
country_id = self.cleaned_data['country2']
try:
country = Country.objects.get(id=country_id)
except Country.DoesNotExist:
raise forms.ValidationError(_('Please select the country'))
return country_id
def clean(self):
cleaned_data = super(VehicleInquiryForm, self).clean()
dialing_code = cleaned_data['phone_code']
try:
dialing_country = Country.objects.get(id=dialing_code)
except Country.DoesNotExist:
raise forms.ValidationError(_('Please select the phone code'))
return self.cleaned_data
def __init__(self, *args, **kwargs):
dialing_code = kwargs.pop('phone_code', None)
super(VehicleInquiryForm, self).__init__(*args, **kwargs)
self.fields['is_subscribed'].label = _("Keep me updated with news, specials offers and more.")
self.helper = FormHelper()
self.helper.template_pack = "bootstrap3"
self.helper.form_method = "post"
self.helper.form_id = "vehicle-shipping-form"
self.helper.form_show_errors = True
self.initial['insurance'] = True
self.fields['phone_code'].initial = dialing_code
self.helper.add_input(
Submit('inquiry', _('Inquiry'), css_class='btn btn-default',)
)
self.helper.form_method = 'post'
self.helper.layout = Layout(
Fieldset(
_("1. Choose Your Final Destination"),
Div(
Field('country2', css_class="order-select-country"),
),
-- other fields --
)
view.py
class VehicleStockDetailView(FormView):
template_name = "site/product/vehicle-detail.html"
template_name_done = "site/contact/contact-us-done.html"
template_name_done_email = "site/contact/emails/contact-us-done.html"
form_class = VehicleInquiryForm
model = VehicleStock
def get(self, request, slug, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
vehicle = get_object_or_404(VehicleStock, slug=slug)
similar_vehicles = VehicleStock.objects.get_public_available().filter(model__id=vehicle.model.id).exclude(slug=slug)[:6]
page_title = vehicle.model
return render(request, self.template_name, {'page_title': page_title, 'similar_products': similar_vehicles, 'stock_product': vehicle, 'shipping_form': form})
def post(self, request, slug, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
vehicle = get_object_or_404(VehicleStock, slug=slug)
similar_vehicles = VehicleStock.objects.get_public_available().filter(model__id=vehicle.model.id).exclude(slug=slug)[:6]
page_title = vehicle.model
if form.is_valid():
form.save()
return render(self.request, self.template_name_done, {'full_name': request.POST['full_name'], 'email': request.POST['email']})
return render(self.request, self.template_name, {'page_title': page_title, 'similar_products': similar_vehicles, 'stock_product': vehicle, 'shipping_form': form})
url.py
url(r'^vehicle/(?P<slug>[-_\w]+)/$', VehicleStockDetailView.as_view(), name='vehicle-detail'),
Now, when I fill the form and send inquiry it is not showing any error but showing again the form with entered field values except phone_code (it is showing default value). No errors showing, but the form is not validated. I tried different ways with TemplateView and with FormView. But no success.Deadly need any help.
You haven't passed the POSTed data to the form anywhere.
This is one of the reasons why you should not be overriding the get and post methods. The point of the various class-based views is that they do almost all of this for you. You should be inheriting from CreateView, so that the form is saved when it is valid, and the extra logic you have added should be in get_context_data - as you can see, this avoids having to include the same code twice.
class VehicleStockDetailView(CreateView):
template_name = "site/product/vehicle-detail.html"
template_name_done = "site/contact/contact-us-done.html"
template_name_done_email = "site/contact/emails/contact-us-done.html"
form_class = VehicleInquiryForm
model = VehicleStock
def get_context_data(self, *args, **kwargs):
context = super(VehicleStockDetailView, self).get_context_data(*args, **kwargs)
context['vehicle'] = get_object_or_404(VehicleStock, slug=self.kwargs['slug'])
context['similar_vehicles'] = VehicleStock.objects.get_public_available().filter(model__id=vehicle.model.id).exclude(slug=slug)[:6]
context['page_title'] = vehicle.model
return context
def form_valid(self, form, *args, **kwargs):
obj = form.save()
return render(self.request, self.template_name_done, {'full_name': self.request.POST['full_name'], 'email': self.request.POST['email']})
Note also that you really should never directly render a template on success; you should always redirect. Again, the form view takes care of this for you.

Getting a field value using Django

Can I get the value of the field which I am not showing in form? I want to pass ref_id in session.
This is my model:
def _createId():
"""
"""
return hexlify(os.urandom(4))
class jobpost(models.Model):
item_types = (
('Full Time','Full Time'),
('Part Time','Part Time'),
('Contract','Contract'),
)
posttype= (
('Job','Job'),
('Classified','Classified'),
('Project/Task','Project/Task'),
('Internship','Internship'),
)
#user = models.ForeignKey(User)
job_id = models.AutoField(primary_key=True)
country= models.ForeignKey(Country,to_field = 'country_name', null=True)
#user = models.ForeignKey(User, editable = False)
post_type = models.CharField(max_length=255,null=True, choices=posttype,default='Job')
job_type = models.CharField(max_length=255,null=True, choices=item_types,default='Full Time')
job_location = models.CharField(max_length=255,null=True)
job_title = models.CharField(max_length=255,null=True)
job_description = models.TextField(null=True)
start_date = models.DateField(null=True, help_text="mm/dd/yyyy")
end_date = models.DateField(null=True, help_text="mm/dd/yyyy")
how_to_apply = models.CharField(max_length=255,null=True)
ref_id = models.CharField(max_length=32, default=_createId)
def __unicode__(self):
return unicode(self.country)
return self.post_type
return self.job_location
return self.job_type
return self.job_title
return self.job_description
return self.start_date
return self.end_date
return self.how_to_apply
return self.ref_id
means i am not displaying it in my form and i want to pass this value in session in next form..
can anyone tell me how can i do this? and how can i pass the primary key of the form in next form ?
forms.py
class JobPostForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(JobPostForm, self).__init__(*args, **kwargs)
self.fields['ref_id'].widget = forms.HiddenInput()
class Meta:
model = jobpost
views.py
def your_view(request):
if request.method == 'POST':
form = JobPostForm(request.POST)
if form.is_valid():
request.session['ref_id'] = form.cleaned_data.get('ref_id')
pk = form.save()
request.session['pk'] = pk.id
else:
form = JobPostForm()
return render(request, page.html,{'form': form})