Improving on 3.0.0 / adding productorder link based on slug
This commit is contained in:
parent
d3b6d28ae6
commit
8952ef0b3a
|
@ -15,6 +15,40 @@ machine. Use `kubectl get nodes` to verify minikube is up and running.
|
||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
|
||||||
#### 3.0.0
|
#### Future (unplanned)
|
||||||
|
|
||||||
|
* When/where to add timeframe constraints
|
||||||
|
* Timeframe slug-or-id
|
||||||
|
* Maybe slug and backlink to avail products
|
||||||
|
* Timeframe in product
|
||||||
|
* Should a product define list of time frames AND resources?
|
||||||
|
* Then can do autoselect on <resources x timeframes> and only show
|
||||||
|
complete ones
|
||||||
|
* resources are also timeframe bound
|
||||||
|
* name != unique (?)
|
||||||
|
* Can we filter drop down in admin?
|
||||||
|
* yes: ModelAdmin.formfield_for_manytomany(db_field, request, **kwargs)¶
|
||||||
|
* resources should have a slug
|
||||||
|
* can be used as an identifier and non unique names
|
||||||
|
|
||||||
|
|
||||||
|
#### 3.0.2 (planned)
|
||||||
|
|
||||||
|
* Add basic validation to ordering
|
||||||
|
|
||||||
|
#### 3.0.1 (planned)
|
||||||
|
|
||||||
|
* Show products [done]
|
||||||
|
* Link to ProductOrderForm [done]
|
||||||
|
* Continue to resources / add resources
|
||||||
|
* Confirm & create
|
||||||
|
|
||||||
|
#### 3.0.0 (2022-01-14)
|
||||||
|
|
||||||
* Introduce ProductOrderView
|
* Introduce ProductOrderView
|
||||||
|
|
||||||
|
|
||||||
|
## Pre-Production requirements
|
||||||
|
|
||||||
|
* Products need to ensure *all* resources are consistent for different timeframes
|
||||||
|
* Products cannot have same resource linked twice in same timeframe
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 4.0 on 2022-01-14 22:20
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('app', '0004_auto_20220102_2020'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='product',
|
||||||
|
name='slug',
|
||||||
|
field=models.SlugField(null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Generated by Django 4.0 on 2022-01-14 23:25
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('app', '0005_product_slug'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='resource',
|
||||||
|
name='slug',
|
||||||
|
field=models.SlugField(null=True, unique=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='product',
|
||||||
|
name='slug',
|
||||||
|
field=models.SlugField(null=True, unique=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='resource',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=128),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,6 +1,8 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
|
||||||
class Currency(models.Model):
|
class Currency(models.Model):
|
||||||
name = models.CharField(max_length=128, unique=True)
|
name = models.CharField(max_length=128, unique=True)
|
||||||
|
@ -43,7 +45,8 @@ class PricePerTime(models.Model):
|
||||||
return f"{self.price} {self.currency.short_name}/{self.timeframe}"
|
return f"{self.price} {self.currency.short_name}/{self.timeframe}"
|
||||||
|
|
||||||
class Resource(models.Model):
|
class Resource(models.Model):
|
||||||
name = models.CharField(max_length=128, unique=True) # CPU, RAM
|
slug = models.SlugField(null=True, unique=True) # primary identifier
|
||||||
|
name = models.CharField(max_length=128, unique=False) # CPU, RAM
|
||||||
unit = models.CharField(max_length=128) # Count, GB
|
unit = models.CharField(max_length=128) # Count, GB
|
||||||
minimum_units = models.FloatField(null=True, blank=True) # might have min
|
minimum_units = models.FloatField(null=True, blank=True) # might have min
|
||||||
maximum_units = models.FloatField(null=True, blank=True) # might have max
|
maximum_units = models.FloatField(null=True, blank=True) # might have max
|
||||||
|
@ -84,12 +87,16 @@ class Product(models.Model):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = models.CharField(max_length=128, unique=True)
|
name = models.CharField(max_length=128, unique=True)
|
||||||
|
slug = models.SlugField(null=True, unique=True)
|
||||||
|
|
||||||
# textconfig = models.ManyToManyField(ProductTextConfiguration)
|
# textconfig = models.ManyToManyField(ProductTextConfiguration)
|
||||||
# textfieldconfig = models.ManyToManyField(ProductTextFieldConfiguration)
|
# textfieldconfig = models.ManyToManyField(ProductTextFieldConfiguration)
|
||||||
|
|
||||||
resources = models.ManyToManyField(Resource, blank=True)
|
resources = models.ManyToManyField(Resource, blank=True)
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse('product-detail', kwargs={'slug' : self.slug})
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<h1>{{ object.name }}</h1>
|
||||||
|
|
||||||
|
|
||||||
|
<form method="post" >
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<input type="submit" value="Buy">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
HERE we show a link to <a href="{{ productorder }}">order</a>.
|
|
@ -0,0 +1,24 @@
|
||||||
|
<h1>Select Product</h1>
|
||||||
|
|
||||||
|
<h2>Product Order</h2>
|
||||||
|
<ul>
|
||||||
|
{% for product in object_list %}
|
||||||
|
{% if product.slug %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ product.get_absolute_url }}">{{ product.name }}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<h2>Product List</h2>
|
||||||
|
<ul>
|
||||||
|
{% for product in object_list %}
|
||||||
|
{% if product.slug %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ product.get_absolute_url }}">{{ product.name }}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
|
@ -1,4 +1,7 @@
|
||||||
<form method="post">{% csrf_token %}
|
Ordering a {{ product }} instance
|
||||||
|
|
||||||
|
<form method="post" >
|
||||||
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
<input type="submit" value="Save">
|
<input type="submit" value="Next">
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,8 +1,49 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render, get_object_or_404
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from django.views.generic.edit import CreateView
|
from django.views.generic.edit import CreateView
|
||||||
from .models import ProductOrder
|
from django.views.generic.base import TemplateView
|
||||||
|
from django.views.generic.list import ListView
|
||||||
|
from django.views.generic.detail import DetailView
|
||||||
|
|
||||||
|
|
||||||
|
from .models import *
|
||||||
|
|
||||||
class ProductOrderView(CreateView):
|
class ProductOrderView(CreateView):
|
||||||
model = ProductOrder
|
model = ProductOrder
|
||||||
fields = ['product', 'resources' ]
|
fields = ['resources']
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['product'] = get_object_or_404(Product, slug=self.kwargs['product'])
|
||||||
|
print(context)
|
||||||
|
print(self.kwargs)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class ProductDetailView(DetailView):
|
||||||
|
model = Product
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['productorder'] = reverse('product-order', kwargs={'product': self.object.slug })
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class ProductListView(ListView):
|
||||||
|
model = Product
|
||||||
|
|
||||||
|
|
||||||
|
class ProductSelectView(CreateView):
|
||||||
|
model = ProductOrder
|
||||||
|
fields = ['product' ]
|
||||||
|
|
||||||
|
|
||||||
|
class Yearly(TemplateView):
|
||||||
|
template_name = "app/config_product.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(Yearly, self).get_context_data(**kwargs)
|
||||||
|
context['current_year'] = self.current_year
|
||||||
|
context['current_month'] = self.current_month
|
||||||
|
return context
|
||||||
|
|
|
@ -19,5 +19,10 @@ from app import views as appviews
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('order', appviews.ProductOrderView.as_view())
|
path('order', appviews.ProductSelectView.as_view()),
|
||||||
|
path('order/<slug:product>/', appviews.ProductOrderView.as_view(), name='product-order'),
|
||||||
|
path('order/<slug:product>/<slug:timeframe>/', appviews.ProductOrderView.as_view(), name='product-order'),
|
||||||
|
path('product/', appviews.ProductListView.as_view()),
|
||||||
|
path('product/<slug:slug>/', appviews.ProductDetailView.as_view(), name='product-detail')
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue