Django Model Design foreign key relationships - django

I'm creating a model for ordering multiple items which I'd like to attach to a Catalog. I can't wrap my head around the correct way to do this. It makes sense to me to have the items foreign key to the Catalog and then the Order with a manytomany relationship with the Catalog. This returns the Catalog object itself in the order, not the Catalog items.
Here is my model:
class Article(models.Model):
catalog = models.ForeignKey(Catalog, related_name='article_products', blank=True, null=True)
title = models.CharField(max_length=200)
abstract = models.TextField(max_length=1000, blank=True)
full_text = models.TextField(blank=True)
def __unicode__(self):
return unicode(self.title)
class Catalog(models.Model):
pass
def __unicode__(self):
return unicode(self.id)
class Order(models.Model):
user = models.ForeignKey(User, related_name='who_ordered')
select = models.ManyToManyField(Catalog, related_name='annuals_ordered', blank=True, null=True)
def __unicode__(self):
return unicode(self.user)
I've attached an image from the admin: A few more items are attached in this image but it shows the issue. Instead of creating a new Catalog in Order, I'd like to be able to select from the items in Catalog to create a new Order.

Related

Django tables connection

I have 3 django tables connected like this:
Is there anyway to make a query for table Table that will get id_equip from table equip?
models.py
class Vendor(models.Model):
vendor_name = models.CharField(max_length=50)
def __str__(self):
return self.vendor_name
class Equipment(models.Model):
equipment_name = models.CharField(max_length=50)
id_vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
def __str__(self):
return self.equipment_name
class Table(models.Model):
table_name = models.CharField(max_length=100)
id_vend = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
id_equip = models.ManyToManyField(Equipment)
This part of the django docs is relevant and helpful, I definitely recommend your review at least that section and ideally the whole page.
Your models are already denormalized as evidenced by Table.id_equip which relates to Equipment so you could do:
table = Table.objects.get(SOME_FILTER)
equipment_ids = list(table.id_equip.all().values_list('id', flat=True))
If you wanted to go through the vendor I'd suggest:
table = Table.objects.get(SOME_FILTER)
equipment_ids = list(Equipment.objects.filter(vendor_set__table_set=table).values_list('id', flat=True))
I would recommend that you don't name your relationship fields with id_. With an ORM, these fields should represent the instances of the Model they are mapping to. For example:
class Table(models.Model):
name = models.CharField(max_length=100)
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
equipment = models.ManyToManyField(Equipment)
If you're trying to create the model on top of an existing table, you can make use of the db_column parameter when defining the field.
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None, db_column="id_vend")

Django - Show only a specific dynamic fields per models in django-eav2

