How can i update with modelformset_factory on Django - python-3.x

I used the modelformset_factory method for multiple photo uploads. But when I want to update the post, I don't know how to do this, I tried something, but this only serves to re-upload photos and upload the uploaded photos again. How can I update or delete a previously uploaded photo? Also, I cannot access the photos in formset as {{formset.image}}. How can I access this?
Views.py
def post_update(request, slug):
post = get_object_or_404(Post, slug=slug)
if not request.user.is_authenticated and not request.user == post.seller or not request.user.is_admin:
raise Http404
ImageFormSet = modelformset_factory(PostImage, form=PostImageForm, extra=5, can_delete = True)
form = PostForm(data=request.POST or None, instance = post, files = request.FILES or None)
formset = ImageFormSet(data=request.POST or None, files= request.FILES or None, queryset=PostImage.objects.filter(post__slug=slug))
if form.is_valid():
if formset.is_valid():
for forms in formset.cleaned_data:
if forms:
image = forms['image']
print(forms['image'])
photo = PostImage(post=post, image=image)
photo.save()
form.save(commit=True)
messages.success(request,"Success")
return HttpResponseRedirect(reverse('gayrimenkul:detail',kwargs={'slug':form.instance.slug}))
return render(request,'post_update.html',{'form':form,'formset':formset,'slug':slug})
post_update.html
{% extends "main_page.html" %}
{% load static %}
{% block icerik %}
{% load crispy_forms_tags %}
<div class="row">
<div class="container">
<h2 class="page_header">İlan Ver</h2>
<hr>
{% if form.errors %}
{{form.errors}}
{% endif %}
<div class="col-md-12">
<form enctype="multipart/form-data" method="POST">
{% csrf_token %}
{{form.media}}
{{form|crispy}}
<div class="row">
<div class="col-md-6">
{{formset}}
</div>
<div class="col-md-6">
<button type="submit" id="inp" class="btn btn-outline-primary" style="float:right;">Kaydet</button>
</div>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
Creating posts works successfully.
def post_create(request):
if not request.user.is_authenticated:
raise Http404
ImageFormSet = modelformset_factory(PostImage, form=PostImageForm, extra=5)
if request.method == 'POST':
post_form = PostForm(request.POST, request.FILES)
formset = ImageFormSet(request.POST, request.FILES, queryset=PostImage.objects.none())
if post_form.is_valid():
created_post = post_form.save(commit=False)
created_post.seller = request.user
created_post.save()
for form in formset.cleaned_data:
if form:
image = form['image']
photo = PostImage(post=created_post, image=image)
photo.save()
messages.success(request,'Success')
return HttpResponseRedirect(reverse('gayrimenkul:detail',kwargs={'slug':created_post.get_slug()}))
else:
post_form = PostForm()
formset = ImageFormSet(queryset = PostImage.objects.none())
return render(request,'post_create.html',{'form':post_form,'formset':formset})

Before checking if the form is valid just filter the model of the formset
data = PostImage.objects.filter(post=post)
Give index of the item for a formset item starting form 0 and (f)the item itself and if the item of the id is not changed than save previous item itself else change the database image with the new image you have updated.
if formset.is_valid():
for index, f in enumerate(formset):
if f.cleaned_data:
if f.cleaned_data['id'] is None:
pic = PostImage(post=post, image=f.cleaned_data.get('image'))
pic.save()
elif f.cleaned.data['image'] is False:
pic = PostImage.objects.get(id = request.POST.get('form-' + str(index) + '-id'))
pic.delete()
else:
pic = PostImage(post=post, image=f.cleaned_data.get('image'))
d = PostImage.objects.get(id=data[index].id) #get slide id which was uploaded
d.image = pic.image # changing the database title with new title
d.save()
This might work for you or get you some idea.

Related

Issue displaying question for answer in views.py

