When I click the submit button, it redirects me to the create model (in this case create record) page, and does not actually create a new model, it doesn't appear in the main page which shows all models that were created.
I tried following this tutorial: Link
I feel like I did mostly the same things as him, and yet my form submission button does not create my post. The differences between our programs is simply the naming and the number of fields in my model.
The user registration form works, but that is using a function based view, this is using a class based view (should still work as far as I know), and there are barely any differences between the model creation html and the user registration html.
Here's the model creation form, record_form.html:
{% extends "catalog/base.html" %}
{% block content %}
<h1 class="text py-3 pt-4">Create a Record!</h1>
<style>
.text {
font-size: 40px;
font-weight: bold;
color: #060007;
}
</style>
<div class="shadow p-3 mb-3 bg-light rounded">
<form class="form" method="POST" action="/catalog/">
{% csrf_token %}
<p>
<label for="name">Name:</label>
{{ form.name }}
</p>
<p>
<label for="description">Description:</label>
</p>
<p>
{{ form.description }}
</p>
<p>
<label for="date_start">Date start:</label>
{{ form.date_start }}
</p>
<p>
<label for="date_end">Date end:</label>
{{ form.date_end }}
</p>
<p>
<label for="manufacturer">Manufacturer:</label>
{{ form.manufacturer }}
</select>
</p>
<p>
<label for="condition_rating">Condition rating (between 0 and 5):</label>
{{ form.condition_rating }}
</p>
<p>
<label for="condition_description">Condition description:</label>
</p>
<p>
{{ form.condition_description }}
</p>
<div>
<input type="submit" name="Create Record" value="Create Record" class="submit action-button">
</div>
</form>
<style>
.form {
color: #060007;
}
</style>
</div>
{% endblock content %}
Here's my models that the program is using in models.py:
class CommonInfo(models.Model):
id = models.AutoField(primary_key=True) # not necessary as django adds this to every model, but declared so that it is clear
creation_date = models.DateField(auto_now_add=True)
last_modified = models.DateField(auto_now=True)
name = models.CharField(max_length=100, help_text='Enter name')
description = models.TextField(blank=True, help_text='Enter description')
class Meta:
abstract = True
ordering = ['-last_modified', 'name'] # '-' reverses order, e.i. newest first
# ordering = ['name','-last_modified'] # '-' reverses order, e.i. newest first
class Catalog(CommonInfo):
def get_absolute_url(self):
return reverse('catalog-detail', args=[str(self.id)])
def __str__(self):
return f'{self.name}'
class Record(CommonInfo):
my_catalog = models.ForeignKey(Catalog, on_delete=models.CASCADE) # Many records to one Catalog. Deletes all records associated with deleted catalog.
date_start = models.DateField() # TODO - is date range for when aquired or creation?
date_end = models.DateField()
manufacturer = models.ForeignKey('Manufacturer', null=True, blank=True, on_delete=SET_NULL)
condition_rating = DecimalField(
help_text='Enter condition rating from 0 to 5',
default=0,
decimal_places=2,
max_digits=3,
validators=[MinValueValidator(Decimal('0')), MaxValueValidator(Decimal('5'))]
)
condition_description = models.TextField(blank=True, help_text='Enter condition description')
def get_absolute_url(self):
return reverse('record-detail', args=[str(self.id)])
def __str__(self):
return f'{self.name} ({self.my_catalog})'
Here's the CreateView class in views.py:
class RecordCreateView(CreateView):
model = Record
fields = ['name', 'description', 'date_start', 'date_end', 'manufacturer', 'condition_rating', 'condition_description'] #Owner/nation/continent not able to be done, since provenance is not linked to Record
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
Here's urls.py:
from django.urls import path
from .views import RecordDetailView, RecordCreateView
from . import views
from django.views.generic import RedirectView
urlpatterns = [
path('about/', views.about, name='catalog-about'),
path('home/', views.home, name='catalog-home'),
path('catalog/', views.catalogList, name='catalog-list'),
path('', RedirectView.as_view(url='about/', permanent=True)),
path('login/', views.loginPage, name='catalog-login'),
path('logout/', views.logoutUser, name='catalog-logout'),
path('register/', views.register, name='catalog-register'),
path('record/<int:pk>/', RecordDetailView.as_view(), name='record-detail'),
path('record/new/', RecordCreateView.as_view(), name='record-create'),
]
i dont see a field "name" on Recored table and you don't give the catalog on your RecordCreateView.
Related
currently I'm trying to show part quantity (quan) together with part name in the dropdown. I have a Part table that carries the part name and part quantity and this table called as ForeignKey into the Order table. So, in the Order form during choose the part name from the part dropdown, I would like to show part quantity as well besides the part name. Any idea to make it like that?
models.py
class Part(models.Model):
partno = models.CharField(max_length=50)
partname = models.CharField(max_length=50)
quan = models.PositiveIntegerField(default= 0)
def __str__(self):
return '{}, quantity - {}'.format(self.partname, self.quan)
class Order(models.Model):
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
part = models.ForeignKey(Part, on_delete=models.CASCADE)
views.py
def create_order(request):
from django import forms
form = OrderForm()
if request.method == 'POST':
for form_data in forms_data:
forms = OrderForm(request.POST)
if forms.is_valid():
supplier = forms.cleaned_data['supplier']
product = forms.cleaned_data['product']
part = forms.cleaned_data['part']
order = Order.objects.create(
supplier=supplier,
product=product,
part=part,
)
return redirect('order-list')
context = {
'form': form
}
return render(request, 'store/addOrder.html', context)
HTML
<form action="#" method="post" id="form-container" novalidate="novalidate">
{% csrf_token %}
<div class="form-group">
<label for="product" class="control-label mb-1">Product</label>
{{ form.product }}
</div>
<div class="form-group">
<label for="supplier" class="control-label mb-1">Supplier</label>
{{ form.supplier }}
</div>
<div class="form-group">
<label for="part" class="control-label mb-1">Part Name</label>
{{ form.part }}
</div>
</form>
You will have to write "__ str __"(without spaces between str and __) method for model 'Part'
def __str__(self):
return '{}, quantity - {}'.format(self.partname, self.quan)
Check this post also: What is doing __str__ function in Django?
I am using Class Based views and want to display data on a webpage using ListView. Am using for loop to display many objects data. In my models, the items have a category field which is ForeignKey where the category is either Bags, Tshirts or Shoes. I want to display items whose Category is Shoes only. I have tried using the if condition which isnt working with the ForeignKey field. How do I filter the Category field to display Bags only?
models.py
from django.db import models
# Create your models here.
class Category(models.Model):
title = models.CharField(max_length=30)
createdtime = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Meta:
verbose_name_plural = "Categories"
class Product(models.Model):
mainimage = models.ImageField(upload_to='product')
name = models.CharField(max_length=264)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='category')
previewtext = models.TextField(max_length=200, verbose_name='Preview Text')
detailstext = models.TextField(max_length=1000, verbose_name='Description')
price = models.FloatField()
oldprice = models.FloatField(default=0.00)
createddate = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Meta:
ordering = ['-createddate',]
views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from shopapp.models import Product
# Create your views here.
class Home(ListView):
model = Product
template_name = 'shopapp/home.html'
html file
<div class="container my-5">
<h2 class="my-5">Handbags</h2>
<div class="row">
{% for product in object_list %}
{% if product.category == 'Bags' %}
<div class="col-md-6 col-sm-12 col-lg-3">
<figure class="card card-product">
<div class="img-wrap">
<img src="/media/{{ product.mainimage }}" style="width:100%; height:300px;">
</div>
<figcaption class="info-wrap">
<h6 class="title">{{ product.name }}</h6>
<div class="action-wrap">
<div class="price-wrap h5">
<span class="price-new">${{ product.price|floatformat:2 }}</span>
<span class="price-old"><strike>${{ product.oldprice|floatformat:2 }}</strike></span>
</div>
</div>
</figcaption>
</figure>
</div>
{% endif %}
{% endfor %}
</div>
</div>
In your code use product.category.title like so:
...
{% if product.category.title == 'Bags' %}
...
You are comparing a Category object with the string Bags.
//edit
I also recommend filtering the data in the view, if you only need that data in the view. There is no need to fetch all the products from your database and send them to the view, just to render a portion of it.
Good day, I have a Django project where I want to display an order list and detail. All seems to work perfectly but the link only links to one particular id ( for instance id 66). I have tried deleting the particular order id from the admin panel, thinking maybe the URL would just reset, but I get the URL id incremented, now it's no longer id 66 but 67. Pls how can I fix this? here are my codes:
models.py
class Order(models.Model):
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
address = models.CharField(max_length=250)
phone_number = models.CharField(max_length=20)
city = models.CharField(max_length=100)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
paid = models.BooleanField(default=False)
braintree_id = models.CharField(max_length=150, blank=True)
coupon = models.ForeignKey(Coupon, related_name='orders', null=True, blank=True, on_delete=models.SET_NULL)
discount = models.IntegerField(default=0, validators=[
MinValueValidator(0),
MaxValueValidator(100)
])
class Meta:
ordering = ('-created',)
def __str__(self):
return self.first_name
def get_absolute_url(self):
return reverse('orders:orderdetail', args=[self.id])
views.py
def order_list(request):
orders = Order.objects.all()
current_user = request.user
success = Order.objects.filter(user=current_user.id).filter(paid=True)
fail = Order.objects.filter(user=current_user.id).filter(paid=False)
return render(request, 'orders/order/order_list.html', {
'success': success,
'fail': fail,
'current_user': current_user,
'orders':orders,
})
def order_detail(request, order_id):
order = get_object_or_404(Order, id=order_id)
return render(request, 'orders/order/order_detail.html', {'order': order})
urls.py
from django.urls import path
from . import views
app_name = 'orders'
urlpatterns = [
path('create/', views.order_create, name='order_create'),
path('admin/order/<int:order_id>/', views.admin_order_detail, name='admin_order_detail'),
path('admin/order/<int:order_id>/pdf/', views.admin_order_pdf, name='admin_order_pdf'),
path('addtocart/<int:id>', views.addtocart, name='addtocart'),
path('myorder/', views.order_list, name='orderlist'),
path('myorder/detail/<int:order_id>/', views.order_detail, name='orderdetail'),
]
html
{% for order in orders %}
<a href="{{ order.get_absolute_url }}" style="position: absolute; top: 5px; right: 5px;">
View Details
</a>
{% endfor %}
full html
<div class="col-md-9">
{% for od in success %}
<div class="card mb-3" style="max-width: 540px;">
<div class="row no-gutters">
<div class="col-md-3">
<img alt="product img" class="card-img" src="...">
</div>
<div class="col-md-9">
<div class="card-body" style="position: relative;">
<h5 class="card-title">Product {{ od.id }}</h5>
{% for order in orders %}
<a href="{{ order.get_absolute_url }}" style="position: absolute; top: 5px; right: 5px;">
View Details
</a>
{% endfor %}
<p class="card-text">
<mark style="color: whitesmoke; background-color: brown;border-radius: 3px;font-weight: bold;">{{transaction}}</mark>
</p>
<p class="card-text"><small class="text-muted">Delivered at
{{od.reference_id}}</small></p>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
The URL I get is like this /orders/myorder/detail/66/
I'm gonna add pictures to make it less abstract
Thanks.
Just like #EricMartin said, it was the context of the order
I realized I had {% for od in success %} and {% for order in orders %}
I guess they're not on good terms with each other and since orders is in success, I removed the {% for order in orders %} loop and all seems peaceful again :)
I'm building a news web site as a part of a task I was given, homework.
I have a "articles.html" template which renders all of my news articles by publish date.
I added a for loop in the template to loop over the Category model and display Categories as a list.
What I'm trying to do now is to filter my articles by category, so when I click "sports" on the list, my site now displays only sports related articles.
I have read so much online, and I just got confused, I'm supposed to do this today but I'm having a rough day and would appreciate some guidance !
Here are my models.py :
from django.db import models
from datetime import datetime
from autoslug import AutoSlugField
class Category(models.Model):
category_title = models.CharField(max_length=200, default="")
def __str__(self):
return self.category_title
class Article(models.Model):
title = models.CharField('title', max_length=200, blank=True)
slug = AutoSlugField(populate_from='title', default="",
always_update=True, unique=True)
author = models.CharField('Author', max_length=200, default="")
description = models.TextField('Description', default="")
is_published = models.BooleanField(default=False)
article_text = models.TextField('Article text', default="")
pub_date = models.DateTimeField(default=datetime.now, blank=True)
article_image = models.ImageField('Article Image')
article_category = models.ForeignKey(Category, on_delete="models.CASCADE", default="")
img2 = models.ImageField('Article Image 2', default="", blank=True)
img3 = models.ImageField('Article Image 3', default="", blank=True)
img4 = models.ImageField('Article Image 4', default="", blank=True)
img5 = models.ImageField('Article Image 5', default="", blank=True)
img6 = models.ImageField('Article Image 6', default="", blank=True)
def __str__(self):
return self.title
My views.py :
from django.shortcuts import render, reverse, get_object_or_404
from django.views import generic
from news.models import Article, Category
from .forms import CommentForm
from django.http import HttpResponseRedirect
class IndexView(generic.ListView):
template_name = 'news/index.html'
context_object_name = 'latest_article_list'
def get_queryset(self):
return Article.objects.order_by("-pub_date").filter(is_published=True)[:6]
class CategoryView(generic.ListView):
template_name = 'news/categories.html'
context_object_name = 'category'
def get_queryset(self):
return Category.objects.all()
def article(request, article_id):
article = get_object_or_404(Article, pk=article_id)
context = {'article': article}
return render(request, 'news/article.html', context)
class ArticlesView(generic.ListView):
context_object_name = 'latest_article_list'
template_name = 'news/articles.html'
queryset = Article.objects.order_by("-pub_date")
def get_context_data(self, **kwargs):
context = super(ArticlesView, self).get_context_data(**kwargs)
context['category'] = Category.objects.all()
return context
def add_comment_to_article(request, pk):
article = get_object_or_404(Article, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = article
comment.save()
return HttpResponseRedirect(reverse('news:article', kwargs={"article_id": article.pk}))
else:
form = CommentForm()
return render(request, 'news/add_comment_to_article.html', {'form': form})
my urls.py :
from django.urls import path, include
from . import views
app_name = "news"
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:article_id>/', views.article, name='article'),
path('articles/', views.ArticlesView.as_view(), name='articles'),
path('search/', include('haystack.urls')),
path('<int:pk>/comment/', views.add_comment_to_article, name='add_comment_to_post'),
path('category/<int:category_id>', views.CategoryView.as_view(), name="category")
]
And the template im trying to render everything in, articles.html:
<div class="container">
{% block articles %}
<!-- ***************************************** -->
<ul>
<li>Categories:</li>
{% for category in category %}
<li>
<h1>{{ category.id}}</h1>
{{ category.category_title }}
</li>
{% endfor %}
</ul>
<!-- ***************************************** -->
<hr class="hr-style1">
<h2 class="article-list-title">Article List :</h2>
<hr class="hr-style2">
<div class="container list-wrapper">
{% for article in latest_article_list %}
<div class="container">
<div class="well">
<div class="media">
<a class="pull-left" href="{% url 'news:article' article.id %}">
<img class="media-object" src="{{ article.article_image.url }}">
</a>
<div class="media-body">
<h4 class="media-heading">{{ article.title }}
</h4>
<p class="text-right">{{ article.author }}</p>
<p>{{ article.description }}</p>
<ul class="list-inline list-unstyled">
<li><span><i class="glyphicon glyphicon-calendar"></i> {{ article.pub_date }} </span></li>
<li>|</li>
<span><i class="glyphicon glyphicon-comment"></i> 2 comments</span>
<li>|</li>
<li>
<span class="glyphicon glyphicon-star"></span>
<span class="glyphicon glyphicon-star"></span>
<span class="glyphicon glyphicon-star"></span>
<span class="glyphicon glyphicon-star"></span>
<span class="glyphicon glyphicon-star-empty"></span>
</li>
<li>|</li>
<li>
<span><i class="fa fa-facebook-square"></i></span>
<span><i class="fa fa-twitter-square"></i></span>
<span><i class="fa fa-google-plus-square"></i></span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
Apologies for the messy code, still trying to learn.
Thank you for taking the time to read this !
I'm not asking you to do this for me, an explanation will be enough ! Thanks !
You can override the get_queryset method on your ArticlesView by passing a filter param as follow:
class ArticlesView(generic.ListView):
context_object_name = 'latest_article_list'
template_name = 'news/articles.html'
def get_context_data(self, **kwargs):
context = super(ArticlesView, self).get_context_data(**kwargs)
# It would be best to rename the context to categories
# as you are returning multiple objects
context['categories'] = Category.objects.all()
return context
def get_queryset(self):
# Note you do not have to use the article PK you can use any
# article field just update the template argument accordingly
category_pk = self.request.GET.get('pk', None)
if category_pk:
return Article.objects.filter(article_category__pk=category_pk).order_by("-pub_date")
return Article.objects.order_by("-pub_date")
In your template you can then update the category links as follow:
<ul>
<li>Categories:</li>
{% for category in categories %}
<li>
<h1>{{ category.id}}</h1>
{{ category.category_title }}
</li>
{% endfor %}
<ul>
Give this a try and let me know if it works
I have been working thorough the DjangoGirls tutorial and was trying to improve on the section on adding comments to an application - TutorialExtensions
I have added the comments to a simple photo blog application but what I was attempting to do was replace the author = models.CharField(max_length=200) with an alternative that would store the current/logged-in user who was commenting on the photo instance and then allow me to display on the photo_detail template.
I thought I was close using author = models.ForeignKey(User, related_name='Commenter') but this through up an error:
NOT NULL constraint failed: timeline_comment.author_id
Here is my models.py consisiting of a Photo model and Comments model:
class Photo(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
title = models.CharField(max_length=120)
slug = models.SlugField(unique=True)
image = ProcessedImageField(upload_to=upload_location,
null=True,
blank=False,
processors=[Transpose(), ResizeToFit(1000, 1000, False)],
format='JPEG',
options={'quality': 50},
width_field="width_field",
height_field="height_field")
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
description = models.TextField(max_length=1000)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
class Comment(models.Model):
post = models.ForeignKey('timeline.Photo', related_name='comments')
author = models.CharField(max_length=200)
text = models.TextField(max_length=1000)
created_date = models.DateTimeField(default=timezone.now)
The related view:
def photo_detail(request, slug=None):
if not request.user.is_authenticated():
return HttpResponseRedirect("/accounts/login")
instance = get_object_or_404(Photo, slug=slug)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = instance
comment.save()
return redirect('timeline:detail', slug=instance.slug)
else:
form = CommentForm()
share_string = quote_plus(instance.description)
context = {
"title": instance.title,
"instance": instance,
"share_string": share_string,
"form": form,
}
return render(request, "photo_detail.html", context)
My forms.py:
class CommentForm(forms.ModelForm):
text = forms.CharField(widget=forms.Textarea, label='Leave a comment: ')
class Meta:
model = Comment
fields = [
"text",
]
Finally the template for the photo_detail view:
<div class="row">
<div class="col-md-12" id="comments">
<p>
{% if instance.comments.count == 0 %}
No Comments
{% elif instance.comments.count == 1 %}
{{ instance.comments.count }} Comment
{% else %}
{{ instance.comments.count }} Comments
{% endif %}
</p>
<hr style="margin-top: 10px;">
{% for comment in instance.comments.all %}
<div class="comment">
<div class="date pull-right">{{ comment.created_date | timesince }} Ago</div>
<strong>{{ comment.author }}</strong>
<p>{{ comment.text|linebreaks }}</p>
</div>
<hr>
{% empty %}
<p>No comments here yet :(</p>
{% endfor %}
</div>
</div>
{% if user.is_superuser or user.is_authenticated %}
<div class="row">
<div class="col-md-12">
<form method="POST" class="comment-form" action=''>
{% csrf_token %}
{{ form | crispy }}
<button type="submit" class="comment-add btn btn-lg btn-purple">Add</button>
</form>
</div>
</div>
{% endif %}
Could anybody recommend the best approach for this? Any help would be very much appreciated! Thank You.
Using the ForeignKey is correct[1] - the missing piece is that you need to assign that in your view. After comment = form.save(commit=False) just add one line:
comment.author = request.user
and it will work.
[1] although you don't want the related_name as "Commenter" (because it refers to the way you access the comment from the user: the default is comment_set which makes more sense).