I've problems when trying to access to the 2nd part of a 2 Steps form.
When clicking on a product, in a given category, for example category 'stickers' and product 'minion-cushion', users are taken to this url:
/shop/stickers/minion-cushion/medida-y-cantidad
In here they'll find a form 'StepOneForm' that only displays a tamanios (sizes in english) and cantidades (quantities in english) both as forms.ChoiceFields.
I'll capture the user's choices for this fields and save the values in the session. And then user should click on Continuar button and should be taken to this url:
/shop/stickers/minion-cushion/subir-arte
Where users will see the 2nd form "StepTwoForm" and the button to submit the form to DataBase.
However, when using this in my StepOneForm template, I get this error:
Continuar
Error:
NoReverseMatch at /shop/stickers/minion-cushion/medida-y-cantidad
Reverse for 'UploadArt' with no arguments not found. 1 pattern(s) tried: ['shop\\/(?P<c_slug>[-a-zA-Z0-9_]+)\\/(?P<product_slug>[-a-zA-Z0-9_]+)\\/subir\\-arte$']
But leaving the a tag href attribute blank lets me access this page without problems (except, obviously, I cannot access the the next page when clicking on Continue).
Continuar
Likes this:
Form in template:
<form method="post">
{% csrf_token %}
<div id="tamanios">
<legend class="text-size20 bold-font"> {{ form.tamanios.label }}</legend>
<ul class="form-items">
<li>
<span>
{{ form.tamanios.0.tag }}
{{ form.tamanios.0.choice_label }}
</span>
</li>
</ul>
</div>
Continuar
</br>
<p>Siguiente: subir imagen</p>
</form>
My urls:
app_name = 'shop'
urlpatterns = [
path('', views.allProdCat, name = 'allProdCat'),
path('<slug:c_slug>', views.allProdCat, name = 'products_by_category'),
path('<slug:c_slug>/<slug:product_slug>/medida-y-cantidad', views.StepOneView.as_view(), name='ProdCatDetail'),
path('<slug:c_slug>/<slug:product_slug>/subir-arte', views.StepTwoView.as_view(), name='UploadArt'),
]
shop/views.py
class StepOneView(FormView):
form_class = StepOneForm
template_name = 'shop/product.html'
success_url = 'shop/subir-arte'
def get_initials(self):
# pre-populate form if someone goes back and forth between forms
initial = super(StepOneView, self).get_initial()
initial['tamanios'] = self.request.session.get('tamanios', None)
initial['cantidades'] = self.request.session.get('cantidades', None)
return initial
# pre-populate form if someone goes back and forth between forms
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['product'] = Product.objects.get(
category__slug=self.kwargs['c_slug'],
slug=self.kwargs['product_slug']
)
return context
def form_valid(self, form):
# In form_valid method we can access the form data in dict format
# and will store it in django session
self.request.session['tamanios'] = form.cleaned_data.get('tamanios')
self.request.session['cantidades'] = form.cleaned_data.get('cantidades')
return HttpResponseRedirect(self.get_success_url())
# here we are going to use CreateView to save the Third step ModelForm
class StepTwoView(CreateView):
form_class = StepTwoForm
template_name = 'shop/subir-arte.html'
success_url = '/'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['product'] = Product.objects.get(
category__slug=self.kwargs['c_slug'],
slug=self.kwargs['product_slug']
)
return context
def form_valid(self, form):
form.instance.tamanios = self.request.session.get('tamanios') # get tamanios from session
form.instance.cantidades = self.request.session.get('cantidades') # get cantidades from session
del self.request.session['cantidades'] # delete cantidades value from session
del self.request.session['tamanios'] # delete tamanios value from session
self.request.session.modified = True
return super(StepTwoView, self).form_valid(form)
shop/models.py
class Category(models.Model):
name = models.CharField(max_length=250, unique=True)
slug = models.SlugField(max_length=250, unique=True)
description = models.TextField(blank=True)
image = models.ImageField(upload_to='category', blank=True)
class Meta:
ordering = ('name',)
verbose_name = 'category'
verbose_name_plural = 'categories'
def get_url(self):
return reverse('shop:products_by_category', args=[self.slug])
def __str__(self):
return '{}'.format(self.name)
class Product(models.Model):
name = models.CharField(max_length=250, unique=True)
slug = models.SlugField(max_length=250, unique=True)
description = models.TextField(blank=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
price = models.DecimalField(max_digits=10, decimal_places=2)
image = models.ImageField(upload_to='product', blank=True)
stock = models.IntegerField()
available = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('name',)
verbose_name = 'product'
verbose_name_plural = 'products'
def get_url(self):
return reverse('shop:ProdCatDetail', args=[self.category.slug, self.slug])
def __str__(self):
return '{}'.format(self.name)
class TamaniosCantidades(models.Model):
# usuario = models.ForeignKey(User, on_delete=models.DO_NOTHING)
producto = models.ForeignKey(Product, on_delete=models.CASCADE)
tamanios = models.CharField(max_length=10, choices=TAMANIOS)
cantidades = models.CharField(max_length=10, choices=CANTIDADES)
imagenes = models.FileField(upload_to='imagenes/', null=True, blank=True)
# imagenes = models.ImageField(upload_to='category', blank=True)
instrucciones = models.CharField(max_length=200, blank=True, null=True, default='')
uploaded_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.tamanios
shop/forms.py
class StepOneForm(forms.Form):
tamanios = forms.ChoiceField(choices=TAMANIOS, widget=forms.RadioSelect(), label='Selecciona un tamaño')
cantidades = forms.ChoiceField(choices=CANTIDADES, widget=forms.RadioSelect(), label='Selecciona la cantidad')
class StepTwoForm(forms.ModelForm):
instrucciones = forms.CharField(widget=forms.Textarea)
class Meta:
model = TamaniosCantidades
fields = ('imagenes', 'instrucciones')
def __init__(self, *args, **kwargs):
super(StepTwoForm, self).__init__(*args, **kwargs)
self.fields['instrucciones'].required = False
Because uploadart has arguments ( c_slug and product_slug ):
path('<slug:c_slug>/<slug:product_slug>/subir-arte',
views.StepTwoView.as_view(),
name='UploadArt'),
Your url must to inform this arguments:
<a href="{% url 'shop:UploadArt' _some_data_here_ _some_data_here_ %}"
Take a look to django url docs samples
Related
Am actually new to programming, so i am just getting a blank page, no errors.
This is my model
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile',
blank=True, null=True)
bio = models.TextField(max_length=500, null=True)
location = models.CharField(max_length=30, null=True)
def __str__(self):
return self.user.username
def get_absolute_url(self):
return reverse('outcome:userprofile-detail', kwargs={'pk': self.pk})
class Post(models.Model):
text = models.TextField(max_length=255)
profile = models.ForeignKey('Profile', null=True, on_delete = models.CASCADE, related_name='create')
overview = models.CharField(max_length=255)
def __str__(self):
return self.text
The view
class Userlist(LoginRequiredMixin, ListView):
model = Profile
template_name = 'outcome/user-list.html'
class UserDetail(LoginRequiredMixin, DetailView):
model = Profile
template_name = 'outcome/userprofile_detail.html'
The template
{% for i in post.profile_set.all %}
**`trying to loop over the post`**
{{i.text}}
{% endfor %}
I have tried this for a while now and i dont know whether its from template or view.
You can override get_context_data method like this :
class UserDetail(LoginRequiredMixin, DetailView):
model = Profile
template_name = 'outcome/userprofile_detail.html'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
# Add in a QuerySet of the user posts
all_posts = Post.objects.all()
user_posts = all_posts.filter(profile_id=self.request.user.profile.id)
context['user_posts'] = user_posts
return context
user_detail.html
{% for post in user_posts %}
{{post.text}}
{{post.overview}}
{% endfor %}
I am setting up my CategoryDetailView for my CRM. Then this error occurred:
'CategoryDetailView' object has no attribute 'get_object'
here's my code sectrion from views.py:
class CategoryDetailView(LoginRequiredMixin, generic.ListView):
template_name = "clients/category/category_detail.html"
context_object_name = "category"
def get_context_data(self, **kwargs):
context = super(CategoryDetailView, self).get_context_data(**kwargs)
clients = self.get_object().client_set.all()
context.update({
"clients": clients
})
return context
Here's my models.py
class Client(models.Model):
first_name = models.CharField(max_length=30)
middle_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
mobile_number = models.CharField(max_length=12)
organization = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
agent = models.ForeignKey("Agent", null=True, blank=True, on_delete=models.SET_NULL)
category = models.ForeignKey("Category", related_name="clients", null=True, blank=True, on_delete=models.SET_NULL)
class Category(models.Model):
name = models.CharField(max_length=30) # New, Tapped, Active, Closed
organization = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
def __str__(self):
return self.name
Thanks in advance!
You are working with a ListView [Django-doc], not a DetailView [Django-doc], and a ListView indeed has no .get_object(…) method [Django-doc]. You furthermore should specify a model = … or queryset = … to specify with what queryset the DetailView is dealing.
You thus should inherit from the DetailView. You can also work with self.object to prevent making an extra query:
from django.views.generic import DetailView
class CategoryDetailView(LoginRequiredMixin, DetailView):
template_name = 'clients/category/category_detail.html'
context_object_name = 'category'
model = Category
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
clients = self.object.client_set.all()
context['clients'] = clients
return context
There is als no reason to add this to the context, in the template, you can simply work with:
{% for client in category.client_set.all %}
{{ client }}
{% endfor %}
Need to add an image to the form either by entering a link to the image, or upload a file from your computer. If no options were entered when the form was submitted, or both options were entered, an error message should be displayed. And after successful loading, you should get to the image page.
models.py:
class Picture(models.Model):
url = models.URLField(blank=True, verbose_name='Ссылка на изображение')
image = models.ImageField(upload_to='pictures/%Y/%m/%d', width_field='image_width', height_field='image_height',
blank=True, verbose_name='Изображение')
image_width = models.IntegerField(default=0, blank=True, verbose_name='Ширина изображения')
image_height = models.IntegerField(default=0, blank=True, verbose_name='Высота изображения')
is_active = models.BooleanField(default=True, verbose_name='Актуальность изображения')
created = models.DateField(blank=True, null=True, default=timezone.now, verbose_name='Дата создания записи')
updated = models.DateField(blank=True, null=True, default=timezone.now, verbose_name='Дата ред-ия записи')
views.py:
def add_picture(request):
picture = Picture.objects.filter(is_active=True)
if request.method == 'POST':
form = PictureCreateForm(data=request.POST, files=request.FILES)
if form.is_valid():
form.save()
return render(request, 'add_picture.html', locals())
else:
messages.error(request, 'Ошибка, проверьте данные')
else:
form = PictureCreateForm()
return render(request, 'add_picture.html', locals())
forms.py: Here you need to define a method clean
class PictureCreateForm(forms.ModelForm):
class Meta:
model = Picture
fields = ('url', 'image')
def clean(self):
cd = self.cleaned_data
if cd['url'] and cd['image']:
raise forms.ValidationError('Ошибка!')
if not cd['url'] and not cd['image']:
raise forms.ValidationError('Ошибка!')
return cd
urls.py:
urlpatterns = [
path('', views.home, name='home'),
path('add_picture/', views.add_picture, name='add_picture'),
path('picture_detail/<int:id>/', views.picture_detail, name='picture_detail'),
]
You can make use of the clean(...) method of forms.ModelForm as
class PictureCreateForm(forms.ModelForm):
class Meta:
model = Picture
fields = ('url', 'image')
def clean(self):
cleaned_data = super().clean()
url = cleaned_data.get("url")
image = cleaned_data.get("url")
# do your logic here
# atlast
return cleaned_data
enter image description here
I see URL, but click on it not goving at page.
If I go directly to the link, the page opens. In my opinion the matter lies in the def post_list
model
class Category(models.Model):
name = models.CharField(max_length=128, unique=True, verbose_name='Название')
slug = models.SlugField(unique=True)
image = models.ImageField(null=True, blank=True, verbose_name='Изображение')
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
class Meta:
verbose_name = 'Категории'
verbose_name_plural = 'Категории'
def __str__(self): # For Python 2, use __unicode__ too
return self.name
def get_absolute_url(self):
return reverse('show_category', kwargs={'slug': self.slug})
class Post(models.Model):
category = models.ForeignKey(Category, default=1, verbose_name='Категория')
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1, verbose_name='Пользователь')
title = models.CharField(max_length=120, verbose_name='Заголовок')
slug = models.SlugField(unique=True)
image = models.ImageField(null=True, blank=True, verbose_name='Изображение')
content = models.TextField(max_length=10000, verbose_name='Контент')
updated = models.DateTimeField(auto_now=True, auto_now_add=False, verbose_name='Обновлено')
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True, verbose_name='Создано')
keywords = models.CharField(max_length=1024, blank=True, null=True)
description = models.CharField(max_length=1024, blank=True, null=True)
class Meta:
verbose_name = 'Статьи'
verbose_name_plural = 'Статьи'
ordering = ["-timestamp", "-updated"]
def __str__(self): # For Python 2, use __unicode__ too
return self.title
def get_absolute_url(self):
return reverse('detail', kwargs={'slug': self.slug, 'category': self.category})
views
only problem page
def post_list(request):
queryset_list = Post.objects.all()
category_list = Category.objects.all()
search = request.GET.get("s")
if search:
queryset_list = queryset_list.filter(
Q(title__icontains=search) |
Q(content__icontains=search) #|
#Q(user__first_name__icontains=search) |
#Q(user__last_name__icontains=search)
).distinct()
paginator = Paginator(queryset_list, 5) # Show 5 contacts per page
page = request.GET.get('page')
try:
queryset = paginator.page(page)
except PageNotAnInteger:
queryset = paginator.page(1)
except EmptyPage:
queryset = paginator.page(paginator.num_pages)
context = {
"object_list": queryset,
"category_list": category_list,
"title": "Новое"
}
return render(request, "post_list.html", context)
urls
from .views import (
post_list,
post_detail,
show_category,
)
urlpatterns = [
url(r'^$', post_list, name="list"),
url(r'^(?P<category>[-\w]+)/(?P<slug>[-\w]+)/$', post_detail, name="detail"),
url(r'^(?P<slug>[-\w]+)/$', show_category, name='show_category'),
]
html
{% for cat in category_list %}
<li>{{ cat.name }}</li>
{% endfor %}
I have a class based view. I am trying to save an object with it's association. I have the following error :
NOT NULL constraint failed: boxes_suggestion.box_id
More explanation: I have a SuggestionBox (Model) and each Participant could add Comments into it. it's sort of a doodle clone.
detail.html
<h3>{{box.title}}</h3>
<form action="." method="post">{% csrf_token %}
{{ form.as_p }}
<input id="box_id_value" type="hidden" name="box_id_value" value='{{box.id}}' />
<input type="submit" class="btn btn-info" value="Add suggies 1" />
</form>
views.py
class SuggiesForm(FormView):
'''
Display the form
Otherwise
Process the form
1-Get the suggestion_box_id
2-Save the comment associated with that suggestion box.
'''
template_name = 'boxes/detail.html'
form_class = SuggestionForm
success_url = '/boxes/success'
box_instance = ''
def get_context_data(self, **kwargs):
'''
Retrieve the id of the Suggestion Box
'''
context = super(SuggiesForm, self).get_context_data(**kwargs)
#Find The appropriate Box so that user can add Suggies
context['box'] = Box.objects.get(pk=self.kwargs['pk'])
box_instance = context['box']
return context
def form_valid(self, form):
'''
'''
form.save(commit=False)
#box = box_instance
form.box = Box.objects.first()
form.participant = Suggestion.objects.first()
form.save()
return super(SuggiesForm, self).form_valid(form)
models.py
#python_2_unicode_compatible
class Box(models.Model):
"""
Box model
"""
def __str__(self):
return self.title
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=40, blank=True, null=True)
identify = models.BooleanField(default=False)
activate = models.BooleanField(default=False)
created_at = models.DateField(auto_now_add=True)
updated_at = models.DateField(auto_now=True)
#expiration_date = models.DateField(auto=Date in Future, blank=True, null=False)
#slug = AutoSlugField(_('slug'), populate_from="id")
#url(slug)
#python_2_unicode_compatible
class Participant(models.Model):
"""
Participant Model
"""
def __str__(self):
return self.email
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(blank=True, null=True, default='anonymous#email.com')
username = models.CharField(max_length=40, blank=True, null=True)
box = models.ForeignKey(Box, on_delete=models.CASCADE)
created_at = models.DateField(auto_now_add=True)
updated_at = models.DateField(auto_now=True)
#python_2_unicode_compatible
class Suggestion(models.Model):
"""
For adding comments (or suggestions)
"""
def __str__(self):
return self.comment[0:10]
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
comment = models.CharField("",max_length=250, blank=True, null=True)
box = models.ForeignKey(Participant, on_delete=models.CASCADE)
created_at = models.DateField(auto_now_add=True)
updated_at = models.DateField(auto_now=True)
You correctly used commit=False, but then added the attributes onto the form object itself instead of the object returned from the save. It should be:
object = form.save(commit=False)
object.box = Box.objects.first()
object.participant = Suggestion.objects.first()
object.save()