I ran into a problem I have questions that are related to items_buy_id , there are also choices that are related to question_id questions
Questions items_buy_id It turns out to connect
And with the choice you will not contact as it should
My models.py
from django.db import models
from datetime import datetime
from phonenumber_field.modelfields import PhoneNumberField
from django_resized import ResizedImageField
from email.policy import default
from django.utils.translation import gettext_lazy
class Items_buy(models.Model):
class Meta:
db_table = 'items_buy'
verbose_name = 'Телефон который покупаем'
verbose_name_plural = 'Телефоны которые покупаем'
image_phone = ResizedImageField(size=[100,100], upload_to='for_sell/',verbose_name='Фотография модели телефона')
model_produkt = models.TextField(max_length=80, verbose_name='Модель продукта ')
text = models.TextField(max_length=500, verbose_name='Текст')
max_prise_iphone = models.FloatField(verbose_name='Максимальная цена telefoha')
image_phone_for_buy_bord = ResizedImageField(size=[100,100],upload_to='for_sell/',verbose_name='Фотография модели телефона ha prodazy')
def __str__(self):
return self.model_produkt
class Question(models.Model):
class Meta:
db_table = 'question'
verbose_name = 'Вопрос к телефону'
verbose_name_plural = 'Вопросы к телефону'
items_buy_id = models.ForeignKey(Items_buy, on_delete=models.RESTRICT)
title = models.CharField(max_length=150,verbose_name='Заголовок вопросa')
question_text =models.TextField(max_length=100, verbose_name='Заголовок вопросa text')
max_prise_qustion = models.FloatField(verbose_name='Максимальная цена')
def __str__(self):
return self.title
class Choice(models.Model):
class Meta:
db_table = 'choice'
verbose_name = 'Выбор ответа'
verbose_name_plural = 'Выбор ответов'
#items_buy_id = models.ForeignKey(Items_buy, on_delete=models.RESTRICT)
question_id = models.ForeignKey(Question, on_delete=models.RESTRICT)
title = models.CharField(max_length=1000, verbose_name='Заголовок выбора')
points = models.FloatField(verbose_name='Цена ответа')
#lock_other = models.BooleanField(default=False, verbose_name='Смотреть другой вариант ответа')
def __str__(self):
return self.title
My urls.py
from django.urls import path, re_path
from . import views
urlpatterns = [
path('',views.home, name ='home'),
path('sell_iphone/', views.sell_iphone, name = 'sell_iphone'),
path('sell_iphone_page/<int:pk>/', views.sell_iphone_page, name= 'sell_iphone_page'),
path("getqestion/<int:pk>/", views.getqestion, name = 'getqestion'),
]
My html
{% load static %}
{% block content %}
<head>
<link rel="stylesheet" href="{% static 'css/qestion.css' %}" type="text/css">
</head>
<body>
{% include 'navbar.html' %}
<div class="bar">
{% for question in test %}
<div class="bar_infor_bar">
<div class="bar_infor_bar_title">{{question.title}} </div>
<div class="wraper_sell_in_line_img_class2_qestion_text">{{question.question_text}}</div>
{% for choiceses in choice %}
<div class="bar_infor_button_nav">
<button class="bar_infor_button">{{choiceses.title}}</button>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</body>
{% endblock %}
My views.py
from django.shortcuts import render, redirect
from .models import Items_buy, Question, Choice, Answer, Orders
from django.core.paginator import Paginator,PageNotAnInteger,EmptyPage
def home(request):
return render(request, 'home.html')
def sell_iphone(request):
limit = request.GET.get('limit')
if limit == None:
limit = 40
limit = int(limit)
iphone = Items_buy.objects.filter()
count = iphone.count()
page = request.GET.get('page')
paginator = Paginator(iphone, 1)
try:
iphone = paginator.page(page)
except PageNotAnInteger:
page = 1
iphone = paginator.page(page)
except EmptyPage:
page = paginator.num_pages
iphone = paginator.page(page)
#pages = list(range(1, (paginator.num_pages + 1)))
iphone = Items_buy.objects.all()
#iphone = iphone[0:limit]
context = {'iphone':iphone, 'count':count, 'paginator':paginator, }
return render(request, 'sell_iphone.html', context)
def sell_iphone_page(request,pk ):
iphones = Items_buy.objects.filter(id=pk)
#question = Question.objects.all()
context = {'iphones':iphones, }
return render(request, 'sell_iphone_page.html', context)
`def getqestion( request, pk):
test = Question.objects.filter(items_buy_id = pk)
choice = Choice.objects.filter(question_id = pk)
context = {'test':test,'choice':choice}
return render(request, 'getqestion.html', context)`
I'm having a problem with the def getqestion function. I linked the question to the product, but the answer to the question didn't work at all
When using select choice = Choice.objects.filter(question_id = pk)
enter image description here
When using select choice = Choice.objects.all()
enter image description here
When using select choice = Choice.objects.filter(id = pk)
enter image description here
And you need 1.test1 to include: da, net, HY TAKOE
And 1.test2 included: 2,1,3
Thanks in advance to anyone who can suggest how to do this!!!
In my case it helped
views.py
class getqestion(generic.DetailView):
model = Items_buy
template_name = 'getqestion.html'
context_object_name = 'testing'
html
<div>
{% for testings in testing.question_set.all %}
<h1>{{testings.titles}}</h1>
<h3>{{testings.question_text}}</h3>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% csrf_token %}
<form action="{% url 'vote' testings.id%}" method="post">
{% for choice in testings.choice_set.all %}
<input type="checkbox" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{choice.title}}</label>
{% endfor %}
{% endfor %}
</div>
<input type="submit" value="vote">
</form>