I'm trying to figure it out on how I can show only a specific set of dynamic fields in eav to a unique registered model in my apps.models. But I don't know how to this, I've also read the documents but I can't seem to find anything about it, or maybe I've come across it and didn't understand.
Now, what is happening is that, when I add an attribute in the django admin. It also adds the dynamic field in all the models registered in the eav.
What I want to do is that;
model 1 - dynamic_field1, dynamic_field2, dynamic_field3
model 2 - dynamic_field4, dynamic_field5, dynamic_field6
Btw, I'm currently using the django-eav2 the documentation is in the link. I've found my solution for my initial use case here link
Below codes are basically on how to register my models to the eav. Here is my sample models
class ClientName(models.Model):
name = models.CharField(max_length=250, null=True, blank=True)
description = models.TextField(null=True, blank=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return str(self.name)
class CallDetails(models.Model):
client_name = models.ForeignKey(ClientName, on_delete=models.PROTECT, null=True, blank=True, db_index=True)
letter_info = models.TextField(null=True, blank=True)
def __str__(self):
return str(self.client_name)
class Meta:
verbose_name = 'Call Detail'
ordering = ['client_name']
eav.register(ClientName)
eav.register(CallDetails)
below is my admin.py
class CallDetailsAdminForm(BaseDynamicEntityForm):
model = CallDetails
class CallDetailsAdmin(BaseEntityAdmin):
form = CallDetailsAdminForm
admin.site.register(CallDetails, CallDetailsAdmin)

Django M2M relationships: Use just one intermediary table or one per entity pair?

When creating many to many relationships we use an intermediary table. Lets say I use the following entities video, category, tag, and VideoCategory, VideoTag to create the relations.
I'm assuming that many tags/categories can have many videos and vice-versa.
And I do it with through keyword 'cause I want to be able to use extra fields in the future if I want.
class Category(models.Model):
category = models.CharField(max_length=50)
def __str__(self):
return self.category
class Tag(models.Model):
tag = models.CharField(max_length=50)
def __str__(self):
return self.tag
class Video(models.Model):
title = models.CharField(max_length=255)
categories = models.ManyToManyField(Category, through='VideoCategory')
tags = models.ManyToManyField(Tag, through='VideoTag')
def __str__(self):
return self.title
class VideoCategory(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
video = models.ForeignKey(Video, on_delete=models.CASCADE)
class VideoTag(models.Model):
tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
video = models.ForeignKey(Video, on_delete=models.CASCADE)
But I was wondering if would be possible to create a taxonomy entity and handle the relationships with categories and tags from just one place.
class Category(models.Model):
category = models.CharField(max_length=50)
def __str__(self):
return self.category
class Tag(models.Model):
tag = models.CharField(max_length=50)
def __str__(self):
return self.tag
class Video(models.Model):
title = models.CharField(max_length=255)
categories = models.ManyToManyField(Category, through='Taxonomy')
tags = models.ManyToManyField(Tag, through='Taxonomy')
def __str__(self):
return self.title
class Taxonomy(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True)
tag = models.ForeignKey(Tag, on_delete=models.CASCADE, null=True)
video = models.ForeignKey(Video, on_delete=models.CASCADE)
Now the taxonomy entity would hold the category and tag related to videos and vice-versa.
I've included 'null=True' to be able to create relations with categories without tags and with tags but without categories.
If I don't use it. I receive an error:
# sqlite3.IntegrityError: NOT NULL constraint failed: MyApp_taxonomy.category_id
This also means that using that single taxonomy entity for the two relationships could have many NULL Fields if one of these category or tag fields are empty on every concrete relation instance (row).
Question:
What would be better ? To keep the intermediary tables separate (VideoCategory & VideoTag) Or to join these intermediary tables into just one ? (Taxonomy)
Due to my lack of experience with databases I couldn't say if I'm missing something important. If doing it with just one intermediary table would give problems in near future or something like that... Of if it is just fine.
You have to use through_fields argument (doc):
class Video(models.Model):
title = models.CharField(max_length=255)
categories = models.ManyToManyField(Category, through='Taxonomy', through_fields=('video', 'category'))
tags = models.ManyToManyField(Tag, through='Taxonomy', through_fields=('video', 'tag'))

Django Nested Form - Always Showing Object instead of model details

I'm working on a Django project generated via Mezzanine. I've been able to create my models, however I want to have a form where an admin can select from a list to assign a value in a many to many or a one to many relationship. For example, I have a model for Schemas:
class Schema(AutoCreatedUpdatedMixin, SoftDeleteMixin):
"""List of all Schemas in a given database"""
name = models.CharField(max_length=128, null=False)
status = models.BooleanField(max_length=128, null=False, default=True, verbose_name="Is Active")
description = models.CharField(max_length=65535, null=True, blank=True, default=None)
database = models.ForeignKey(Database, on_delete=models.CASCADE)
pull_requests = models.ManyToManyField(Link)
questions = models.ManyToManyField(Question, blank=True)
comments = models.ManyToManyField(Comment, blank=True)
technical_owners = models.ManyToManyField(Employee, related_name='technical_owners_schemas', blank=True)
business_owners = models.ManyToManyField(Employee, related_name='business_owners_schemas', blank=True)
watchers = models.ManyToManyField(Employee, related_name='watchers_schemas', blank=True)
def __unicode__(self):
return "{}".format(self.name)
And I have a model for Employees
class Employee(AutoCreatedUpdatedMixin, SoftDeleteMixin):
"""List of people with any involvement in tables or fields: business or technical owners, developers, etc"""
name = models.CharField(max_length=256, blank=False, null=False, default=None, unique=True)
email = models.EmailField(blank=True, null=True, unique=True)
def __unicode__(self):
return "{}".format(self.employee)
An employee can own multiple schemas and a schema can be owned by multiple employees. My database has an active employee in it, however when I try to create a Schema the employee shows up as Employee Object. Rather I would want the form to show the Employee.name. How can I do this? My admin file contains the following:
class SchemasAdmin(admin.ModelAdmin):
list_display = ['name', 'status', 'database', 'description']
ordering = ['status', 'database', 'name']
actions = []
exclude = ('created_at', 'updated_at', 'deleted_at')
First of all are you using python 2 or 3? For 3, the __str__ method should be used instead of __unicode__. I am writing this because it seems that there's a problem with the __unicode__ method of Employee, which although is defined as:
def __unicode__(self):
return "{}".format(self.employee)
th Employee class does not have an employee attribute (unless there's such an attribute in the mixins that class inherits from (AutoCreatedUpdatedMixin, SoftDeleteMixin) but I don't think that is the case.
In any case, the problem is that you haven't defined a propery __str__ (if using python 3) or __unicode__ (for python 2) method on the Employee class - just define it like:
return self.name
and you should see the employee's name in the django admin select fields.

Django spanning relationships

I've read the documentation but am still coming up with errors. I have Users placing Orders for Catalog objects. I'd like to create a query which returns all Users that have an Order containing a specific Catalog item.
Here are my models:
class Catalog(models.Model):
name = models.CharField(max_length=100)
price = models.IntegerField()
def __unicode__(self):
return self.name
class Annual(models.Model):
catalog = models.OneToOneField(Catalog, blank=True, null=True, related_name='annual_products')
year_id = models.IntegerField(max_length=4)
start_date = models.CharField(max_length=10)
end_date = models.CharField(max_length=10)
date = models.DateTimeField(auto_now_add=True, blank=True)
def __unicode__(self):
return unicode(self.year_id)
class Order(models.Model):
user = models.ForeignKey(User, related_name='who_ordered')
select = models.ManyToManyField(Catalog, related_name='annuals_ordered', blank=True, null=True)
def __unicode__(self):
return unicode(self.user)
Here is the query I've been trying:
Catalog.objects.filter(order__select__annual='2014')
If you need users, you should start with users. Also, you need to filter on a specific field in Annual, ie year_id.
User.objects.filter(order__select__annual__year_id=2014)
If I got your question correctly then, your query is wrong. There is no attribute name order inside your Catalog model, then how can you use it for filtering ? Or I'm missing anything here ?
Directly using the related name references on the related fields, you can get the users by using -
# id is auto generated field or you can pass one annual_product object.
User.objects.filter(who_ordered__select__annual_products__id=1)
# OR
annual = Annual.objects.all()[0]
User.objects.filter(who_ordered__select__annual_products=annual)
The step by step how you can achieve the same :-
# where 1 is the id of an one object in Catalog model.
# You can pass Catalog object also to filter the users
Order.objects.filter(select__id=1)
# Here is the full query
catalog = Catalog.objects.all()[0]
orders = Order.objects.filter(select=catalog)
users = [o.user for o in orders] # This loop isn't necessary.
Now you have all orders specific to one Catalog, from this you can get the user object by using the user attribute in each order.