Hi Perhaps someone could point me in the right direction, i am learning Django through Tango with Django and i am also following along with the official Django tutorials as well as creating my own Django app for purchase orders.
I need to understand how I can access the Foreign key details of another Model and save it using forms. Basically my app has Orders and Suppliers when creating an order I can get the supplier foreign key options to appear on the form but when I save it I also want to save with the suppier_name into the orders table currently it just saves with the supplier_id, I have searched through many examples of different scenarios but just can't understand it thanks.
view.py
def add_order(request):
if request.method == 'POST':
form = OrderForm(request.POST)
if form.is_valid():
form.save(commit=True)
return orders(request)
else:
print(form.errors)
else:
form = OrderForm()
context_dict = {'form':form}
return render(
request,
'purchaseorders/add_order.html',
context_dict
)
model.py
# Create your models here.
class Supplier(models.Model):
supplier_code = models.CharField(max_length=10)
supplier_name = models.CharField(
max_length=100,
unique=True
)
supplier_email = models.EmailField(max_length=100)
supplier_website = models.URLField(max_length=100)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.supplier_name)
super(Supplier,self).save(*args, **kwargs)
def __unicode__(self):
return self.supplier_name
def __str__(self):
return self.supplier_name
class Meta:
verbose_name_plural = "Suppliers"
class Order(models.Model):
supplier = models.ForeignKey(Supplier)
po_number = models.IntegerField(default=0)
ordered_by = models.CharField(max_length=50)
order_date = models.DateTimeField()
supplier_name = models.CharField(max_length=50)
net_value = models.DecimalField(
decimal_places=2,
max_digits=10
)
class Meta:
verbose_name_plural = "Orders"
def __unicode__(self):
return self.po_number
forms.py
from django import forms
from PurchaseOrders.models import Supplier, Order
class SupplierForm(forms.ModelForm):
supplier_code = forms.CharField(
max_length=10,
help_text="Please enter a unique code"
)
supplier_name = forms.CharField(
max_length=100,
help_text="Please enter the Suppliers full name"
)
supplier_email = forms.EmailField(
max_length=100,
help_text="Please enter a email address"
)
supplier_website = forms.URLField(
max_length=100,
help_text="Please enter a website"
)
slug = forms.CharField(
widget=forms.HiddenInput(),
required=False
)
# an inline class to provide additional information on the form
class Meta:
# provide an association between the ModelForm and model
model = Supplier
fields = (
'supplier_code', 'supplier_name',
'supplier_email', 'supplier_website'
)
class OrderForm(forms.ModelForm):
#list all form details except the Foreignkey connection
po_number = forms.IntegerField(
help_text="please enter a PO Number"
)
ordered_by = forms.CharField(
max_length=50,
help_text="please enter your name"
)
order_date = forms.DateTimeField(
help_text="please enter a date of order"
)
#supplier_name = forms.ModelChoiceField(
queryset=Supplier.objects.all()
)
net_value = forms.DecimalField(
decimal_places=2,
max_digits=10,
help_text="please enter a net amount"
)
class Meta:
# provide an association between the ModelForm and model
model = Order
html
{% load staticfiles %} <!-- New line -->
<html>
<head>
<title>Purchase Orders</title>
</head>
<body>
<img src="{% static "purchaseorders/images/po_icon.png" %}"
alt="PO icon" />
<h1>Add a Order</h1>
<form id="order_form" method="post"
action="/PurchaseOrders/add_order/{{ supplier }}">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<ul style="list-style-type:none ">
{% for field in form.visible_fields %}
<li></li>
{{ field.errors }}
{{ field.help_text }}
<li>{{ field }}</li>
{% endfor %}
</ul>
<input type="submit" name="submit" value="Add Order" />
</form>
</body>
</html>
To start with the question as-asked, you could capture this data in the model's save() method:
class Order(models.Model):
[...]
def save(self, *args, **kw):
if self.supplier_id is not None:
self.supplier_name = self.supplier.supplier_name
super(Order, self).save(*args, **kw)
HOWEVER, although there are some cases where the above might be correct (such as if supplier name is expected to change), it is much more typical to simply access a related field through the existing relationship, ex:
myorder.supplier.supplier_name
Related
I'm trying to populate a field with images from a model in Django. The idea is that the user will enter the name of their product, then ultimately an API with google images will look that up and populate a field on the next page with a couple images to select.
At this stage, I'm just trying to get a field on the form to show multiple images for the user to select and I'm having a hard time. Here's some of my code, any input is helpful. I know there is a lot out there around this topic and I've looked through a lot but I'm still stuck. My most recent attempt was to create a custom Widget, I'm really open to any solution that will work.
I'm really not a Django/Python wizard so bear with me :) Thank you!
Models.py
class ProductImage(models.Model):
imageId = models.AutoField(auto_created=True, primary_key=True)
image = models.ImageField(upload_to='images',null=True,blank=True)
def __str__(self):
return str(self.image)
class Item(models.Model):
itemId = models.AutoField(auto_created=True, primary_key=True)
itemName = models.CharField(
"Name",
max_length=1024,
)
category = models.ForeignKey(Category,
on_delete=models.CASCADE,
related_name='category'
)
itemImage = models.ForeignKey(ProductImage,
on_delete=models.CASCADE,
related_name='photo',
default="",
)
itemOwner = models.ForeignKey(Customer,
on_delete=models.CASCADE,
related_name='my_items'
)
itemAvaialable = models.BooleanField()
costPerItem = models.IntegerField(verbose_name='Cost per Item (USD)')
itemDescription = models.TextField(null=True, blank=True)
itemAddedDate = models.DateField(auto_now_add=True)
asin = models.CharField(null=True, blank=True, max_length=10)
forms.py
class ImageCreationForm(forms.ModelForm):
class Meta:
model = ProductImage
fields = ('image',)
def clean_itemImage(self):
itemImage = self.cleaned_data['itemImage']
valid_extensions = ['jpg', 'jpeg']
extension = itemImage.rsplit('.', 1)[1].lower()
if extension not in valid_extensions:
raise forms.ValidationError('The given product Image file does not ' \
'match valid image extensions.')
return itemImage
class ItemCreationForm(forms.ModelForm):
class Meta:
model = Item
fields = '__all__'
widgets = {
'itemAddedDate': forms.HiddenInput,
}
Views.py
class AddImageView(LoginRequiredMixin,CreateView):
model = ProductImage
template_name = 'addImage.html'
fields = ('image',)
def form_valid(self, form):
form.is_valid()
form.instance.itemOwner = self.request.user
return super().form_valid(form)
def get_success_url(self):
return reverse('RentalApp:my_products')
class AddProductView(LoginRequiredMixin, CreateView):
model = Item
template_name = 'addProduct.html'
image = forms.FileField(required=False)
fields = ('itemName',
'category',
'itemImage',
'itemAvaialable',
'costPerItem',
'itemDescription')
login_url = '/users/login/'
def form_valid(self, form):
form.fields["itemImage"].queryset = ProductImage.objects.all()
form.is_valid()
form.instance.itemOwner = self.request.user
return super().form_valid(form)
def get_success_url(self):
return reverse('RentalApp:my_products')
Widgets.py
class ImageWidget(forms.widgets.Widget):
def render(self, name, value, attrs=None, **kwargs):
html = Template("""<img src="$link"/>""")
return mark_safe(html.substitute(link=value))
Serializers.py
class ProductImageSerializer(serializers.ModelSerializer):
product_image = serializers.SerializerMethodField()
class Meta:
model = ProductImage
fields = ('image')
class ProductImageRequirementSerializer(serializers.ModelSerializer):
class Meta:
model = ProductImage
fields = ('image')
class ProductSerializer(serializers.ModelSerializer):
Product_requirement = serializers.SlugRelatedField(many=True,read_only=True,slug_field='text')
club_image = ProductImageSerializer(many=True)
class Meta:
model = ProductImage
fields = ('image')
Template for adding a product:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div id="login">
<h5 class="text-center pt-5">Add Product</h5>
<div id="login-row" class="row justify-content-center align-items-center">
<div id="login-column" class="col-md-6">
<div id="login-box" class="col-md-12">
<form action="" method="post" id="login-form" enctype="multipart/form-data" class="form">{% csrf_token %}
{{ form|crispy }}
<br>
<button class="btn btn-success ml-2" type="submit">Save</button>
<a href="{% url 'RentalApp:my_products' %}" class="btn btn-secondary ml-2">
Cancel</a>
</form>
</div>
</div>
</div>
</div>
{% endblock content %}
models.py
here is my model
class Load_post(models.Model):
user = models.ForeignKey(get_user_model(),on_delete=models.CASCADE)
pick_up_station = models.CharField(max_length=150)
destination_station = models.CharField(max_length=150)
sender_name = models.CharField(max_length=150)
phone_number = PhoneNumberField(null=False , blank=False , unique=True)
receiver_name = models.CharField(max_length=150)
sending_item = models.CharField(max_length=150)
weight = models.CharField(max_length=150)
metric_unit = models.CharField(max_length=30, default='SOME STRING')
quantity = models.PositiveIntegerField(default=1)
requested_shiiping_price = models.PositiveIntegerField()
pick_up_time = models.DateField()
drop_time = models.DateField()
paid_by = models.CharField(max_length=150)
created_at = models.DateTimeField(auto_now=True)
published_date = models.DateField(blank=True, null=True)
def __str__(self):
return self.user.username
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
def publish(self):
self.published_date = timezone.now()
self.save()
def get_absolute_url(self):
return reverse('local')
class Meta:
ordering = ["-created_at"]
unique_together = ["sender_name", "receiver_name"]
please check the phone number
forms.py
this is form.py
class Loader_post_form(forms.ModelForm):
phone_number = PhoneNumberField()
metric_unit = forms.ChoiceField(choices=UNIT, required=True)
class Meta:
model = Load_post
fields = ("pick_up_station", "destination_station",
"sender_name", "phone_number", "receiver_name",
"sending_item","image_of_load","weight","metric_unit",
"quantity","requested_shiiping_price","pick_up_time",
"drop_time","paid_by")
views.py
This is my views.py
absolute URL used in models already
class Loader_post_view(CreateView, LoginRequiredMixin):
login_url = 'Driver/login/'
form_class = forms.Loader_post_form
model = Loader_Signup
template_name = "Driver/post.html"
def form_valid(self,form):
form.instance.user = self.request.user
form.save()
return super(Loader_post_view,self).form_valid(form)
post.html
this is html page (template)
{% extends "Driver/base.html" %}
{% block content %}
<h1>create a post</h1>
{% csrf_token %}
{{form}}
<button type="submit">submit</button>
{% endblock content %}
this is html code
how to add it to the database
and I cannot see any error in my forms
thank you
am working on driver and client-side project
From what I see you html template cannot submit the form because you ae missing the <form> tags - if you do not have them hidden in your base.html.
Your html template should be something like this:
{% extends "Driver/base.html" %}
{% block content %}
<h1>create a post</h1>
<form method="POST">
{% csrf_token %}
{{form}}
<button type="submit">submit</button>
</form>
{% endblock content %}
The {{ form }} renders the form with all the inputs but does not create the tags needed for html forms.
In addition there are some other errors in the code you posted.
In your view the model you defined is called Loader_Signup, however the model you posted is Load_post. Either you posted the wrong model or you declared the wrong model in your view.
In your form one field is called image_of_load, however, this field is not part of you model.
In your model you have got a field called phone_number, you are defining a field with the same name in your form. The field in your form has got no connection to your model so take it out.
Unfortunately you are not providing any details about your PhoneNumberField so this cannot be checked.
I'm new to Django and I would like to create a "modular registering form".
The aim of this form is to be able to select the needed form (related to the user type) to complete the registration of a new user.
models.py
class UserTypes(models.Model):
USER_TYPES = (
('simple', 'simple'),
('advanced', 'advanced')
)
user_type = models.CharField(max_length = 10, choices = USER_TYPES)
class FirstClass(models.Model):
username = models.CharField(max_length=100, null=True)
first_name = models.CharField(max_length=100, null=True)
last_name = models.CharField(max_length=100, null=True)
class SecondClass(models.Model):
link_to_first_class = models.OneToOneField(FirstClass, on_delete=models.CASCADE, null=True)
other_informations = models.CharField(max_length=200, null=True)
forms.py
class UserTypesForm(forms.ModelForm):
class Meta:
model = UserTypes
fields = '__all__'
class FirstClassForm(forms.ModelForm):
class Meta:
model = FirstClass
fields = '__all__'
class SecondClassForm(forms.ModelForm):
class Meta:
model = SecondClass
fields = '__all__'
exclude = ('link_to_first_class',)
views.py
#transaction.atomic
def modular_register(request):
if request.method == 'POST':
user_types = UserTypesForm(request.POST)
first_form = FirstClassForm(request.POST)
second_form = SecondClassForm(request.POST)
if user_types_form.is_valid() and first_form.is_valid() and second_form.is_valid():
first_form.save()
first_class_instance = FirstClass.objects.filter(username = first_form.data['username'])[0]
second_class = SecondClass(link_to_first_class = first_class_instance,
other_informations = second_form.data['other_informations'])
second_class.save()
messages.success(request, 'Account created successfully')
return redirect('modularregister')
else:
user_types_form = UserTypesForm()
first_form = FirstClassForm()
second_form = SecondClassForm()
return render(request, 'blog/modularregister.html', {'user_types_form':user_types_form, 'first_form': first_form, 'second_form' : second_form} )
template
<form method="post" >
{% csrf_token %}
<table>
{{ user_types_form.as_table }}
{{ first_form.as_table }}
{{ second_form.as_table }}
<tr>
<td><input type="submit" name="submit" value="Register" /></td>
</tr>
</table>
</form>
Explanation :
If the user select "simple" as user_type only the FirstClassForm need to appear.
If the user select "advanced" the two forms (FirstClassForm and SecondClassForm) need to appear.
So I read some articles about the "OnChange" function which requires the writing of a script.
So here is my question :
According to you, what is the best way to select only the needed forms and how to handle that in the view ?
I have problem with connect two models on one page, detail page (Django 1.11).
I have model Event - I want to display details for this model on detail page - this is working for me.
class Event(models.Model):
title = models.CharField(max_length=500)
date = models.DateField()
text = models.TextField()
image = FilerImageField(null=True, blank=True)
free_places = models.IntegerField()
class Meta:
ordering = ['-date']
def __str__(self):
return self.title
On another hand I have model Register
class Register(models.Model):
event = models.ManyToManyField(Event)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
company = models.CharField(max_length=30, blank=True)
street = models.CharField(max_length=50, blank=True)
post_code = models.CharField(max_length=30, blank=True)
city = models.CharField(max_length=30, blank=True)
email = models.EmailField()
phone_number = models.IntegerField(max_length=30)
def __str__(self):
return self.first_name
I want to signup user on event with folder on detail page, below details for events.
Here is my detail view, where I want to display details for event and take data from user to Register model:
class EventDetailView(DetailView, FormMixin):
model = models.Event
form_class = forms.RegisterForm
def get_success_url(self):
return reverse('events:list')
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
Template:
{% extends 'base.html' %}
{% block content %}
<ul>
<h1>Detail page:</h1>
<li>{{ object.title }}</li>
<li>{{ object.text }}</li>
<li>{{ object.date }}</li>
</ul>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
After push submit button I have no items in Register model.
The default definition of form_valid on FormMixin is simply to redirect to the success URL. That's because it doesn't know anything about models, so it is not expecting a .save() method on the form.
You should use ModelFormMixin instead.
My problem is that I can not save the form. I think the problem lies in the event field in the Register model.
I do not want the user to choose an Event from the list, I want it to happen automatically, hence the code: form.cleaned_data['event'] = kwargs['pk']
This part of code kwargs['pk'] is from url.
Please any hint if this is good approch to dealing with forms and hint to solve my problem. Below is my code.
Thanks :)
Models:
class Event(models.Model):
title = models.CharField(max_length=500)
date = models.DateField()
text = models.TextField()
image = FilerImageField(null=True, blank=True)
flag = models.ForeignKey(Flag)
free_places = models.IntegerField()
class Meta:
ordering = ['-date']
def __str__(self):
return self.title
#property
def slug(self):
return slugify(self.title)
def get_absolute_url(self):
return reverse('events:detail', args=[self.slug, self.id])
class Register(models.Model):
event = models.ForeignKey(Event)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
company = models.CharField(max_length=30, blank=True)
street = models.CharField(max_length=50, blank=True)
post_code = models.CharField(max_length=30, blank=True)
city = models.CharField(max_length=30, blank=True)
email = models.EmailField()
phone_number = models.IntegerField()
def __str__(self):
return self.first_name
def get_event_name(self):
return self.event
View:
class EventDetailView(DetailView, ModelFormMixin):
model = models.Event
form_class = forms.RegisterForm
def get_success_url(self):
return reverse('events:list')
def post(self, request, *args, **kwargs):
form = self.get_form()
print(kwargs['pk'])
print(self.form_class)
if form.is_valid():
print(form.cleaned_data['event'])
form.cleaned_data['event'] = kwargs['pk']
form.save()
return self.form_valid(form)
else:
return self.form_invalid(form)
My form:
class RegisterForm(ModelForm):
class Meta:
model = models.Register
fields = ('event', 'first_name', 'last_name', 'company', 'street', 'post_code', 'city', 'email', 'phone_number',)
My template:
{% extends 'base.html' %}
{% block content %}
<ul>
<h1>Detail page:</h1>
<li>{{ object.title }}</li>
<li>{{ object.text }}</li>
<li>{{ object.date }}</li>
</ul>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
What you are doing here is to insert into a validated data. Instead of that,
Initialize the form with request POST data which should include "event" key and its value you got from kwargs['pk']. Then validate it and save. You will not get validation errors, as well as the value will be saved.
Basically, even the event id you get from the url that has to be validated. Django does with db level check against the pk value you passed when you call is_valid.