django-filter not filtering the query

I applied django-filter library in my project if it's not filtering the items.
if i visit the url http://127.0.0.1:8000/products/?q=&category=electronics it should gives the only electronics products but its giving the all available products. What i am doing wrong? it should filter categories wise or product title wiase and price wise.
class ProductFilter(FilterSet): # by using django-filters
title = CharFilter(field_name='title', lookup_expr='icontains', distinct=True)
category = CharFilter(field_name='categories__title', lookup_expr='icontains', distinct=True)
category_id = CharFilter(field_name='categories__id', lookup_expr='icontains', distinct=True)
min_price = NumberFilter(field_name='price', lookup_expr='gte', distinct=True)
max_price = NumberFilter(field_name='price', lookup_expr='lte', distinct=True)
class Meta:
model = Product
fields = ['category', 'title', 'description', 'min_price', 'max_price']
class FilterMixin(object):
filter_class = ProductFilter
search_ordering_param = 'ordering'
def get_queryset(self, *args, **kwargs):
try:
qs = super(FilterMixin, self).get_queryset(*args, **kwargs)
return qs
except:
raise ImproperlyConfigured("You must have a queryset in order to use the FilterMixin")
def get_context_data(self, *args, **kwargs):
context = super(FilterMixin, self).get_context_data(*args, **kwargs)
qs = self.get_queryset()
ordering = self.request.GET.get(self.search_ordering_param)
if ordering:
qs = qs.order_by(ordering)
filter_class = self.filter_class
print(filter_class)
if filter_class:
f = filter_class(self.request.GET, queryset=qs)
context['object_list'] = f
return context
class ProductListView(FilterMixin, ListView):
queryset = Product.objects.all()
filter_class = ProductFilter
def get_context_data(self, *args, **kwargs):
context = super(ProductListView, self).get_context_data(*args, **kwargs)
context['filter_form'] = ProductFilterForm(data=self.request.GET or None)
return context
Template File-
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
<div class='col-sm-2'>
<form method="GET" action="{% url 'products:product-list' %}">
{{ filter_form|crispy }}
<input type='hidden' name='q' value='{{ request.GET.q }}' />
<input type='submit' value='Apply Filter' class='btn btn-default'>
</form>
Clear Filters
</div>
<div class='col-sm-12'>
<h3>All Products <small>*Categories*</small></h3>
{% if product_list %}
<div class="row">
{% for product in product_list %}
<div class="col">
{% include 'products/snippets/card.html' with instance=product %}
</div>
{% endfor %}
{% else %}
<p>No product found!!</p>
{% endif %}
</div>
</div>
{% endblock %}
Your FilterMixin never exports something like a product_list, so that will be the original queryset, not the one that you filter with the FilterSet.
You can easily update this with:
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
qs = context['object_list']
if self.filter_class:
qs = self.filter_class(self.request.GET, queryset=qs).qs
ordering = self.request.GET.get(self.search_ordering_param)
if ordering:
qs = qs.order_by(ordering)
context['object_list'] = qs
context_object_name = self.get_context_object_name(qs)
if context_object_name is not None:
context[context_object_name] = qs
return context

