As part of an Address Book application, I have the following in my models.py
from django.db import models
class Contact(models.Model):
contact_id= models.AutoField(auto_created=True, primary_key=True, default=1, verbose_name='ID')
name = models.CharField(max_length=100, unique=True)
contact_no = models.ManyToManyField(ContactNumberTypeField,
through='ContactContactNumber', through_fields=('contact_name','contact_type'))
def __str__(self):
return self.name
class ContactNumberTypeField(models.Model):
contact_number_type=models.AutoField(auto_created=True, primary_key=True, default=1, verbose_name='ID')
name = models.CharField(max_length=20)
contact_no = models.ManyToManyField(Contact,
through='ContactContactNumber', through_fields=('contact_name','contact_type'))
def __str__(self):
return self.name
class ContactContactNumber(models.Model):
contact_name=models.ForeignKey(Contact)
contact_type=models.ForeignKey(ContactNumberTypeField)
contact_number = models.CharField(max_length=50)
def __str__(self):
return contact_number
My question is that why is it when I run makemigrations, it throws a ContactNumberTypeField is not defined error?
Update
Correct code is as follows
from django.db import models
class Contact(models.Model):
contact_id= models.ManyToManyField('ContactNumberTypeField',
through='ContactContactNumber', through_fields=('contact_name','contact_type'))
name = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.name
class ContactNumberTypeField(models.Model):
contact_number_type=models.ManyToManyField('Contact',
through='ContactContactNumber', through_fields=('contact_type','contact_name'))
name = models.CharField(max_length=20)
contact_no = models.IntegerField(max_length=20)
def __str__(self):
return self.name
class ContactContactNumber(models.Model):
contact_name=models.ForeignKey(Contact)
contact_type=models.ForeignKey(ContactNumberTypeField)
contact_number = models.CharField(max_length=50)
def __str__(self):
return contact_number
ContactNumberTypeField is not defined at the time of defining of Contact class. Change contact_no field to this:
class Contact(models.Model):
...
contact_no = models.ManyToManyField('ContactNumberTypeField',
through='ContactContactNumber',
through_fields=('contact_name','contact_type'))
Note the quotes around 'ContactNumberTypeField'.
The other error here is the wrong order of field names in through_fields attribute of the ContactNumberTypeField.contact_no field. It should be:
class ContactNumberTypeField(models.Model):
...
contact_no = models.ManyToManyField(Contact,
through='ContactContactNumber',
through_fields=('contact_type','contact_name'))
Read the documentation about field1 and field2.
Related
I want to create muti category in my ecommerce website where sub category will be dependent on main category.
Please help me with this
class MainCategory(models.Model):
# name = models.CharField(max_length=50)
# date_created = models.DateTimeField(auto_now_add=True)
# def __str__(self):
# return self.name
# class SubCategory(models.Model):
# perentcategory = models.OneToOneField(MainCategory, on_delete=models.CASCADE, primary_key=True)
# name = models.CharField(max_length=50)
# date_created = models.DateTimeField(auto_now_add=True)
# def __str__(self):
# return self.name
# class Items(models.Model):
# main = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
# name = models.CharField(max_length=255)
Posting this question 4th time
Change models.OneToOneField to models.ForeignKey so you can have multiple subcategories assigned to a main category:
class MainCategory(models.Model):
name = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class SubCategory(models.Model):
main_category = models.ForeignKey(MainCategory, on_delete=models.CASCADE, primary_key=True)
name = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Items(models.Model):
main = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
You can use single model to accommodate both Category and Sub-categories. Something like this.
class Category(models.Model):
name = models.CharField(blank=False, max_length=200)
slug = models.SlugField(null=False)
parent = models.ForeignKey('self',blank=True, null=True ,related_name='children', on_delete=models.SET_NULL)
Then add following function to the above model
def get_categories(self):
if self.parent is None:
return self.name
else:
return self.parent.get_categories() + ' -> ' + self.name
def __str__(self):
return self.get_categories()
This will return structure similar to this image
models.py
from django.db import models
from django.contrib.auth.models import User
class ActiveManager(models.Model):
def active(self):
return self.filter(active=True)
class Product(models.Model):
name = models.CharField(max_length=32)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits = 5, decimal_places = 2)
slug = models.SlugField(max_length=48)
active = models.BooleanField(default=True)
in_stock = models.BooleanField(default=True)
date_updated = models.DateTimeField(auto_now=True)
objects = ActiveManager()
tags = models.ManyToManyField(ProductTag, blank=True)
def __str__(self):
return self.name
class ProductImage(models.Model):
product = models.ForeignKey(
Product, on_delete=models.CASCADE)
image = models.ImageField(upload_to="product-images")
thumbnail = models.ImageField(
upload_to="product-thumbnails", null=True)
class ProductTag(models.Model):
name = models.CharField(max_length=40)
slug = models.SlugField(max_length=48)
description = models.TextField(blank=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.name
def natural_key(self):
return(self.slug,)
The name error says ProductTag is not defined, whereas ProductTag itself a Class. I don't understand where I missed... appreciate for the help
The solution must be like this, because I think reordering could solve your problem. However please put 2 lines of space between your classes and 1 line of space between your functions. It can make your code more readable and also more suitale for the Python guidelines.
from django.db import models
from django.contrib.auth.models import User
class ActiveManager(models.Model):
def active(self):
return self.filter(active=True)
class ProductTag(models.Model):
name = models.CharField(max_length=40)
slug = models.SlugField(max_length=48)
description = models.TextField(blank=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.name
def natural_key(self):
return(self.slug,)
class Product(models.Model):
name = models.CharField(max_length=32)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits = 5, decimal_places = 2)
slug = models.SlugField(max_length=48)
active = models.BooleanField(default=True)
in_stock = models.BooleanField(default=True)
date_updated = models.DateTimeField(auto_now=True)
objects = ActiveManager()
tags = models.ManyToManyField(ProductTag, blank=True)
def __str__(self):
return self.name
class ProductImage(models.Model):
product = models.ForeignKey(
Product, on_delete=models.CASCADE)
image = models.ImageField(upload_to="product-images")
thumbnail = models.ImageField(
upload_to="product-thumbnails", null=True)
Looking at your code, you’re trying to use ProductTag before you’ve defined it.
You could either reorder things, or I believe you can reference by string and django will link them up later.
Eg tags = models.ManyToManyField('ProductTag', blank=True)
I have 3 models : User, Attribute, Site.
class User(models.Model):
userid = models.CharField(max_length=200, primary_key=True)
name= models.BooleanField(null=True)
def get_absolute_url(self):
return reverse('myapp:index')
def __str__(self):
return self.userid
class Site(models.Model):
pK_site = models.CharField(max_length=200, primary_key=True)
name = models.CharField(max_length=200,null=True)
def __str__(self):
return self.pK_site
class Attribute(models.Model):
userid = models.ForeignKey(User, on_delete=models.CASCADE)
role= models.CharField(max_length=200)
site = models.ForeignKey(Site, on_delete=models.CASCADE)
def __str__(self):
return str(self.site)
def get_absolute_url(self):
return reverse('myapp:edit', kwargs={'pk' : self.userid.pk})
My problem is when i get for example the list of all the attribues (Class : Attribute) in a view, i can't get the Site of this attribute or its user in the template.
Someone has a suggestion to do that ? thank you
django inheritence admin site -- why do charfields follow down the tree automatically whereas fields that are defined classes do not? I've been searching for the answer for several hours and this is my first question so please be gentle.
here is my models.py
from django.db import models
import datetime
from django.db.models import EmailField
class XObj(models.Model):
auto_increment_id = models.AutoField(primary_key=True)
creation_date = models.DateTimeField(default=datetime.datetime.now)
def __str__(self):
return str(self.creation_date.datetime)
def date_created(self):
return self.creation_date
def date_last_change(self):
return str(self.auto_increment_id)
class Address(XObj):
# todo: differentiate between US and non US addresses and validate
house = models.CharField(max_length=20, default="")
street = models.CharField(max_length=200, default="")
street2 = models.CharField(max_length=200, default="")
city = models.CharField(max_length=200, default="")
state = models.CharField(max_length=200, default="")
zipcode = models.CharField(max_length=200, default="")
country = models.CharField(max_length=200, default="")
def __str__(self):
return str(self.house, self.street, self.street2, self.city, self.state, self.zipcode, self.country)
class Entity(XObj):
full_name = models.CharField(max_length=200, default="")
# todo: validate email
email = EmailField()
# def _init_(self):
# self.full_name = models.CharField(max_length=200, default="")
#
def __str__(self):
return "Entity"
class Person(Entity):
first_name = models.CharField(max_length=200, default="")
last_name = models.CharField(max_length=200, default="")
address = Address
# def _init_(self):
# self.first_name = models.CharField(max_length=200, default="")
def __str__(self):
return self.full_name
class Vendor(XObj):
name = models.CharField(max_length=200, default="")
address = Address
website = models.URLField
point_of_contact = Person
def __str__(self):
return self.name
class Hotel(Vendor):
def __str__(self):
return self.name
class Restaurant(Vendor):
def __str__(self):
return self.name
class Lounge(Vendor):
def __str__(self):
return self.name
and here is my admin.py:
from django.contrib import admin
from .models import Person, Address, Entity, Vendor, Hotel, Restaurant, Lounge
class AddressAdmin(admin.ModelAdmin):
list_display = [field.name for field in Address._meta.fields if field.name !="id"]
# TODO: add implementation for non charfields
admin.site.register(Person)
admin.site.register(Address, AddressAdmin)
admin.site.register(Entity)
admin.site.register(Vendor)
admin.site.register(Hotel)
admin.site.register(Restaurant)
admin.site.register(Lounge)
Here is my add for Person:
Person Admin Site Output
Here is my add for Address:
Address Admin Site Output
Why are the address fields not in the Person add admin page?
Please be my Ace of Spades :)
Have a look at ForeignKey
Your model should be
class Person(Entity):
first_name = models.CharField(max_length=200, default="")
last_name = models.CharField(max_length=200, default="")
address = models.ForeignKey(
'Address',
on_delete=models.CASCADE,
)
Remember do the migration after fix it. Also django has build-in auto_increment_id for every model, you don't have to rewrite it.
I am new to Django (and databases for that matter) and trying to create a simple inventory application to help learn. I've been through the tutorials and am going through some books, but I am stuck at what i think is simple, just not sure where to look or how to ask.
With an inventory application, you have your equipment which then has a manufacturer, which the equipment has a model number that only that manufacturer has. Lets say Dell Optiplex 3040. I am also using the admin console right now as well. So i would like to be able to relate equipment to a manufacturer and then also relate the equipment to the model number. It almost seems as I am needing to use the many to many field and the through field to accomplish what I am trying to do but I dont think that is the right way to do it (shown in the link below). https://docs.djangoproject.com/en/1.9/topics/db/models/#many-to-many-relationships
Below is the code I have so far. Thank you.
from django.db import models
# Create your models here.
class Department(models.Model):
department = models.CharField(max_length=50)
def __str__(self):
return self.department
class Manufacturer(models.Model):
manufacturer = models.CharField(max_length=50)
def __str__(self):
return self.manufacturer
class EquipmentModel(models.Model):
equipmentModel = models.CharField(max_length=50)
def __str__(self):
return self.equipmentModel
class Employees(models.Model):
employee_name_first = models.CharField(max_length=25)
employee_name_last = models.CharField(max_length=25)
employee_username = models.CharField(max_length=20)
phone = models.IntegerField()
assigned_equipment = models.ForeignKey('Device', default='undefined')
department = models.ForeignKey('Department', on_delete=models.CASCADE, default='undefined')
job_title = models.ManyToManyField('Job_Positions', default='undefined')
def __str__(self):
return self.employee_username
class Device(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4',unpack_ipv4=False,null=True, blank=True)#might be good to seperate IP in its own class because a device can have multiple IP's
department = models.ForeignKey('Department', on_delete=models.CASCADE)
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
serial_number = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now=False, auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
comments = models.TextField(blank=True)
def __str__(self):
return self.serial_number
class Job_Positions(models.Model):
position_title = models.CharField(max_length=50)
position_description = models.TextField(blank=True)
def __str__(self):
return position_title
***Edit to add the updated code and the admin.py code in response question I had to answer.
#admin.py
from django.contrib import admin
# Register your models here.
from .models import Device,Department,Manufacturer,Employees, Job_Positions, EquipmentModel
class DeviceModelAdmin(admin.ModelAdmin):
list_display = ["ip", "department","model","serial_number","date_updated"]
list_filter = ["department","model","ip"]
search_fields = ["ip"]
class Meta:
model = Device
class EmployeesModelAdmin(admin.ModelAdmin):
list_display = ["employee_name_first", "employee_name_last", "employee_username", "phone"]
list_filter = ["department"]
class Meta:
model = Employees
admin.site.register(Device, DeviceModelAdmin)
admin.site.register(Department)
admin.site.register(Manufacturer)
admin.site.register(EquipmentModel)
admin.site.register(Employees, EmployeesModelAdmin)
admin.site.register(Job_Positions)
updated models.py
from django.db import models
# Create your models here.
class Department(models.Model):
department = models.CharField(max_length=50)
def __str__(self):
return self.department
class Manufacturer(models.Model):
manufacturer = models.CharField(max_length=50)
def __str__(self):
return self.manufacturer
class EquipmentModel(models.Model):
model_number = models.CharField(max_length=50)
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
def __str__(self):
return self.model_number
class Employees(models.Model):
employee_name_first = models.CharField(max_length=25)
employee_name_last = models.CharField(max_length=25)
employee_username = models.CharField(max_length=20)
phone = models.IntegerField()
assigned_equipment = models.ForeignKey('Device', default='undefined')
department = models.ForeignKey('Department', on_delete=models.CASCADE, default='undefined')
job_title = models.ManyToManyField('Job_Positions', default='undefined')
def __str__(self):
return self.employee_username
class Device(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4',unpack_ipv4=False,null=True, blank=True)#might be good to seperate IP in its own class because a device can have multiple IP's
department = models.ForeignKey('Department', on_delete=models.CASCADE)
model = models.ForeignKey('EquipmentModel', on_delete=models.CASCADE,null=True)
serial_number = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now=False, auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
comments = models.TextField(blank=True)
def __str__(self):
return self.serial_number
class Job_Positions(models.Model):
position_title = models.CharField(max_length=50)
position_description = models.TextField(blank=True)
def __str__(self):
return position_title
A many-to-many relationship is not what you want here, because any piece of equipment (I assume) can only have one manufacturer.
You do need an intermediate model which stores the model information, and you already have one in your EquipmentModel. I would suggest modifying it as follows:
class EquipmentModel(models.Model):
# This stores information about a particular model of device
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
model_number = models.CharField(max_length=50)
And then instead of having a foreign key to the manufacturer in Device, replace it with a foreign key to the equipment model:
class Device(models.Model):
# ...
model = models.ForeignKey('EquipmentModel', on_delete=models.CASCADE)