I’m trying to make a sales app with what I thought was going to be simple features, but I’m having a lot of struggles with some of those features:
- I want to make a form like the ones in the admin panel, with an inline and the possibility to create a new item for a model. I already made one that works exactly as I want it to do so (in the admin panel) for the “Order” model, so I’ll show you the code.
I also found a way to do it using JS, but I want to know if there’s an easier way. - Auto-populate fields based on other models.
This is the important part of the code that I have so far (without the JS solution):
Models
class Product(models.Model):
category = models.ForeignKey(
Category, related_name="products", on_delete=models.CASCADE
)
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True)
image = models.ImageField(upload_to="products/%Y/%m/%d", blank=True)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
available = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ("name",)
index_together = (("id", "slug"),)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("sales:product_detail", args=[self.id, self.slug])
class Order(models.Model):
customer = models.ForeignKey("Customer", on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
paid = models.BooleanField(default=False)
class Meta:
ordering = ("-created",)
def __str__(self):
return "Order {}".format(self.id)
def get_total_cost(self):
return sum(item.get_cost() for item in self.items.all())
class OrderItem(models.Model):
order = models.ForeignKey(Order, related_name="items", on_delete=models.CASCADE)
product = models.ForeignKey(
Product, related_name="order_items", on_delete=models.CASCADE
)
quantity = models.PositiveIntegerField(default=1)
def __str__(self):
return "{}".format(self.id)
def get_cost(self):
return self.price * self.quantity
class Customer(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
phone = models.CharField(max_length=15, null=True)
email = models.EmailField()
address_line_1 = models.CharField(max_length=250)
address_line_2 = models.CharField(max_length=60, null=True)
postal_code = models.CharField(max_length=20)
city = models.CharField(max_length=100)
state = models.CharField(max_length=100, null=True)
country = models.CharField(max_length=100, default="Mexico")
def __str__(self):
return f"{self.first_name} {self.last_name}"
Forms.
I only have the customer form, which works pretty well. I made it that way so I can show the fields with the same format as in a template that I’m using (I know almost nothing about the front end). What I want is a form for the Order model, similar to the one in the admin panel.
class CustomerForm(ModelForm):
first_name = forms.CharField(
widget=forms.TextInput(
attrs={
"placeholder": "First Name",
"class": "form-control",
"type": "text",
}
)
)
last_name = forms.CharField(
widget=forms.TextInput(
attrs={
"placeholder": "Last Name",
"class": "form-control",
"type": "text",
}
)
)
phone = forms.CharField(
widget=forms.TextInput(
attrs={
"placeholder": "Phone Number",
"class": "form-control",
"type": "text",
}
)
)
email = forms.CharField(
widget=forms.TextInput(
attrs={"placeholder": "Email", "class": "form-control", "type": "email"}
)
)
address_line_1 = forms.CharField(
widget=forms.TextInput(
attrs={
"placeholder": "Address Line 1",
"class": "form-control",
"type": "text",
}
)
)
address_line_2 = forms.CharField(
widget=forms.TextInput(
attrs={
"placeholder": "Address Line 2",
"class": "form-control",
"type": "text",
}
)
)
postal_code = forms.CharField(
widget=forms.TextInput(
attrs={
"placeholder": "Postal Code",
"class": "form-control",
"type": "number",
}
)
)
city = forms.CharField(
widget=forms.TextInput(
attrs={
"placeholder": "City",
"class": "form-control",
"type": "text",
}
)
)
state = forms.CharField(
widget=forms.TextInput(
attrs={
"placeholder": "State",
"class": "form-control",
"type": "text",
}
)
)
country = forms.CharField(
widget=forms.TextInput(
attrs={
"placeholder": "Country",
"class": "form-control",
"type": "text",
}
)
)
class Meta:
model = Customer
fields = "__all__"
Admin
(it works as I want it to work in a template).
from django.contrib import admin
from .models import Order, OrderItem, Category, Product, Customer
class OrderItemInline(admin.TabularInline):
model = OrderItem
raw_id_fields = ["product"]
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = [
"id",
"paid",
"created",
"updated",
]
list_filter = ["paid", "created", "updated"]
inlines = [OrderItemInline]
# register
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ["name", "slug"]
prepopulated_fields = {"slug": ("name",)}
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ["name", "slug", "price", "available", "created"]
list_filter = ["available", "created", "updated"]
list_editable = ["price", "available"]
prepopulated_fields = {"slug": ("name",)}
@admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin):
list_display = [
"first_name",
"last_name",
"email",
"address_line_1",
"address_line_2",
"postal_code",
"city",
]
I still have neither views nor URLs related to the Order.