If statement in method in forms.py not processing

I'm having some trouble getting this validation to work. I want the form to only submit if there's a valid .yaml, .yml, or .json at the end of the URL I'm submitting.
forms.py:
class TemplateForm(FlaskForm):
template_url = URLField( 'Template URL', validators=[InputRequired(), URL(message='error')])
submit = SubmitField('Add Template')
def validate_filetype(self, field):
form = TemplateForm
template_path = form.template_url
ext = os.path.splitext(template_path)[1]
if ext not in ('.json', '.yml', '.yaml'):
raise ValidationError('Invalid File Type')
views.py:
#apps.route('/new-template', methods=['GET', 'POST'])
#login_required
#admin_required
def new_template():
"""Add a new app."""
form = TemplateForm()
if form.validate_on_submit():
template_location = form.template_url.data
flash("added template: " + template_location)
template_path = urlparse(template_location).path
ext = os.path.splitext(template_path)[1]
flash("Extension = " + ext )
if ext == '.json':
flash('var = .json')
template_filename = wget.download(template_location, out='app/storage/templates/json')
flash(template_filename)
elif ext in ('.yml', '.yaml'):
flash('var = .yaml')
return redirect(url_for('apps.index'))
return render_template('apps/new_template.html', form=form)
new_index.html:
{% extends 'layouts/base.html' %}
{% import 'macros/form_macros.html' as f %}
{% import 'macros/check_password.html' as check %}
{% block scripts %}
{% endblock %}
{% block content %}
<div class="ui stackable centered grid container">
<div class="twelve wide column">
<a class="ui basic compact button" href="{{ url_for('apps.index') }}">
<i class="caret left icon"></i>
Back to dashboard
</a>
<h2 class="ui header">
New App Template
<div class="sub header">Add a new app template</div>
{% set flashes = {
'error': get_flashed_messages(category_filter=['form-error']),
'warning': get_flashed_messages(category_filter=['form-check-email']),
'info': get_flashed_messages(category_filter=['form-info']),
'success': get_flashed_messages(category_filter=['form-success'])
} %}
{{ f.begin_form(form, flashes) }}
{{ f.render_form_field(form.template_url, extra_classes=novalidate) }}
{{ f.render_form_field(form.submit) }}
{{ f.end_form() }}
</h2>
</div>
</div>
{% endblock %}
No matter what I do I can't get the raise ValidationError('Invalid File Type') to work. I'm trying to just use https://test.com and it won't throw the validation error.
Please let me know if there's anything else I should attach to provide more information. Everything is importing correctly so I'm pretty sure it's not a dependency issue.
This is the boiler plate I'm using: https://github.com/hack4impact/flask-base
This resolved it. Thank you #ngShravil.py I needed to use a custom validator and separate it into it's own method (outside of the class).
def validate_filetype(form, field):
template_path = field.data
ext = os.path.splitext(template_path)[1]
if ext not in ('.json', '.yml', '.yaml'):
raise ValidationError('Invalid File Type')
class TemplateForm(FlaskForm):
template_url = URLField( 'Template URL', validators=[InputRequired(), URL(message='error'), validate_filetype])
submit = SubmitField('Add Template')

pass a parameter to a view function (form) in a for loop to populate form flask wtforms sqlalchemy

