Sharing Django Models with Foreign Fields across apps - django

I have a Django project with two apps that are almost identical but for a number of reasons, I'd like to keep them separate. To keep things DRY, I created a base_model file.
# base_model.py
from django.db import models
class ModelOne(models.Model):
name = models.CharField()
class ModelTwo(models.Model):
name = models.CharField()
friend = models.ForeignKey(ModelOne)
My two apps are called app1 & app2.
How do I import these models so that essentially I'll have 4 tables for these two models?
Thanks.
UPDATE 1
The reason why I need two versions of these 2 models is that I want to keep them in a separate database as they have separate uses.
For example, let's say I own a home with furniture and as well as a furniture store. I want to keep a separate list for both sets of furniture. The furniture in my home will be kept on a home server, while my store furniture will be kept on a work server. In addition, I'll also like to keep track of the color of the furniture, so that will be a separate table.
# base_model.py
from django.db import models
class Color(models.Model):
name = models.CharField()
class FurnitureBase(models.Model):
name = models.CharField()
color = models.ForeignKey(Color)
For the store app, I need to keep track of pricing, manufacturer, etc. For the home app, I'll need to keep track of usage, age, etc.

These two models should be defined as abstract = True under Meta. Then in each of your two apps, sub-class to create concrete versions in each app. Something like:
app1/models.py:
class App1ModelOne(base_models.ModelOne):
pass
class App1ModelTwo(base_models.ModelTwo):
pass
Read abstract base classes and model inheritance in django's docs for more information: https://docs.djangoproject.com/en/1.7/topics/db/models/#abstract-base-classes

Related

Including fields from a OneToOneField in Django Admin

I am attempting to add the fields from a OneToOneField into my admin view. Here is an example of how my models look.
class Customer(BaseUser):
name = CharField()
address = CharField()
secondary_information = OneToOneField("SecondaryCustomerInfo", on_delete=SET_NULL, null=True)
class SecondaryCustomerInfo(models.Model):
email = EmailField()
And I tried adding in the fields as an inline like this.
class SecondaryCustomerInfoInline(admin.StackedInline):
model = SecondaryCustomerInfo
class CustomerAdmin(admin.ModelAdmin):
inlines = [SecondaryCustomerInfoInline]
But I get the error
<class 'user.admin.SecondaryCustomerInfoInline'>: (admin.E202) 'user.SecondaryCustomerInfo' has no ForeignKey to 'user.Customer'.
I'm used to putting the OneToOneField on the secondary model but my coworker asked that I put it on the main Customer model since we will be accessing that information more often. I think switching things around is what is tripping me up. How would I include the fields from SecondaryCustomerInfo on the admin view for Customer?
The answer would be to use Django Reverse Admin
From its documentation:
Module that makes django admin handle OneToOneFields in a better way. A common use case for one-to-one relationships is to "embed" a model inside another one. For example, a Person may have multiple foreign keys pointing to an Address entity, one home address, one business address and so on. Django admin displays those relations using select boxes, letting the user choose which address entity to connect to a person. A more natural way to handle the relationship is using inlines. However, since the foreign key is placed on the owning entity, django admins standard inline classes can't be used.
class CustomerAdmin(ReverseModelAdmin):
inline_type = 'stacked'
inline_reverse = ['secondary_information']

Importing model classes from other apps without causing circular reference in Django

I have 3 apps products, sales, purchases. each app has a correspondingly named Model class, Product, Sale, and Purchase.
products/models.py
class Product(models.Model):
Name = models.CharField(max_length=32)
sales/models.py
class Sale(models.Model):
Product = models.ForeignKey('products.Product', on_delete=models.CASCADE)
purchases/models.py
class Purchase(models.Model):
Product = models.ForeignKey('products.Product', on_delete=models.CASCADE)
And I decided to make custom managers for the Model classes so that I can keep all the logic in the model files (by overriding objects attr for each class) when I'm writing the methods in the custom manager I imported Sale model In products.models and Product model in sales.models which creates a circular reference, I was able to get away with it by performing the imports in the methods themselves but I remember reading online that circular imports are sign of bad code writing.
So my question is how can I avoid circular imports in this case and have access to the Product Model in sales.models and Sale in products.models.
You can import a model by name to avoid circular imports. When you need to use the model, import it like this:
from django.apps import apps
ModelName = apps.get_model(app_label='app_name', model_name='ModelName')
Running into circular importing means you are fighting against the separation you've created, or you're not writing appropriately decoupled code. In your case, I think you may be trying too hard to separate these models into separate apps. Surely sales and purchases are part of the same set of functionality and share lots of business logic. Even products could live in the same app, although you might have more of an argument there.
If you're coming from another language where it's customary not to have multiple classes in a single file, you should know that is not a best practice in python. Note in the official Django tutorial, the polls app has both Question and Answer models in the same file.
I think a single app named commerce with all three models in the same models.py file would make sense.
# commerce/models.py
class Product(models.Model):
name = models.CharField(max_length=32)
class Sale(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
class Purchase(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)

Is it possible to define views and templates for abstract models to be used for actual models?

Let's say I have a myapp django app and that I need to define 2 specific contact-related models, e.g.
myapp.PersonContact
myapp.CompanyContact
Somewhat obvious thing to do is to create a new contacts app and define an abstract contacts.Contact model which can then be reused in myapp.models, e.g.:
# contacts/models.py
from django.db import models
class Contact(models.Model):
name = models.CharField(max_length=80)
...
class Meta:
abstract = True
# myapp/models.py
from contacts.models import Contact
class PersonContact(Contact):
person = ...
class CompanyContact(Contact):
company = ...
My goal is to abstract as much logic as possible to the contacts app but the only thing that comes to mind is to define an Abstract class contacts.Contact and use that so that I don't have to redefine the same fields in myapp.PersonContact and myapp.CompanyContact.
Is is somehow possible to define contacts.Contact related views and/or templates within the contacts app so that I don't have to create almost identical CRUD-ish views and templates for both PersonContact and CompanyContact?

Django Design Reusable Apps?

I am developing Django application, but still have confusion over apps design pattern, let say my application has models like follow.
class Department(models.Model):
name = models.CharField(max_length=255)
class Student(models.Model):
name = models.CharField(max_length=255)
department = models.ForeignKey(Department)
As u see student model has relation of department = models.ForeignKey(Department)
In This case should i need to create separate apps for department and student or is it good enough to create custom_app with both department and student models ?
You don't have to create app for each model. App is more high level thing. You can logically think of app name which contains both models: for example, 'university' or 'practice' or even 'students' that will contain all the business logic of interaction with this models. Below you can create another app that could have any other models. Just try to link each model to only one app if you can

How to avoid duplicate models in django project?

i'm learning django so i've many questions, and one is how i can reuse a model? i mean the models live in the application folder, but some models are exactly the same between two differents applications.
So should i rewrite the model every time that i write a new app?
Yes, this is wrong when you have the same names of yours apps
You also can use abstract models
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
If your models are exactly the same in different applications, you're doing something wrong. Don't forget that an application is basically just a set of models, and you can use one application's models within another application just by importing them.
Can you give an example of two applications with exactly the same models?
How do I reuse a Model.
Best way to reuse model is to Inherit the parent Model class. This is how you must be doing it. Inheriting from models.Model.
from django.db import models
class trial(models.Model):
# override the parent class methods here or define your own
Also make sure that you import your apps models in the appropriate models.py file.