What is wrong with the form? - django

I am trying to create a online Phone Book for my locality. I am getting problem with the app's entry creation view.
Here is my PhoneEntry model:
# coding=utf-8
from django.urls import reverse_lazy
from django.db import models
from django.template.defaultfilters import slugify
from phonenumber_field.modelfields import PhoneNumberField
class PhoneEntry(models.Model):
# Name of the organisation
org_name = models.CharField(max_length=100, verbose_name="Organisation's Name")
org_details = models.CharField(max_length=500, blank=True, verbose_name="Organisation's Details")
slug = models.SlugField(default='slug', unique=True)
# Verified or not
verified = models.BooleanField(default=False, blank=True)
# Dates when the entry was added and verified
added_date = models.DateField(auto_now_add=True, editable=False)
verified_date = models.DateField(auto_now_add=True)
last_edited_date = models.DateField(blank=True, null=True, auto_now_add=True)
# The phone numbers of the organisation
primary_ph_number = PhoneNumberField(verbose_name="Primary Phone Number")
secondary_ph_number = PhoneNumberField(verbose_name="Secondary Phone Number", blank=True)
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
super(PhoneEntry, self).save(force_insert, force_update, using, update_fields)
self.slug = slugify(self.org_name+"-"+str(int(self.id)))
super(PhoneEntry, self).save(force_insert, force_update, using, update_fields)
#staticmethod
def get_absolute_url():
return reverse_lazy('phbook:index')
def __str__(self):
return self.org_name+"-"+str(self.primary_ph_number)
class Meta:
verbose_name_plural = "Phone Entries"
And this the EntryCreateForm:
class EntryAddForm(forms.ModelForm):
"""org_name = forms.CharField(max_length=100, label="Enter your organisation name: ")
org_details = forms.CharField(max_length=100, widget=forms.Textarea,
label="Enter your organisation details: ", required=False)"""
primary_ph_number = PhoneNumberField(label="Enter your primary phone number: ")
secondary_ph_number = PhoneNumberField(label="Enter your secondary phone number: ", required=False)
class Meta:
model = PhoneEntry
exclude = ['slug', 'last_edited_date', 'added_date', 'verified_date', 'verified']
And this the EntryAddView:
class EntryCreateView(CreateView):
model = PhoneEntry
form_class = EntryAddForm
template_name = 'phbook/form.html'
success_url = 'phbook:index'
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
print("Data is", form.instance)
model = form.save(commit=False)
print(model.org_name, model.org_details, model.primary_ph_number, model.secondary_ph_number)
model.save()
return self.get_success_url()
And the template form.html
{% extends 'base.html' %}
{% block head %}
<title>Add your Organisation's Entry | PhoneBook</title>
{% endblock %}
{% block body %}
{% load crispy_forms_tags %}
<form method="post" action="{% url 'phbook:add' %}" enctype="multipart/form-data">
<button type="submit" value="Submit">Submit</button>
{% csrf_token %}
{% crispy form %}
</form>
{% endblock %}
The base.html contains only the static links for the foundation css and js files.
In the EntryCreateView, when the line print("Data is ", form.instance) is executed it produced this result
Please tell me what I am doing here??

You've overridden post on the view, and are therefore bypassing all the calls to validation that the CreateView would normally do. There is rarely any good reason to override the get or post methods; you should always define a more specific method; in this case, form_valid would be more appropriate, if all you want to do is print out the submitted data. If that's just for debugging, then you may not need to override any methods at all.

Related

Django form fields required and optional configuration