I want to be able to display the rows of a database model on my web page as an updatable prepopulated form! I can display the rows on the page easily and I can add a link to each to open a seperate page to edit each row, I can also display each row with the update form, but I cant display the form populated. here is my code:
#bp.route('/stock', methods=['GET', 'POST'])
#bp.route('/stock/<int:id>', methods=['GET', 'POST'])
#login_required
def stock(id=None):
if id is not None:
obj = Stock.query.get_or_404(id)
form = AddStockForm(request.form, obj=obj)
if form.validate_on_submit():
form.populate_obj(obj)
db.session.commit()
return redirect(url_for('stock.stock'))
else:
form = AddStockForm()
page = request.args.get('page', 1, type=int)
stock = Stock.query.order_by(Stock.id.desc()).paginate(
page, current_app.config['ITEMS_PER_PAGE'], False)
next_url = url_for('stock.stock', page=stock.next_num) \
if stock.has_next else None
prev_url = url_for('stock.stock', page=stock.prev_num) \
if stock.has_prev else None
return render_template('stock/stock.html',form=form, title=Stock, stock=stock.items,
next_url=next_url, prev_url=prev_url)
and the stock.html code:
{% extends "base.html" %}
{% block content %}
<div class="main">
<h2>Stock</h2>
<div class="books">Upload Stock csv
</div>
<div class="books">Add a new Item</div>
{% for s in stock %}
{% include 'stock/_stock.html' %}
{% endfor %}
</div>
_stock.html code:
<div class="stock">
<div class="c0"><img src="{{ s.image_url }}" alt="{{ s.image_filename }}"></div>
<form action="{{ url_for('stock._stock', id=s.id) }}" method="post",
enctype="multipart/form-data">
{{ form.hidden_tag() }}
<div>SKU<BR> {{ s.id }} </div>
<div>Date of Purchase<br>{{ form.date(class="input") }}</div>
<div>Description<br>{{ form.description(class="input") }}</div>
<div>Market<br>{{ form.event(class="input") }}</div>
<div>Purchase Price<br>{{ form.achat(class="input") }}</div>
<div>Sale Price<br>{{ form.vente(class="input") }}</div>
<div>Sold<br>{{ form.sold(class="input") }}</div>
<div>{{ form.submit(class="submit") }}</div>
</form>
</div>
on google developer tools each form shows stock/4 or 3 but this does not seem to then populate the form. there are no error messages.
thanks in advance for any help.
regards Paul
EDIT
hi #Greg Cowell, Thank you for your help, I have addapted your code but I Get this error
File "/var/www/accounts/bdf/templates/base.html", line 30, in root
</body>
File "/var/www/accounts/env/lib/python3.7/site-packages/jinja2/runtime.py", line 262, in call
return __obj(*args, **kwargs)
File "/var/www/accounts/env/lib/python3.7/site-packages/flask/helpers.py", line 370, in url_for
return appctx.app.handle_url_build_error(error, endpoint, values)
File "/var/www/accounts/env/lib/python3.7/site-packages/flask/app.py", line 2215, in handle_url_build_error
reraise(exc_type, exc_value, tb)
File "/var/www/accounts/env/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/var/www/accounts/env/lib/python3.7/site-packages/flask/helpers.py", line 358, in url_for
endpoint, values, method=method, force_external=external
File "/var/www/accounts/env/lib/python3.7/site-packages/werkzeug/routing.py", line 2020, in build
raise BuildError(endpoint, values, method, self)
werkzeug.routing.BuildError: Could not build url for endpoint 'stock.stock'. Did you forget to specify values ['id']?
[pid: 29588|app: 0|req: 1/1] 192.168.0.13 () {48 vars in 1095 bytes} [Sun Nov 17 09:26:58 2019] GET /index =>
here is the adapted code:
#bp.route('/stock/stock/<int:id>/', methods=['GET', 'POST'])
#login_required
def stock(id=None):
if id is not None:
group = current_user.group()
try:
stock = Stock.query.filter_by(group=group, id=id).one()
except NoResultFound:
flash('Invalid account.')
return redirect(url_for('stock.add_stock'))
accounts = current_user.group().stock
form = AddStockForm()
form.stock_id.default = stock.id
if form.validate_on_submit():
if form.modify.data:
for s in stock:
if (
item.id == form.stock_id.data and
item.id != form.stock_id.default
):
flash('Another account already has this name.')
return redirect(url_for('stock.add_stock', id=id))
stock.id = form.stock_id.data
db.session.add(stock)
db.session.commit()
form.process() # Do this after validate_on_submit or breaks CSRF token
else:
form = AddStockForm()
page = request.args.get('page', 1, type=int)
stock = Stock.query.order_by(Stock.id.desc()).paginate(
page, current_app.config['ITEMS_PER_PAGE'], False)
next_url = url_for('stock.stock', page=stock.next_num) \
if stock.has_next else None
prev_url = url_for('stock.stock', page=stock.prev_num) \
if stock.has_prev else None
return render_template('stock/stock.html',form=form, title=Stock, stock=stock.items,
next_url=next_url, prev_url=prev_url)
SECOND EDIT
I added this to the top of the view function:
#bp.route('/stock', methods=['GET', 'POST'])
which got rid of the above error, I then got a similar error for the "stock.html code"
{% for s in stock %}
{% include 'stock/_stock.html' %}
{% endfor %}
which I changed to:
{% include {{ url_for('stock._stock', id=['s.id']) }} %}
Which gives me the following error:
jinja2.exceptions.TemplateSyntaxError: expected token ':', got '}'
I use a different method for prepopulating forms.
In summary, I set the default for each form field and process the form before rendering. In the example below I set the value for the account_name field default using form.account_name.default = account.accname and then call form.process() before rendering the form.
#web.route('/accounts/modify/<int:accno>/', methods=['GET', 'POST'])
#login_required
def modify_account(accno):
"""
Modify or delete accounts.
Return a form for modifying accounts or process submitted
form and redirect to Accounts HTML page.
"""
group = current_user.group()
try:
account = Account.query.filter_by(group=group, accno=accno).one()
except NoResultFound:
flash('Invalid account.')
return redirect(url_for('.accounts_page'))
accounts = current_user.group().accounts
form = ModifyAccountForm()
form.account_name.default = account.accname
if form.validate_on_submit():
if form.modify.data:
for item in accounts:
if (
item.accname == form.account_name.data and
item.accname != form.account_name.default
):
flash('Another account already has this name.')
return redirect(url_for('.modify_account', accno=accno))
account.accname = form.account_name.data
db.session.add(account)
db.session.commit()
elif form.delete.data:
for transaction in current_user.group().transactions:
if transaction.account == account:
unknown_account = Account.query.filter_by(
group=current_user.group(), accname='Unknown').one()
transaction.account = unknown_account
db.session.add(transaction)
db.session.commit()
db.session.delete(account)
db.session.commit()
elif form.cancel.data:
pass
return redirect(url_for('.accounts_page'))
form.process() # Do this after validate_on_submit or breaks CSRF token
return render_template(
'modify_account.html', form=form, accno=accno, menu="accounts")
To make an HTML page which has a form for each record and an individual submit button for each record, you need to create multiple forms in your view/route function and then loop through them all in your HTML template.
View/route:
#web.route('/stocks', methods=['GET', 'POST'])
def stocks():
"""Return Stocks HTML page."""
stocks = Stock.query.all()
forms = []
for stock in stocks:
form = ModifyStockForm()
form.stock_id.default = stock.stock_id
form.stock_name.default = stock.stock_name
forms.append(form)
for form in forms:
if form.validate_on_submit():
if form.modify.data:
stock = Stock.query.filter_by(stock_id=form.stock_id.data).one()
stock.stock_name = form.stock_name.data
db.session.add(stock)
db.session.commit()
elif form.delete.data:
stock = Stock.query.filter_by(stock_id=form.stock_id.data).one()
db.session.delete(stock)
db.session.commit()
return redirect(url_for('.stocks'))
form.process() # Do this after validate_on_submit or breaks CSRF token
return render_template('stocks.html', forms=forms, stocks=stocks)
Template:
<h2>Stocks:</h2>
{% for form in forms %}
<form method="post" role="form" enctype="multipart/form-data">
{{ form.hidden_tag() }}
{{ form.stock_id }}
{{ form.stock_name }}
{{ form.modify }}
{{ form.delete }}
</form>
{% endfor %}
I've put a complete example in this repo: Example of multiple forms on a single page

