In my Django project I have catalog of products, there is how its look like in models.py:
class Category(models.Model):
category = models.CharField(max_length=15)
description = models.CharField(max_length = 1000)
class Product(models.Model):
name = models.CharField(max_length=15)
description = models.CharField(max_length=1000)
category = models.ForeignKey(Category)
This is product detail view.
def ProductDetailView(request, pk):
productdetail = get_object_or_404(Product, pk=pk)
return render(request, 'product/detail.html', {'productdetail':productdetail})
And this is urls.py for product detail view:
url(r'^(?P<pk>[0-9]+)/$', views.ProductDetailView, name='detail'),
Now I need to add an order button on product detail page. When user click on this button, the data with the order have to save to the database, so i made a new model:
class Order(models.Model):
order_id = models.AutoField(primary_key=True, unique=True)
customer_name = models.CharField(max_length=20)
email = models.CharField(max_length=50)
product = models.ForeignKey(Product)
All datas for this model i take from the form, but i don't know how to get current product field. I will be thankful if you will help me with it.
You can add current item ID to HTML (by template tags). For example as hidden form field:
<input id="id_current_item_id" name="current_item_id" type="hidden"
value="{{ current_item.id }}"/>
Try
<input name="prouct_id" id="id_product" type="hidden" value="{{product.id}}">
and submit the order form. You will get product id in view.
Related
I am working on a product overview page in Django.
For this I have three models: category, brand, product.
I have created a View with ListView of the category. I loop through them to display them. I then want to open another overview of all brands within that category.
How do I do this?
Here are my models:
class Category(models.Model):
category_name = models.CharField(max_length=200)
sub_category = models.CharField(max_length=200,blank=True,null=True)
category_picture = models.ImageField(upload_to='category/', null=True, blank=True)
def __str__(self):
if self.sub_category is None:
return self.category_name
else:
return f" {self.category_name} {self.sub_category}"
class Meta:
ordering = ['category_name']
class Brand(models.Model):
category = models.ForeignKey('Category', on_delete=models.SET_NULL,null=True,blank=True)
brand_name = models.CharField(max_length=200)
brand_owner = models.CharField(max_length=200)
brand_story = models.TextField()
brand_country = models.CharField(max_length=200)
def __str__(self):
return f"{self.brand_name}"
class Bottle(models.Model):
category_name = models.ForeignKey('Category', on_delete=models.SET_NULL,null=True,blank=True)
brand = models.ForeignKey('Brand', on_delete=models.CASCADE)
bottle_name = models.CharField(max_length=255)
bottle_info = models.TextField()
bottle_tasting_notes = models.TextField()
bottle_barcode = models.IntegerField()
bottle_image = models.ImageField(upload_to='bottles/',null=True)
def __str__(self):
return f"{self.brand.brand_name} {self.bottle_name}"
How do I open a listview of all brands within a certain category from a link of the category listview?
First thing is to create another listview that displays all brands within a specific category. We do this by creating a new get_queryset() method.
views.py
class BrandListView(ListView):
model = Brand
def get_queryset(self):
return Brand.objects.filter(category__category_name=self.kwargs['category'])
Next add a url to your URLS.py so it can be accessed. We're using category_name as part of the url so it's human readable
from .views import BrandListView
urlpatterns = [
path('brands/<str:category>/', PublisherBookList.as_view()), name= "brand_list"
]
Then, as you loop through your categories in your template, create a link to the url
{% for category in categories %}
{{category.category_name}} : See brands in category
{% endfor %}
This will work as long as your categories have fairly simple names. If not, you might want to use the ID in the URL instead, or add a slug field to the model and use that.
I have a ModelChoiceField in a form that uses a TextInput widget. I want to be able to select a value from the database or add new entries to the database with this input. If the value is not already in the database, I get an error on the form that says "Select a valid choice. That choice is not one of the available choices."
Model
class FeedCategory(models.Model):
category = models.CharField(max_length=255, unique=True)
class RssFeed(models.Model):
category = models.ForeignKey(FeedCategory, null=True, on_delete=models.SET_NULL)
name = models.CharField(max_length=255)
feed = models.URLField()
Form
class RssForm(forms.Form):
name = forms.CharField()
feed = forms.URLField()
category = forms.ModelChoiceField(queryset=FeedCategory.objects.all(), to_field_name='category', widget=forms.TextInput())
def clean(self):
cleaned_data = super().clean()
????
Views
class RssCreateView(FormView):
template_name = 'dashboard/rss_feed_form.html'
form_class = RssForm
success_url = '/dashboard/'
def form_valid(self, form):
name = form.cleaned_data['name']
feed = form.cleaned_data['feed']
category = form.cleaned_data['category']
rss_obj = RssFeed(category=category, name=name, feed=feed)
rss_obj.save()
return super().form_valid(form)
Template
<form method="post">
{%csrf_token%}
{{form|crispy}}
<button type="submit">Save</button>
</form>
It might help you what I am using:
category = models.ForeignKey("General.entity",verbose_name='Category', db_column="CategoryEntityRef", null=False, blank=False)
so, what I am doing with this is creating a field that points to an existing category that exists in another table. It will display it as a dropdown box. However using this method will allow me to have the option to add another Category:
I'm building an app for personnel. Someone belongs in a company, which have different departments. A department from one company may have the same name with the department of another company.
The models:
class Company(models.Model):
COMPANIES = (('Comp1', 'Comp1'), ('Comp2', 'Comp2'), ('Comp3', 'Comp3'),)
name = models.CharField(primary_key=True, max_length=5, choices=COMPANIES)
def __str__(self):
return self.name
class Departments(models.Model):
name = models.CharField(max_length=10)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Personel(models.Model):
name = models.IntegerField(primary_key=True, unique=True)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
department = models.ForeignKey(Departments, on_delete=models.CASCADE)
The (very basic) form:
class PersonelForm(forms.ModelForm):
class Meta:
model = Personel
fields = ['name', 'company', 'department']
Companies and Departments are managed from the admin page.
The view:
def new_personel(request):
template = 'TestApp/new_personel.html'
form = PersonelForm(request.POST or None)
if form.is_valid():
form.save()
return HttpResponseRedirect('/thanks/')
context = {
'form': form
}
return render(request, template, context)
The template:
<form method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
With the current code, in the department select field are shown all the departments from all companies in the database. What I'm trying to achieve is when the user selects the company, the department select field dynamically being filled with the departments from the selected company.
All the solutions I managed to find requires the company being selected before the form loads (e.g. set company in a form and continue to another form for the rest fields, use of ModelChoiceField, use of limit_choices_to and define init).
Is there a way to achieve this through Django or with the use of JavaScript in the html?
(of course more than welcome a solution that can do that in the admin page also)
You could use the ModelSelect2 widget from django-autocomplete-light.
You would define a form
from dal import autocomplete
class PersonelForm(forms.ModelForm):
department = forms.ModelChoiceField(queryset=Department.objects.all(),
widget=autocomplete.ModelSelect2(url='department-autocomplete', forward=('company', )))
Then you need to define the department-autocomplete URL view
class DepartmentAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
queryset = Department.objects
company = self.forwarded.get('vzw')
if company:
queryset = queryset.filter(company__pk=company)
return queryset.filter(name__icontains=self.q) if self.q else queryset
The self.q in this view is the query that you're typing in the form. Also don't forget to import the necessary javascript and css as stated in the documentation.
I'm using Django 2.2 and PostgreSQL. I want to display the product information that the user has added to the detail page. I see the information in the 'StoreOtherInfo' model, but I don't see the information in the 'Product' model. How can I do that?
store/models.py
class StoreOtherInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,blank=True, null=True)
phone = models.CharField(max_length=11)
fax = models.CharField(max_length=11)
province = models.CharField(max_length=11)
district = models.CharField(max_length=11)
neighborhood = models.CharField(max_length=11)
def __str__(self):
return self.user.username
products/models.py
class Product(models.Model):
seller = models.ForeignKey(User, on_delete = models.CASCADE)
product_name = models.CharField(max_length = 50)
description = RichTextField()
added_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.seller
store/views.py
from store.models import StoreOtherInfo
from products.models import Product
def neighbor_detail(request,username):
neighbor_detail = get_object_or_404(User,username = username)
neighbor_list = StoreOtherInfo.objects.all()
product_list = Product.objects.all()
return render(request, 'store/neighbor_detail.html', {'neighbor_detail':neighbor_detail, 'neighbor_list':neighbor_list, 'product_list':product_list})
templates/neighbor_detail.html
<strong><p>{{neighbor_detail.first_name}} {{neighbor_detail.last_name}}</p></strong>
<p>{{neighbor_detail.username}}</p>
<p>{{neighbor_detail.email}}</p>
<p>{{neighbor_detail.storeotherinfo.phone}}</p>
<p>{{neighbor_detail.storeotherinfo.fax}}</p>
<p>{{neighbor_detail.storeotherinfo.province}}</p>
<p>{{neighbor_detail.storeotherinfo.district}}</p>
<p>{{neighbor_detail.storeotherinfo.neighborhood}}</p>
<p>{{neighbor_detail.product.product_name}}</p>
<p>{{neighbor_detail.product.description}}</p>
<p>{{neighbor_detail.product.added_date}}</p>
according to your Product model:
seller = models.ForeignKey(User, on_delete = models.CASCADE)
the relation between User model and Product model is one-to-many. This means every User(in this case seller) can have multiple Products.
So when you try to access the Product objects of a User object as you did in you template: <p>{{neighbor_detail.product.product_name}}</p> you end up giving an attribution error because neighbor_detail.product is not a single object of Product class it's a collection.
replace your template code with this and i hope you realize whats happening.
<strong><p>{{neighbor_detail.first_name}} {{neighbor_detail.last_name}}</p></strong>
<p>{{neighbor_detail.username}}</p>
<p>{{neighbor_detail.email}}</p>
<p>{{neighbor_detail.storeotherinfo.phone}}</p>
<p>{{neighbor_detail.storeotherinfo.fax}}</p>
<p>{{neighbor_detail.storeotherinfo.province}}</p>
<p>{{neighbor_detail.storeotherinfo.district}}</p>
<p>{{neighbor_detail.storeotherinfo.neighborhood}}</p>
{% for product in neighbor_detail.product_set.all %}
{{product.product_name}}<br/>
{{product.description}}<br/>
{{product.added_date}}<br/>
{% endfor %}
note that product_set is the default name that django associate with products related to each user.
A User can have multiple Products, so you can't do neighbor_detail.product because product isn't defined on a User. You need to loop through the list of products with {% for product in neighbor_detail.product_set.all %} and then you can display the properties of each product.
Read [this] for more information about one-to-many relationships.
I have an app that let users create blogs and allow other users to comment on each other blogs.The Problem is .In order to create a comment object , I require the blog id and text . I can grab the text data via post but I'm having trouble getting the blog id from POST and the only way I can think of getting it is via value field in the form
How can I grab the value field from POST?
My models
class Blog(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
created = models.DateTimeField(auto_now_add=True)
description = models.TextField()
class BlogComment(models.Model):
created = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User)
body = models.TextField()
blog = models.ForeignKey(Blog)
my forms.py
class BlogCommentForm(forms.ModelForm):
text = forms.CharField(required=False)
class Meta:
model = BlogComment
fields = ()
<form method ="POST"> {% csrf_token %}
<input type = "hidden" name="d" value= "blog.id" />
{{form}}
</form>
My views
def Blogs(request,blog_id):
form = BlogCommentForm(request.POST)
if request.method == "POST":
if form.is_valid():
text = form.cleaned_data['text']
value = form.cleaned_data['value']
form = BlogCommentForm()
blog.objects.get(pk=blog_id)
comment = BlogComment.objects.filter(blog=blog)
return render(request,'blogcomment.html',{'comment':comment,'form':form})
request.POST['d']
or to avoid raising an Exception if it's not there use
request.POST.get('d', False)
You can always get the blog id from ?= parameter in url.
When user goes to comment someone's blog the url might be http://yoursite.com/blog/id/comment or http://yoursite.com/blog/comment?blogid=12345.