I am in a middle of a project. I have a model :-
class CustomersModels(models.Model):
def servChoices(servs):
lst = [x.serv_name for x in servs]
ch =()
for a in lst:
ch += (a,a),
return ch
customer_name = models.CharField(max_length=100)
comp_name = models.CharField(max_length=100)
ph_no = models.CharField(max_length=12)
webs_name = models.URLField(max_length=200)
service_insterested = models.OneToOneField(ServiceModel, on_delete = models.CASCADE)
def __str__(self):
return self.customer_name
I have a corresponding form for this model.
Now what i want is the fields customer_name, comp_name, webs_name
to be optional in one page. And required in another page.
Please guide me to establish the task in the most convenient manner
Deleted in 'def servChoices', service_insterested because I don't have access to them in the model. I also made it to return a string with the name of the class return 'CustomersModels', so that you can edit, delete records with empty values.
The field class 'customer_name', 'comp_name' ,'webs_name' are set to blank=True to make them optional.
In the NoForm, the required field is 'ph_no'. YesForm requires all fields to be filled in. For this, a validator (clean) is used, which will display a message on the page which field is not filled in (the form will not be sent until all fields are filled). You can read about clean here:
In the bboard views, replace with your folder where you have the templates (this is the string template_name = 'bboard/templ_yes.html').
urls.py
urlpatterns = [
path('yes/', YesCreateView.as_view(), name='yes'),
path('no/', NoCreateView.as_view(), name='no'),
]
views.py
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .forms import NoForm, YesForm
class NoCreateView(CreateView):
template_name = 'bboard/templ_no.html'
form_class = NoForm
success_url = reverse_lazy('no')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
class YesCreateView(CreateView):
template_name = 'bboard/templ_yes.html'
form_class = YesForm
success_url = reverse_lazy('yes')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
forms.py
from django.forms import ModelForm
from .models import CustomersModels
from django.core.exceptions import ValidationError
class YesForm(ModelForm):
class Meta:
model = CustomersModels
fields = ('customer_name', 'comp_name', 'ph_no', 'webs_name')
def clean(self):
cleaned_data = super().clean()
customer_name = cleaned_data.get('customer_name')
comp_name = cleaned_data.get('comp_name')
webs_name = cleaned_data.get('webs_name')
if len(customer_name) <= 0 or customer_name == '':
raise ValidationError(
"fill in the field customer_name"
)
if len(comp_name) <= 0 or comp_name == '':
raise ValidationError(
"fill in the field comp_name"
)
if len(webs_name) <= 0 or webs_name == '':
raise ValidationError(
"fill in the field webs_name"
)
class NoForm(ModelForm):
class Meta:
model = CustomersModels
fields = ('customer_name', 'comp_name', 'ph_no', 'webs_name')
models.py
class CustomersModels(models.Model):
customer_name = models.CharField(max_length=100, blank=True)
comp_name = models.CharField(max_length=100, blank=True)
ph_no = models.CharField(max_length=12)
webs_name = models.URLField(max_length=200, blank=True)
def __str__(self):
return 'CustomersModels'
tepmplate(templ_yes.html)
<h2>form</h2>
<form method="post" action="{% url 'yes'%}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="adding">
</form>
tepmplate(templ_no.html)
<h2>form</h2>
<form method="post" action="{% url 'no'%}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="adding">
</form>

Multiple file uploads not working in Form Wizard Django