unable to save Foreign key object to the model.cc

I am trying to save the data from views, My two models are:
models.py
class Customer(models.Model) :
name = models.CharField(max_length=25)
address = models.CharField(max_length=250)
phone_number = models.IntegerField()
email = models.EmailField(max_length=35)
contact_person = models.CharField(max_length=25)
created_date = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return self.name
class Product(models.Model):
support = models.CharField(max_length=8, choices=support_choice, null=True)
amc_date = models.DateField(null=True)
amc_product = models.CharField(max_length=500, default="No Products in amc")
warranty_date = models.DateField(null=True)
warranty_product_list = models.CharField(max_length=500, default="No Products in warranty")
product_name = models.CharField(max_length=100, null=True)
serial_number = models.CharField(max_length=50, null=True)
customer = models.ForeignKey(Customer)
def __str__(self):
return self.product_name
i have created a form for the Product:
class ProductForm(forms.ModelForm):
support = forms.ChoiceField(choices=support_choice, required=True,)
amc_date = forms.DateField(required=False, widget=forms.TextInput(attrs={'placeholder': 'ex: 10/25/2006'}))
amc_product = forms.CharField(required=False, widget=forms.TextInput(attrs={'placeholder': 'Products listed in AMC'}))
warranty_date = forms.DateField(required=False, widget=forms.TextInput(attrs={'placeholder': 'ex: 10/25/2006'}))
warranty_product_list = forms.CharField(required=False, widget=forms.TextInput(attrs={'placeholder': 'Products listed in warranty'}))
product_name = forms.CharField(required=True, widget=forms.TextInput(attrs={'placeholder':'Product model'}))
serial_number = forms.CharField(required=True)
class Meta:
model = Product
fields = ['support', 'amc_date', 'amc_product', 'warranty_date', 'warranty_product_list', 'product_name',
'serial_number']
in my views.py i am trying to save the Foreign key object to the Product database but i am getting an error "Cannot assign "'Sabaree'": "Product.customer" must be a "Customer" instance."
views.py
def product_detail(request):
cust = request.POST.get('customer_name')
obj = Customer.objects.all()
obj1 = obj.filter(name=cust)
print (cust)
if request.method == 'POST':
form = ProductForm(request.POST)
if form.is_valid():
a = form.save(commit=False)
a.customer = cust
form.save()
context = {'obj':obj, 'form':form}
return render(request,"products.html",context)
and my template is:
products.html
{% block content %}
<script type="text/javascript" src="//code.jquery.com/jquery-1.12.0.min.js"></script>
<script src="{% static 'js/product_detail.js' %}"></script>
<div class="container">
<h2>Products</h2>
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
<div class="controls ">
<select class="select form-control" id="id_customer_name" name="customer_name">
{% for i in obj %}
<option id="{{ i.id }}" value="{{ i.name }}">{{ i.name }}{{ i.id }}</option>
{% endfor %}
</select>
</div>
{{ form|crispy }}
<input type="submit" class="btn btn-default " value="Submit">
</form>
</div>
{% endblock %}
I am not sure how to save the data which is assigned as Foreign key in Product table.
Since Customer is foreign key you cannot assign the value you get from POST method. Try either of this
a.customer.name = cust
or you convert it to Customer table object as follows
cust_obj = Customer.objects.get(name=cust) # Assuming cust is unique or do a query to return obj
then while save,
a.customer = cust

Resources