I am Developing a E-commerce Application with Django
So what I was thinking is getting the category of the Product in a separate Model and list them down in another using choice field in CharField.
So Here is the code for this
This is the model for getting the Categories from the user
class ProjektCat(models.Model):
id = models.AutoField(primary_key=True)
Option_Name = models.CharField(max_length=50)
Option_Number = models.IntegerField()
Number_Visits = models.IntegerField(default=0)
def __str__(self):
return f'{self.Option_Name}'
and here is the code to list those categories as a dropdown in the CharField
class Software_And_Service(models.Model):
id = models.AutoField(primary_key=True)
Product_Name = models.CharField(max_length=100, default='')
projectKats = ProjektCat.objects.all()
choice = []
for i in projectKats:
option = (i.Option_Number, i.Option_Name)
choice.append(option)
Cateogary = models.CharField(
max_length=256, choices=choice)
Price = models.IntegerField(default=0)
Description = models.TextField(default='', max_length=5000)
pub_date = models.DateField(auto_now_add=True, blank=True, null=True)
image = models.URLField(default='')
linkToDownload = models.URLField(default='')
def __str__(self):
return f'Projekt : {self.Product_Name}'
But it's Showing me an Error that there is no such table in app_name.projektcat
Is there is any solution for this??
It's not how you do this. First correctly assign the projectKats field i.e
# You can set max_length as per your choice
projectKats = models.CharField(max_length=50)
You need to do this logic in django forms rather than django models.
So this is how you can do it.
forms.py
from django import forms
from .models import ProjektCat, Software_And_Service
def get_category_choices():
return [(obj.Option_Name,obj.Option_Name) for obj in ProjektCat.objects.values_list('Option_Name',flat=True).distinct()]
class SoftwareAndServiceForm(forms.ModelForm):
projectKats = forms.ChoiceField(choices=get_category_choices)
class Meta:
model = Software_And_Service
fields = [
'projectKats',
# whatever fields you want
]
Related
I'm developing a web app for fun and the goal is to use Django Admin and only Django Admin, without any custom templates (yet). I'm unable to figure out how I should structure my models.py and admin.py files, where what I'm trying to do is:
There are many items and many departments: Each item can only belong to one department and each department can have several items. This currently works.
Now, what I can't seem to figure out is:
There are many sites. Each site can have many items, but the PRICE of each item at each site can be different. For example:
Site #123 can have a can of coke for $1.00
Site #124 can also have a can of coke, but at a price of $0.95
Site #123 can have a bag of chips for $1.50
Site #124 can also have a bag of chips, but at a price of $1.95
etc...
How do I establish this relationship in Django models.py/admin.py? Also, how could I edit the price using the inline (screenshot below)? In other words, how could the price be shown to the right of the description?
Thanks in advance
Current Code:
admin.py:
from django.contrib import admin
from .models import Site, Department, Item
class ItemInline(admin.TabularInline):
model = Site.items.through
can_delete = False
verbose_name = 'Item'
verbose_name_plural = 'Items'
extra = 0
#admin.register(Site)
class SiteAdmin(admin.ModelAdmin):
fields = ("site", "address")
list_display = ("site", "address")
inlines = (ItemInline, )
exclude = ("items", )
#admin.register(Department)
class DepartmentAdmin(admin.ModelAdmin):
fields = ("number", "description")
list_display = ("number", "description")
#admin.register(Item)
class ItemAdmin(admin.ModelAdmin):
fields = ("upc", "description", "department")
list_display = ("upc", "description", "department")
save_as = True
def formfield_for_dbfield(self, *args, **kwargs):
formfield = super().formfield_for_dbfield(*args, **kwargs)
formfield.widget.can_delete_related = False
formfield.widget.can_change_related = False
formfield.widget.can_add_related = False
# formfield.widget.can_view_related = False
return formfield
models.py:
from django.db import models
class Department(models.Model):
number = models.IntegerField(unique=True)
description = models.CharField(max_length=30)
def __str__(self):
return str(self.number) + ": " + self.description
class Meta:
ordering = ["number", ]
class Item(models.Model):
upc = models.CharField(max_length=30, unique=True, verbose_name="UPC")
description = models.CharField(max_length=30)
department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.upc + ": " + self.description
class Meta:
ordering = ["upc", ]
class Site(models.Model):
site = models.IntegerField(unique=True)
address = models.CharField(max_length=50)
items = models.ManyToManyField(Item)
def __str__(self):
return str(self.site)
class Meta:
ordering = ["site", ]
I figured this out about 20 minutes after posting. The key was to create a new model (named ItemPrice) with site, upc, and price -- with site and upc FK'd to Site and Item. I then created a new Inline pointing to ItemPrice:
class ItemPrice(models.Model):
site = models.ForeignKey(Site, on_delete=models.CASCADE, null=True)
upc = models.ForeignKey(Item, on_delete=models.CASCADE, null=True, verbose_name="UPC")
price = models.DecimalField(max_digits=6, decimal_places=2, default=0)
class Meta:
constraints = [
models.UniqueConstraint(fields=['site', 'upc'], name='unique_site_upc')
]
and
class ItemPriceInline(admin.TabularInline):
model = ItemPrice
# can_delete = False
verbose_name = 'Item Price'
verbose_name_plural = 'Item Prices'
extra = 0
Trying to create a column in my model called, stock_count, that finds the sum of the total string objects in my ArrayField(), aka stock_list. Here is my function.
def total_stocks_calc(self):
self.stock_count = Bucket.objects.aggregate(Sum('stock_list', distinct=True))
self.save()
However it doesn't seem to be doing anything, no calculating, leaving the field blank in my model, admin page, and DRF interface...
EDIT: updated post with new implementation.
Here is my model.
class Bucket(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='buckets')
users = models.ManyToManyField(settings.AUTH_USER_MODEL)
category = models.CharField(max_length=30, choices=category_options)
name = models.CharField(max_length=35)
created = models.DateTimeField(default=timezone.now)
slug = models.SlugField(unique=True, blank=True)
stock_count = models.IntegerField(blank=True, null=True)
stock_list = ArrayField(models.CharField(max_length=6,null=True),size=30,null=True)
about = models.CharField(max_length=75)
objects = models.Manager()
bucketobjects = BucketObjects()
class Meta:
ordering = ('-created',)
def total_stocks_calc(self):
self.stock_count = Bucket.objects.annotate(stock_count=F('stock_list__len'))
self.save()
def __unicode__(self):
return self.stock_list
Would like to know the proper way to count total items in ArrayField(), thank you in advance.
The ArrayField provides the len lookup field, through that you can get the count
like
from django.db.models import F
Bucket.objects.annotate(stock_count=F('stock_list__len'))
I have two models (Product & Category) which every product has a linked category.
I have installed DjangoFilterBackend which the hope of filtering on the category field to return a list of products in that category.
However, whenever I send the query in Postman. I receive the error Select a valid choice. That choice is not one of the available choices..
I have tried filtering on another field in my product model (name for an example) and that works fine. So i'm not sure if i'm missing something for category to work.
Product/View.py:
class ProductView(ListAPIView):
serializer_class = ProductSerializer
queryset = Product.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ('category', 'name')
Products/Models.py:
class Product(models.Model):
name = models.CharField(max_length=250, unique=True, blank=False)
photo = models.ImageField(upload_to=product_photo_path)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
quantity = models.IntegerField()
description = models.TextField(blank=False)
price = models.DecimalField(max_digits=6, decimal_places=2)
in_stock = models.BooleanField(default=False)
trending = models.BooleanField(default=False)
def __str__(self):
return self.name
Products/serializers.py
class ProductSerializer(serializers.ModelSerializer):
category = serializers.CharField(source='category.name', read_only=True)
class Meta:
model = Product
fields = ('category', 'name', 'photo', 'quantity', 'description', 'price', 'in_stock', 'trending')
The query I am using is a GET request to:
http://127.0.0.1:8000/api/products?category=xxxx - I am sending no payload. The response I am receiving is a `400 Bad Request` and the exact error is:
{
"category": [
"Select a valid choice. That choice is not one of the available choices."
]
}
Ah-ha!
I changed the model to:
class Product(models.Model):
name = models.CharField(max_length=250, unique=True, blank=False)
photo = models.ImageField(upload_to=product_photo_path)
**category = models.ForeignKey(Category, to_field='name', on_delete=models.CASCADE)**
quantity = models.IntegerField()
description = models.TextField(blank=False)
price = models.DecimalField(max_digits=6, decimal_places=2)
in_stock = models.BooleanField(default=False)
trending = models.BooleanField(default=False)
And now it works!
Well, I am not sure, but try to filter on field category_id, this field is created automatically for FK fields
Just in case somebody will ever need the answer, to be able to use the name of a foreign field to filter instead of the primary key use a double underscore i.e category__name in this case. Note that name in this case is the field of the foreign model that you want to filter with and you can replace it with your field accordingly.
In my database, I store the file name of a particular image for an item. Let's say this is the model in models.py
from django.db import models
class Product(models.Model):
sku = models.CharField(validators=[isalphanumeric], max_length=20, null=False, blank=False)
image = models.CharField(max_length=20, blank=False, null=False)
and then I have a serializer defined like so in serializers.py
from rest_framework import serializers
from app.models import Product
class ProductSerializer(serializer.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
what I want is to be able to add a string to the image of a Product that makes it into a string representing the relative link, something like:
storage_location = '/assets/img'
img_url = f'{storage_location}/{image}'
The reason why I want to do this is because I want to be flexible with the urls rather than having the file name be a "file location" and then having to update the database each time I change how I arrange my images (I'm still not sure how to store them).
How can I do that?
First of all you can use model's ImageField for this:
class Product(models.Model):
sku = models.CharField(validators=[isalphanumeric], max_length=20, null=False, blank=False)
image = models.ImageField(max_length=20, blank=False)
This will automatically add MEDIA_URL setting to the value when you fetch value.
In case you want to use CharField you can do what you need on serializer level using SerializerMethodField:
class ProductSerializer(serializer.ModelSerializer):
image = serializers.SerializerMethodField()
def get_image(self, obj):
storage_location = '/assets/img'
img_url = f'{storage_location}/{obj.image}'
return img_url
class Meta:
model = Product
fields = '__all__'
Try following in your serialiser.py
class ProductSerializer(serializer.ModelSerializer):
img_url = serializers.SerializerMethodField()
class Meta:
model = Product
fields = '__all__'
#fields = ('sku', 'img_url') # This is what i will prefer
def get_img_url(self, obj):
storage_location = '/assets/img'
img_url = f'{storage_location}/{obj.image}'
return img_url
Good Luck!
Let's say i have 10 tables in 1 Db and the table names differ and data is different, but the structure of the tables are the same. And then i have 1 more table that collects all the table names and the creation date of that table.
Example:
PrimaryTable
table_name_1
table_name_2
....
table_name_10
and the structure of all tables example:
class PrimaryTable(models.Model):
name = models.CharField(db_column='Name', unique=True, max_length=100)
date = models.CharField(db_column='Date', max_length=100)
class Meta:
managed = True
db_table = 'Primary Table'
def __str__(self):
return self.name
class table_name_1(models.Model):
title = models.TextField(db_column='Title', blank=True, null=True)
url = models.CharField(db_column='Url', unique=True, max_length=250, blank=True,
null=True)
description = models.TextField(db_column='Description', blank=True, null=True)
created_at = models.DateTimeField(db_column='Created_at')
class table_name_2(models.Model):
title = models.TextField(db_column='Title', blank=True, null=True)
url = models.CharField(db_column='Url', unique=True, max_length=250, blank=True,
null=True)
description = models.TextField(db_column='Description', blank=True, null=True)
created_at = models.DateTimeField(db_column='Created_at')
and so on...
And i only want to make 1 class that includes all those tables that have same structure and call it when i choose the table from the PrimaryTable.
I don't want to use "python manage.py inspectdb > models.py" every time i create a table. I want to have access to the new created table instantly when i create it.
You can define your model fields as dict:
fields = dict(
title = models.TextField(db_column='Title', blank=True, null=True),
url = models.CharField(db_column='Url', unique=True, max_length=250, blank=True, null=True),
description = models.TextField(db_column='Description', blank=True, null=True),
created_at = models.DateTimeField(db_column='Created_at'),
)
Then you can dynamicly create and run migration for it:
from django.db import connection, migrations, models
from django.db.migrations.executor import MigrationExecutor
def create_table(table_name, model_fields, app_label):
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name=table_name,
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
] + [(k, field) for k,field in model_fields.items()],
options={
'db_table': table_name,
},
),
]
executor = MigrationExecutor(connection)
migration = Migration(table_name, app_label)
with connection.schema_editor(atomic=True) as schema_editor:
migration.apply(executor._create_project_state(), schema_editor)
Then you can use dynamic model creation to access data in tables:
from django.db import models
def create_model(name, fields=None, app_label=None, module='', options=None, admin_opts=None):
"""
Create specified model
"""
class Meta:
db_table = name
if app_label:
# app_label must be set using the Meta inner class
setattr(Meta, 'app_label', app_label)
# Update Meta with any options that were provided
if options is not None:
for key, value in options.iteritems():
setattr(Meta, key, value)
# Set up a dictionary to simulate declarations within a class
attrs = {'__module__': module, 'Meta': Meta}
# Add in any fields that were provided
if fields:
attrs.update(fields)
# Create the class, which automatically triggers ModelBase processing
model = type(name, (models.Model,), attrs)
return model
I hope you will get general idea.
I took code from project that uses Django 2 (similar code is used to create tables per uploaded CSV file, columns and name of each uploaded CSV is stored in table which is similar to your PrimaryTable).
You can simplify things by keeping all of the data with the same structure in one table. You can use admin filters and custom manager methods to focus on one type of information at a time, which will provide the same functionality as separate tables.
class Information(models.Model):
name = models.CharField(db_column='Name', unique=True, max_length=100)
date = models.CharField(db_column='Date', max_length=100)
information_type = models.ForeignKey(InformationType, related_name='information_records')
def __str__(self):
return self.name
class InformationType(models.Model):
title = models.TextField(db_column='Title', blank=True, null=True)
url = models.CharField(db_column='Url', unique=True, max_length=250, blank=True,
null=True)
description = models.TextField(db_column='Description', blank=True, null=True)
created_at = models.DateTimeField(db_column='Created_at')
def __str__(self):
return self.title
k i figure out but i dont know how to write it.
I m going to create 1 class in models:
Example models.py:
class Alltables(models.Model):
title = models.TextField(db_column='Title', blank=True, null=True) # Field name made lowercase.
url = models.CharField(db_column='Url', unique=True, max_length=250, blank=True,
null=True) # Field name made lowercase.
description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase.
created_at = models.DateTimeField(db_column='Created_at') # Field name made lowercase.
class Meta:
managed = False
db_table = 'Table_name' # make it args
def __str__(self):
return self.url
and in the class Meta i want to implement Args at db_table.
That means when i click on a table in the html i want that table name to be inserted in the db_table and give me the data in it.
Because the class PrimaryTable will give me all the table names in that DB.
I hope i ve explained k. But i still need the answer of how to implement args in the Meta class. and Use it in the views.py and html template.
tables/views.py
def table_base(request):
table_name = Crawledtables._meta.db_table
list_tables = Crawledtables.objects.order_by('id')
table_list = {'list_tables': list_tables}
return render(request, 'tables/table_base.html', {'table_name': table_name,
'list_tables': list_tables})
class AboutDetail(DetailView):
model = Crawledtables
pk_url_kwarg = 'table_id'
template_name = 'tables/table_list.html'
def get_object(self):
if 'table_id' not in self.kwargs:
return Crawledtables.objects.get(id=1)
else:
return Crawledtables.objects.get(id=self.kwargs['table_id'])
part of tables/views.py
class Details(ListView):
model = table_name_1
template_name = 'tables/table_list.html'
context_object_name = 'details'
paginate_by = 15
queryset = table_name_1.objects.all()