I am working on a project that requires an upload of multiple images in one of the form wizard steps. The form wizard also has several models used for the wizard which I think complicates the whole process the more. Here is the relevant code:
models.py
from django.db import models
from django.contrib.auth.models import User
from location_field.models.plain import PlainLocationField
from PIL import Image
from django.core.validators import MaxValueValidator, MinValueValidator
from listing_admin_data.models import (Service, SubscriptionType, PropertySubCategory,
PropertyFeatures, VehicleModel, VehicleBodyType, VehicleFuelType,
VehicleColour, VehicleFeatures, BusinessAmenities, Currency
)
class Listing(models.Model):
listing_type_choices = [('P', 'Property'), ('V', 'Vehicle'), ('B', 'Business/Service'), ('E', 'Events')]
listing_title = models.CharField(max_length=255)
listing_type = models.CharField(choices=listing_type_choices, max_length=1, default='P')
status = models.BooleanField(default=False)
featured = models.BooleanField(default=False)
city = models.CharField(max_length=255, blank=True)
location = PlainLocationField(based_fields=['city'], zoom=7, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
expires_on = models.DateTimeField(auto_now=True)
created_by = models.ForeignKey(User,
on_delete=models.CASCADE, editable=False, null=True, blank=True
)
listing_owner = models.ForeignKey(User,
on_delete=models.CASCADE, related_name='list_owner'
)
def __str__(self):
return self.listing_title
def get_image_filename(instance, filename):
title = instance.listing.listing_title
slug = slugify(title)
return "listings_pics/%s-%s" % (slug, filename)
class ListingImages(models.Model):
listing = models.ForeignKey(Listing, on_delete=models.CASCADE)
image_url = models.ImageField(upload_to=get_image_filename,
verbose_name='Listing Images')
main_image = models.BooleanField(default=False)
class Meta:
verbose_name_plural = "Listing Images"
def __str__(self):
return f'{self.listing.listing_title} Image'
class Subscriptions(models.Model):
subscription_type = models.ForeignKey(SubscriptionType, on_delete=models.CASCADE)
subscription_date = models.DateTimeField(auto_now_add=True)
subscription_amount = models.DecimalField(max_digits=6, decimal_places=2)
subscribed_by = models.ForeignKey(User, on_delete=models.CASCADE)
duration = models.PositiveIntegerField(default=0)
listing_subscription = models.ManyToManyField(Listing)
updated_at = models.DateTimeField(auto_now=True)
status = models.BooleanField(default=False)
class Meta:
verbose_name_plural = "Subscriptions"
def __str__(self):
return f'{self.listing.listing_title} Subscription'
class Property(models.Model):
sale_hire_choices = [('S', 'Sale'), ('R', 'Rent')]
fully_furnished_choices = [('Y', 'Yes'), ('N', 'No')]
listing = models.OneToOneField(Listing, on_delete=models.CASCADE)
sub_category = models.ForeignKey(PropertySubCategory, on_delete=models.CASCADE)
for_sale_rent = models.CharField(choices=sale_hire_choices, max_length=1, default=None)
bedrooms = models.PositiveIntegerField(default=0)
bathrooms = models.PositiveIntegerField(default=0)
rooms = models.PositiveIntegerField(default=0)
land_size = models.DecimalField(max_digits=10, decimal_places=2)
available_from = models.DateField()
car_spaces = models.PositiveIntegerField(default=0)
fully_furnished = models.CharField(choices=fully_furnished_choices, max_length=1, default=None)
desc = models.TextField()
property_features = models.ManyToManyField(PropertyFeatures)
price = models.DecimalField(max_digits=15, decimal_places=2)
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "Properties"
def __str__(self):
return f'{self.listing.listing_title}'
The forms for this app is as follows:
forms.py
from django import forms
from .models import Listing, Property, Vehicle, Business, ListingImages
class ListingDetails(forms.ModelForm):
class Meta:
model = Listing
fields = ['listing_title', 'city', 'location']
class PropertyDetails1(forms.ModelForm):
class Meta:
model = Property
fields = ['sub_category', 'for_sale_rent', 'bedrooms', 'bathrooms',
'rooms', 'land_size', 'available_from', 'car_spaces', 'fully_furnished',
'desc', 'currency', 'price'
]
class PropertyDetails2(forms.ModelForm):
class Meta:
model = Property
fields = ['property_features']
class ListingImagesForm(forms.ModelForm):
class Meta:
model = ListingImages
fields = ['image_url']
The view that handles all this, though not yet complete as I am still researching on the best way to save the data to the database is as shown below:
views.py
from django.shortcuts import render
import os
from .forms import ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm
from .models import ListingImages
from formtools.wizard.views import SessionWizardView
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.forms import modelformset_factory
from django.contrib import messages
from django.http import HttpResponseRedirect
class PropertyView(SessionWizardView):
ImageFormSet = modelformset_factory(ListingImages, form=ListingImagesForm, extra=3)
template_name = "listings/create_property.html"
formset = ImageFormSet(queryset=Images.objects.none())
form_list = [ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm]
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'media'))
def done(self, form_list, **kwargs):
return render(self.request, 'done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
The template that is used to handle the form fields is as below:
create_property.py
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">
{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{% for field in wizard.form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<span class="message">{{ field.errors }}</span>
</div>
{% endfor %}
{% endif %}
</table>
{% if wizard.steps.prev %}
<div class="d-flex justify-content-around">
<button name="wizard_goto_step" type="submit" class="btn btn-primary" value="{{ wizard.steps.first }}">First Step</button>
<button name="wizard_goto_step" type="submit" class="btn btn-primary" value="{{ wizard.steps.prev }}">Previous Step</button>
</div>
{% endif %}
<div class="d-flex justify-content-end col-12 mb-30 pl-15 pr-15">
<input type="submit" value="{% trans "submit" %}"/>
</div>
</form>
I have tried to attach all the relevant information for this to work.
The main problem I am facing is that the template doesn't give room for multiple uploads, and again, after I attach a single file that is provided and try to submit, I get a field cannot be empty error message.
I am still new to Django and trying to learn as I code, but so far, not much has been documented about the form wizard and the multiple image upload issues. Most of the posts available appear to be shoddy and only uses the contact form which does not store any details on the database.
The solution is from this Project
MultipleUpload.py
from django import forms
FILE_INPUT_CONTRADICTION = object()
class ClearableMultipleFilesInput(forms.ClearableFileInput):
# Taken from:
# https://stackoverflow.com/questions/46318587/django-uploading-multiple-files-list-of-files-needed-in-cleaned-datafile#answer-46409022
def value_from_datadict(self, data, files, name):
upload = files.getlist(name) # files.get(name) in Django source
if not self.is_required and forms.CheckboxInput().value_from_datadict(
data, files, self.clear_checkbox_name(name)):
if upload:
# If the user contradicts themselves (uploads a new file AND
# checks the "clear" checkbox), we return a unique marker
# objects that FileField will turn into a ValidationError.
return FILE_INPUT_CONTRADICTION
# False signals to clear any existing value, as opposed to just None
return False
return upload
class MultipleFilesField(forms.FileField):
# Taken from:
# https://stackoverflow.com/questions/46318587/django-uploading-multiple-files-list-of-files-needed-in-cleaned-datafile#answer-46409022
widget = ClearableMultipleFilesInput
def clean(self, data, initial=None):
# If the widget got contradictory inputs, we raise a validation error
if data is FILE_INPUT_CONTRADICTION:
raise forms.ValidationError(self.error_message['contradiction'], code='contradiction')
# False means the field value should be cleared; further validation is
# not needed.
if data is False:
if not self.required:
return False
# If the field is required, clearing is not possible (the widg et
# shouldn't return False data in that case anyway). False is not
# in self.empty_value; if a False value makes it this far
# it should be validated from here on out as None (so it will be
# caught by the required check).
data = None
if not data and initial:
return initial
return data
enter code here
from django.core.files.uploadedfile import UploadedFile
from django.utils import six
from django.utils.datastructures import MultiValueDict
from formtools.wizard.storage.exceptions import NoFileStorageConfigured
from formtools.wizard.storage.base import BaseStorage
class MultiFileSessionStorage(BaseStorage):
"""
Custom session storage to handle multiple files upload.
"""
storage_name = '{}.{}'.format(__name__, 'MultiFileSessionStorage')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.prefix not in self.request.session:
self.init_data()
################################################################################################
# Helper
################################################################################################
def _get_data(self):
self.request.session.modified = True
return self.request.session[self.prefix]
def _set_data(self, value):
self.request.session[self.prefix] = value
self.request.session.modified = True
data = property(_get_data, _set_data)
################################################################################################
# formtools.wizard.storage.base.BaseStorage API overrides
################################################################################################
def reset(self):
# Store unused temporary file names in order to delete them
# at the end of the response cycle through a callback attached in
# `update_response`.
wizard_files = self.data[self.step_files_key]
for step_files in six.itervalues(wizard_files):
for file_list in six.itervalues(step_files):
for step_file in file_list:
self._tmp_files.append(step_file['tmp_name'])
self.init_data()
def get_step_files(self, step):
wizard_files = self.data[self.step_files_key].get(step, {})
if wizard_files and not self.file_storage:
raise NoFileStorageConfigured(
"You need to define 'file_storage' in your "
"wizard view in order to handle file uploads.")
files = {}
for field in wizard_files.keys():
files[field] = {}
uploaded_file_list = []
for field_dict in wizard_files.get(field, []):
field_dict = field_dict.copy()
tmp_name = field_dict.pop('tmp_name')
if(step, field, field_dict['name']) not in self._files:
self._files[(step, field, field_dict['name'])] = UploadedFile(
file=self.file_storage.open(tmp_name), **field_dict)
uploaded_file_list.append(self._files[(step, field, field_dict['name'])])
files[field] = uploaded_file_list
return MultiValueDict(files) or MultiValueDict({})
def set_step_files(self, step, files):
if files and not self.file_storage:
raise NoFileStorageConfigured(
"You need to define 'file_storage' in your "
"wizard view in order to handle file uploads.")
if step not in self.data[self.step_files_key]:
self.data[self.step_files_key][step] = {}
for field in files.keys():
self.data[self.step_files_key][step][field] = []
for field_file in files.getlist(field):
tmp_filename = self.file_storage.save(field_file.name, field_file)
file_dict = {
'tmp_name': tmp_filename,
'name': field_file.name,
'content_type': field_file.content_type,
'size': field_file.size,
'charset': field_file.charset
}
self.data[self.step_files_key][step][field].append(file_dict)
form.py
from MultipleUpload import MultipleFilesField, ClearableMultipleFilesInput
class ListingImagesForm(forms.ModelForm):
image_url = MultipleFilesField(widget=ClearableMultipleFilesInput(
attrs={'multiple': True, 'accept':'.jpg,.jpeg,.png'}), label='Files')
class Meta:
model = ListingImages
fields = ['image_url']
views.py
from MultipleUpload import MultiFileSessionStorage
class PropertyView(SessionWizardView):
storage_name = MultiFileSessionStorage.storage_name
ImageFormSet = modelformset_factory(ListingImages, form=ListingImagesForm, extra=3)
template_name = "listings/create_property.html"
formset = ImageFormSet(queryset=Images.objects.none())
form_list = [(....), ('ListingImagesForm',ListingImagesForm)]
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'media'))
def done(self, form_list, **kwargs):
cleaned_data = self.get_cleaned_data_for_step('ListingImagesForm')
for f in cleaned_data.get('image_url',[]):
instance = ListingImages(image_url=f, .....)
instance.save()
return render(self.request, 'done.html', {
'form_data': [form.cleaned_data for form in form_list],
})

What Query Sets can help me produce results dependent on two Choice Fields?

My project has many physics questions stored in its database where each of these questions belongs to a Physics' topic and a Question type.
I have two ChoiceField:
* One for topics and includes 16 topics.
* One for question type and includes two question types.
I have a submit button that is supposed to show me the results of my filtering, however, I don't know how to write the Query Sets in the views.py although I have read the Documentation but still don't know how to make one query or more to get my results.
This is the models.py
from django.db import models
from home.choices import *
# Create your models here.
class Topic(models.Model):
topic_name = models.IntegerField(
choices = question_topic_name_choices, default = 1)
def __str__(self):
return '%s' % self.topic_name
class Image (models.Model):
image_file = models.ImageField()
def __str__(self):
return '%s' % self.image_file
class Question(models.Model):
question_type = models. IntegerField(
choices = questions_type_choices, default = 1)
question_topic = models.ForeignKey( 'Topic',
on_delete=models.CASCADE,
blank=True,
null=True)
question_description = models.TextField()
question_answer = models.ForeignKey( 'Answer',
on_delete=models.CASCADE,
blank=True,
null=True)
question_image = models.ForeignKey( 'Image',
on_delete=models.CASCADE,
blank=True,
null=True)
def __str__(self):
return '%s' % self.question_type
class Answer(models.Model):
answer_description = models.TextField()
answer_image = models.ForeignKey( 'Image',
on_delete=models.CASCADE,
blank=True,
null=True)
def __str__(self):
return '%s' % self.answer_description
This is the forms.py
from django import forms
from betterforms.multiform import MultiModelForm
from .models import Topic, Image, Question, Answer
from .choices import questions_type_choices, question_topic_name_choices
class TopicForm(forms.ModelForm):
topic_name = forms.ChoiceField(
choices=question_topic_name_choices,
widget = forms.Select(
attrs = {'class': 'home-select-one'}
))
class Meta:
model = Topic
fields = ['topic_name',]
def __str__(self):
return self.fields
class QuestionForm(forms.ModelForm):
question_type = forms.ChoiceField(
choices= questions_type_choices,
widget = forms.Select(
attrs = {'class': 'home-select-two'},
))
class Meta:
model = Question
fields = ['question_type',]
def __str__(self):
return self.fields
class QuizMultiForm(MultiModelForm):
form_classes = {
'topics':TopicForm,
'questions':QuestionForm
}
This is the views.py
from django.shortcuts import render, render_to_response
from django.views.generic import CreateView, TemplateView
from home.models import Topic, Image, Question, Answer
from home.forms import QuizMultiForm
def QuizView(request):
if request.method == "POST":
form = QuizMultiForm(request.POST)
if form.is_valid():
pass
else:
form = QuizMultiForm()
return render(request, "index.html", {'form': form})
This is the index.html
{% extends 'base.html' %} {% block content %}
<form method="POST">
{% csrf_token %} {{ form.as_p }}
<button type="submit" id="home-Physics-time-button">
It is Physics Time</button>
</form>
{% endblock content %}
Any help would be great. Thank you!
i dont know what exactly you want to filter or if i understood correctly (cant add comments yet), but here is an example:
views.py
def QuizView(request):
topics = Topic.objects.filter(topic_name=1) # i dont know your choices, but i go with the set default
if request.method == "POST":
form = QuizMultiForm(request.POST)
if form.is_valid():
pass
else:
form = QuizMultiForm()
return render(request, "index.html", {'form': form, 'topics':'topics})
template part for calling now the query
{% for topic in topics %}
<h1> {{ topic.topic_name }} </h1>
{% endfor %}
explanation: you are filtering the query in your view by .filter(model_field=)
in your template you iterate trough all results (you are passing 'topics' from the view into the template by the context parameter in your curly brackets), filtered by the view

Using Multiple URL Parameters to get_object in Class-Based-View

Alright, I'm fairly new to this, I've been working on my Project for a couple months now and I'd like to create URLs that accept multiple parameters to call a View. A sample URL would look like this:
http://www.sample.com/builders//m//
I've got this implemented successfully, by overriding get_object in my DetailView, but I'm wondering if there is a better/easier method for accomplishing this or if this is considered a bad practice. Any guidance would be appreciated.
urls.py
urlpatterns = [
# url(r'^$', builder_list, name='list'),
# url(r'^create/$', builder_create, name='create'),
# url(r'^(?P<slug>[\w-]+)/$', builder_detail, name='detail'),
# url(r'^(?P<slug>[\w-]+)/edit/$', builder_update, name='update'),
# url(r'^(?P<slug>[\w-]+)/delete/$', builder_delete, name='delete'),
# url(r'^$', builder_list, name='sub_list'),
# url(r'^m/create/$', sub_create, name='sub_create'),
url(r'^(?P<builder>[\w-]+)/m/(?P<market>[\w-]+)/$', sub_detail, name='sub_detail'),
# url(r'^m/(?P<slug>[\w-]+)/edit/$', sub_update, name='sub_update'),
# url(r'^m/(?P<slug>[\w-]+)/delete/$', sub_delete, name='sub_delete'),
]
views.py
class BuilderSubDetailView(DetailView):
model = BuilderSub
template_name = "builders/sub_detail.html"
def get_context_data(self, **kwargs):
context = super(BuilderSubDetailView, self).get_context_data(**kwargs)
context['now'] = timezone.now()
print(context)
return context
def get_object(self, queryset=None):
if queryset is None:
queryset = self.get_queryset()
# Next, try looking up by primary key.
builder = self.kwargs['builder']
builder_id = Builder.objects.filter(slug=builder).first().pk
market = self.kwargs['market']
market_id = Market.objects.filter(slug=market).first().pk
if builder is not None and market is not None:
queryset = BuilderSub.objects.filter(parent=builder_id).filter(market=market_id)
# If none of those are defined, it's an error.
if builder is None or market is None:
raise AttributeError("Generic detail view %s must be called with "
"Builder and Market"
% self.__class__.__name__)
try:
# Get the single item from the filtered queryset
obj = queryset.get()
except queryset.model.DoesNotExist:
raise Http404("No %(verbose_name)s found matching the query") % \
{'verbose_name': queryset.model._meta.verbose_name}
return obj
And models.py for reference -- also is there any problem with my get_absolute_url function?
class Builder(models.Model):
added_by = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
company_name = models.CharField(max_length=80, help_text="Full Company Name", unique=True)
short_name = models.CharField(help_text="Short Company Name", max_length=30)
slug = models.SlugField(unique=True)
website = models.CharField(max_length=80, help_text="Format: www.[website].com")
logo = models.ImageField(blank=True, null=True)
timestamp = models.DateTimeField(auto_now_add=True)
info = RedactorField(verbose_name=u'Company Info')
def show_website_url(self):
return format_html("<a href='{url}'>{url}</a>", url=self.website)
def __str__(self):
return self.short_name
class BuilderSub(models.Model):
parent = models.ForeignKey(Builder)
market = models.ForeignKey(Market, null=True, blank=True)
details = RedactorField(verbose_name=u'Details', blank=True, null=True)
main_contact = models.ForeignKey(Person, blank=True, null=True)
def __str__(self):
return "{}: {} - {}".format(self.pk, self.market.name, self.parent.short_name)
def get_absolute_url(self):
return reverse('builders:sub_detail', kwargs={'market': self.market.slug, 'builder': self.parent.slug})
def pre_save_builder_reciever(sender, instance, *args, **kwargs):
instance.slug = slugify(instance.short_name)
pre_save.connect(pre_save_builder_reciever, sender=Builder)
I'm not 100% sure I'm my BuilderSub Model is the appropriate way to handle the Relationship between the overall Builder (company) and the Markets they serve so any guidance there would be appreciated as well.
Yes there is indeed a more ethical way to do this. DetailView is meant to deal with only one object. ListView however gets the job done!
I have replaced builder and market with city and category.
I am also a beginner. Hope I have answered your question :)
views.py
class EntryListView(generic.ListView):
template_name = 'myapp/category.html'
context_object_name = 'entry'
def get_queryset(self):
city_id = self.kwargs['city']
category_id = self.kwargs['category']
entry = Entry.objects.all().filter(city=city_id).filter(category=category_id)
return entry
urls.py
url(r'^(?P<city>[0-9]+)/(?P<category>[0-9]+)/$', views.EntryListView.as_view(), name='entry'),
category.html
{% extends 'myapp/base.html' %}
{% block body %}
<table>
{% for new in entry %}
<tr>
<td>
<img src = "{{new.image_url}}">
<br>
<b>Name :</b> {{new.name}}<br>
{% if new.phone %}
<B>Phone No. :</B> {{new.phone}}<br>
{% endif %}
<b>Address :</b> {{new.address}}<br>
</td>
</tr>
{% endfor %}
{% endblock %}
models.py
class Entry(models.Model):
city = models.ForeignKey(City, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
name = models.CharField(max_length=250)
phone = models.IntegerField(null=True)
address = models.CharField(max_length=250)
image_url = models.CharField(max_length=500)
def __str__(self):
return self.name

csrfmiddlewaretoken error while creating form using cripsy-forms

I am beginner in django (using django 1.7) and trying to create a form using crispy-forms in order to add new product to db. The problem is, form is working but it is not creating new product in database.
when I logged, if i click to save button nothing happen and shows below in address bar.
http://127.0.0.1:8000/add_product/?csrfmiddlewaretoken=kfGpEA6ZC32Lad9m9uwWZEhElwBGLHPA&csrfmiddlewaretoken=kfGpEA6ZC32Lad9m9uwWZEhElwBGLHPA&Category_IDCategory=66&DealType=Rent&Title=kkjkj&Price=78&Description=kjjk&save=Save
if I logged out and click to save button it directs me to the homepage as I provide in form but still no new product in database.
The problem looks like related to user and csrf, but still couldnt figure out the exact problem even I searched need your help.
models.py
class Product(models.Model):
DealType_Choice = (
("Sale", "Sale"),
("Rent", "Rent"),
("Swap", "Swap"),
("Free", "Free"),
("Announ", "Announ"),
)
DealType = models.CharField(max_length=11, blank=True, choices=DealType_Choice)
Title = models.CharField(max_length=70)
Description = models.TextField(blank=False)
Price = models.IntegerField(max_length=11, null=True)
User_IDUser = models.ForeignKey(User)
Category_IDCategory = models.ForeignKey(Category)
PubDate = models.DateField("Publication Data")
def __str__(self):
return self.Title
views.py
def add_product(request):
product_form= ProductForm(request.POST)
if product_form.is_valid():
form=product_form.save(commit=False)
form.User_IDUser= request.user
form.save()
return HttpResponseRedirect('/')
else:
product_form= ProductForm()
return render(request, 'add_productts.html', {'product_form':product_form})
forms.py
class ProductForm(forms.ModelForm):
Category_IDCategory=forms.ModelChoiceField(queryset=Category.objects.all(), label="Category")
DealType=forms.ChoiceField(widget=forms.Select, choices=Product.DealType_Choice, label="DealType")
Title=forms.CharField(label='Title', max_length=70)
Price=forms.IntegerField(min_value=0, label='Price')
Description=forms.CharField(widget=forms.Textarea(), label="Description")
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_method = "POST"
self.helper.form_action= "/"
self.helper.layout= Layout(
Field('Category_IDCategory',css_class='input-sm'),
Field('DealType',css_class='input-sm'),
Field('Title',css_class='input-sm'),
Field(PrependedText('Price', 'TL', '.00'),css_class='input-sm'),
Field('Description',css_class='input-sm', rows=5),
FormActions(
Submit('save', 'Save', css_class='btn btn-labeled btn-info'))
)
super(ProductForm, self).__init__(*args, **kwargs)
class Meta:
model=Product
fields= ['Category_IDCategory','DealType', 'Title','Price', 'Description']
template
{% extends "index.html" %}
{% load crispy_forms_tags %}
{% block content %}
<h1>Add Product</h1>{% csrf_token %}
{% crispy product_form %}
{% endblock %}
urls.py
urlpatterns = patterns('',
...
url(r'^add_product/$', add_product),
...
)
I think this is wrong:
self.helper.form_action= "/"
form_action should refer to add_product function:
self.helper.form_action= "/add_product/"