diff --git a/uncloud_v3/README.md b/uncloud_v3/README.md index d6ecad0..b7a6cbd 100644 --- a/uncloud_v3/README.md +++ b/uncloud_v3/README.md @@ -15,6 +15,40 @@ machine. Use `kubectl get nodes` to verify minikube is up and running. ## 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 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 + + +## Pre-Production requirements + +* Products need to ensure *all* resources are consistent for different timeframes +* Products cannot have same resource linked twice in same timeframe diff --git a/uncloud_v3/app/migrations/0005_product_slug.py b/uncloud_v3/app/migrations/0005_product_slug.py new file mode 100644 index 0000000..44f56b0 --- /dev/null +++ b/uncloud_v3/app/migrations/0005_product_slug.py @@ -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), + ), + ] diff --git a/uncloud_v3/app/migrations/0006_resource_slug_alter_product_slug_alter_resource_name.py b/uncloud_v3/app/migrations/0006_resource_slug_alter_product_slug_alter_resource_name.py new file mode 100644 index 0000000..0473546 --- /dev/null +++ b/uncloud_v3/app/migrations/0006_resource_slug_alter_product_slug_alter_resource_name.py @@ -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), + ), + ] diff --git a/uncloud_v3/app/models.py b/uncloud_v3/app/models.py index 95204a9..a922215 100644 --- a/uncloud_v3/app/models.py +++ b/uncloud_v3/app/models.py @@ -1,6 +1,8 @@ from django.db import models from django.contrib.auth import get_user_model from django.utils import timezone +from django.urls import reverse + class Currency(models.Model): 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}" 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 minimum_units = models.FloatField(null=True, blank=True) # might have min 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) + slug = models.SlugField(null=True, unique=True) # textconfig = models.ManyToManyField(ProductTextConfiguration) # textfieldconfig = models.ManyToManyField(ProductTextFieldConfiguration) resources = models.ManyToManyField(Resource, blank=True) + def get_absolute_url(self): + return reverse('product-detail', kwargs={'slug' : self.slug}) + def __str__(self): return self.name diff --git a/uncloud_v3/app/templates/app/product_detail.html b/uncloud_v3/app/templates/app/product_detail.html new file mode 100644 index 0000000..4e404e1 --- /dev/null +++ b/uncloud_v3/app/templates/app/product_detail.html @@ -0,0 +1,10 @@ +

{{ object.name }}

+ + +
+ {% csrf_token %} + {{ form.as_p }} + +
+ +HERE we show a link to order. diff --git a/uncloud_v3/app/templates/app/product_list.html b/uncloud_v3/app/templates/app/product_list.html new file mode 100644 index 0000000..7a52e7c --- /dev/null +++ b/uncloud_v3/app/templates/app/product_list.html @@ -0,0 +1,24 @@ +

Select Product

+ +

Product Order

+ +

Product List

+ diff --git a/uncloud_v3/app/templates/app/productorder_form.html b/uncloud_v3/app/templates/app/productorder_form.html index 256405a..dd8326c 100644 --- a/uncloud_v3/app/templates/app/productorder_form.html +++ b/uncloud_v3/app/templates/app/productorder_form.html @@ -1,4 +1,7 @@ -
{% csrf_token %} +Ordering a {{ product }} instance + + + {% csrf_token %} {{ form.as_p }} - +
diff --git a/uncloud_v3/app/views.py b/uncloud_v3/app/views.py index 2012f8c..0f808da 100644 --- a/uncloud_v3/app/views.py +++ b/uncloud_v3/app/views.py @@ -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 .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): 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 diff --git a/uncloud_v3/uncloud/urls.py b/uncloud_v3/uncloud/urls.py index 1a0df4c..b919dc9 100644 --- a/uncloud_v3/uncloud/urls.py +++ b/uncloud_v3/uncloud/urls.py @@ -19,5 +19,10 @@ from app import views as appviews urlpatterns = [ path('admin/', admin.site.urls), - path('order', appviews.ProductOrderView.as_view()) + path('order', appviews.ProductSelectView.as_view()), + path('order//', appviews.ProductOrderView.as_view(), name='product-order'), + path('order///', appviews.ProductOrderView.as_view(), name='product-order'), + path('product/', appviews.ProductListView.as_view()), + path('product//', appviews.ProductDetailView.as_view(), name='product-detail') + ]