Django - can you explain this? - django

I have three models:
System_Contact
System
Contact_list
The Contact_List model has two fields: contact and sys and, not surprisingly, is just a manyToMany model to associate a list of contacts to each system. I have modelForm for adding a new contact to the system's list of contacts:
class Add_Contact_Form(ModelForm):
class Meta:
model = Contact_List
fields = ('contact',)
Simple, right? My confusion is this: Even thought the Contact_List model has many many duplicate contacts (because one contact can be associated with many systems) each contact is only displayed once within the form's Select widget.
Why?!
I mean, this is a great default behaviour for my purposes, but I want to make sure this is actually the correct default behaviour that I can rely on, not some random error I have done that just happens to work out for me now.

It's not that it's default behaviour, it's that the select widget in your contact_list form is displaying all of the entries that are from the contact table.
Every model is a table in the database, therefore you have 3 tables:
ContactTable - where every row in the table is a person
SystemTable - where every row in the table is a computer (for arguements sake)
ContactListTable - where every row is a mapping between a system and a list of users
If this is what you are trying to do, you should have the following:
class Contact(models.Model):
name = ...
class System(models.Model):
type = ...
class ContactList(models.MOdel):
system = models.ForeignKey(System)
contacts = models.ManyToManyField(Contact)
This means that every row in the ContactList table is a relationship between a particular machine from the system table and a list of contacts from the contact table

Related

Choose a specific manager for a related field for a model

I am in a situation where I need to use a custom manager for a related field which is different from the base_manager for the related fields. Let's say that I have a model Item which is in one to many relation with another model Purchase. Now, Item has 2 managers:
objects = ItemManager() #which by default excludes the out_of_stock=True items
complete = CompleteItemManager() #which gives all the items.
For all the other models related to Item, ItemManager is the default one. But in Purchase, I would want to use the CompleteItemManager for the related Item.
So let's say there was once a purchase for an item which is now has out_of_stock=True and we just have the id of that purchase say old_purchase_id, now if try to run the below query:
purchase = Purchase.objects.filter(id=old_purchase_id) # gives error
It would give an error like "Item matching query does not exist" as the manager being used for the related items is ItemManager which excludes such out of stock items.
What can be done in that case? Ideally I would want something to override the manager to be used for a given related field per model, so that even if all other models use ItemManager to resolve item fields, the Purchase Model still uses the CompleteItemManager for its relations with Item.
When accessing a reverse relation you can specify a custom manager to use by calling the related_name and passing the custom manager by name
purchase.item_set.all() # Uses ItemManager
purchase.item_set(manager='complete').all() # Uses CompleteItemManager
Here's how I did it.
I made a CustomForwardManyToOneDescriptor which would just pick the manager named complete for the related model. And used that descriptor in a CustomForeignKey as the forward_related_accessor_class.
class CustomForwardManyToOneDescriptor(ForwardManyToOneDescriptor):
def get_queryset(self, **hints):
related_model = self.field.remote_field.model
return related_model.complete.db_manager(hints=hints).all()
class CustomForeignKey(models.ForeignKey):
forward_related_accessor_class = CustomForwardManyToOneDescriptor
Now using the CustomForeignKey instead of ForeignKey to create OneToMany relation with a model would make that model use the complete manager for the foreign key field no matter what the default related manager is.

How can I create a model that represents a spreadsheet?

I am trying to build a table style app to allow tracking items in a spreadsheet that can be added to a branded website. My table would look something like this if using a spreadsheet:
Customer Name
Customer Address
Producer
Mark
233 Main St
Greg
Company
Date Ordered
Rep
Date Received
Cost
Quote Number
A
7/20/21
John
7/25/21
500
JDHP
B
7/20/21
Mary
C
7/23/21
John
7/25/21
1500
584D
D
7/18/21
Mary
7/22/21
400
J5HP
Effectively the idea is that I'd have a model that houses each Customer's different quotes. I have 2 categories of companies (public and private) that would each be tracked so I'm envisioning a large form that houses these three small forms (customer info, private company quotes and public company quotes). I would be including every company in every sheet whether we reach out to them for a quote or not so we know what options are still available if the customer requests more quotes.
I've been looking at the django formsets as a possible option but don't fully understand how they work. I watched some tutorials and read through the documentation but it seems like those will simply add a blank input after all complete ones already in the table. Is this a correct interpretation of how formsets work? Or would they effectively allow me to nest multiple forms within a larger form? Secondary to that is how would I implement this model? I tried company_date_ordered, company_rep, company_date_received, etc. for each company in my list but got a lot of clash errors.
Welcome to web development.
A few points:
It's been said, "Applications age like fish, data ages like wine" - what this means is its best to focus your attention on your data models and concern yourself less with the application code itself
Spreadsheets are themselves tables - meaning you wouldn't build a model that represents a spreadsheet but rather you would build a model that represents a row (object) or elements of each row (objects) of the spreadsheet
That being said, given your example let's consider what objects we are working with:
Your first "spreadsheet" looks like it could be a combination of a Customer and Producer table - for this example we will simplify this to just a Customer table which will contain the field producer
Your second spreadsheet is a bit more complex, it appears to join Company, something like an Order and possibly a Representative (and maybe even more) - let's break this down into each of its parts:
models.py
class Customer(models.Model):
"""
this is a simple model that represents a customer,
it doesn't have any relations to other tables
"""
name = models.CharField(...)
address = models.CharField(...)
producer = models.CharField(...)
class Order(models.Model):
"""
this table represents orders,
it will have relations to other tables, add them as needed
"""
# fields:
date_ordered = models.DateField(...)
date_received = models.DateField(...)
quote_number = models.CharField(...)
"""
an Order can only be associated to one Company
but a Company can have many Orders
therefore we will use a ForeignKey
the same goes for Representative
"""
# relations:
company = models.ForeignKey("Company", ..., related_name = "orders")
representative = models.ForeignKey(...)
class Company(models.Model):
"""
this model represents a Company
its related to Orders,
but the relation is defined on the Orders table
"""
name = models.CharField(...)
class Representative(models.Model):
...
Spend some time thinking about what your entities are and how they relate to one another. Once your data structure is well formed, you can start to build out interfaces for users to view, edit, and add to your tables - forms are a good way to start but they are certainly not the only option. Best of luck!

django - many-to-many and one-to-many relationships

I am working in django, am planning a database for rides for users.
each User can be on multiple Rides (over time) and each Ride can have multiple Users (passengers) in it.
Also, for each Ride there has to be only one Driver (also a User) so I think I have a many-to many relationship between the Rides and Users tables for what user is on what ride, and also a One-To-Many relationship between the Rides's Driver_id and the User_id. right?
My questions are-
I saw in the django docs that I should put a many-to-many field in One of the models. Does it matter which one? and also, does it create a new table like rides_users?
and also, what is the difference (in One-To-many relationship) between using a foreignKey field and a OneToManyField field?
EDIT:
Currently, there are my models:
def get_image_path(models.Model):
return os.path.join('photos',str(instance.id),filename)
class UserProfile(models.Model):
user=models.OneToOneField(User)
phone_number=models.CharField(max_length=12)
profile_picture=models.ImageField(upload_to=get_image_path, black=True, null=True)
class Ride(models.Model):
driver=models.ForeignKey(UserProfile, related_name="r_driver")
destination=models.ForeignKey(Destination, related_name="r_final_destination")
leaving_time=models.DateTimeField()
num_of_spots=models.IntergerField()
passengers=models.ManyToMany(UserProfile, related_name="r_passengers")
mid_destinations=models.ManyToMany(Destination, related_name="r_mid_destinations")
class Destination(models.Model):
name=models.CharField(max_length=30)
As you can see, each Ride has multiple mid_destination and multiple passengers. a Ride also has One driver and One final destination.
The Issue is - when a User adds a Ride, I want the driver, destination and mid_destinations and the rest of the fields to be set by the User (the driver is user adding the Ride), Except for the passengers field. I want the other Users to add themselves to the ride, so when the Ride is created the User (driver) doesn't have to set the passengers.
How do I go about it? and also, any other suggestions about the models?
There is no such thing as a OneToManyField.
It doesn't matter from a practical point of view which side the ManyToManyField lives on. Personally, I'd put it on Ride, both to avoid changing the User model and because conceptually I'd say that rides are the main objects here.
And yes, adding the field will automatically create the linking table.
what you want is probably something like this
class MyModel(models.Model):
driver = models.ForeignKey(to=User, related_name='r_driver')
# you need to use a related name if you want to link to the same model more than once
passengers = models.ManyToManyField(User, related_name="r_passengers")

django nested models field access

Here's the scenario:
I have a Student Model with subject field connected with Many-to-Many relationship to Subject Model
class Student(models.Model):
(...)
subject = models.ManyToManyField(Subject)
In Subject Model i have a program field connected with Many-to-Many relationship to Programs Model. Subject Model got also CharField name.
class Subject(models.Model):
(...)
program = models.ManyToManyField(Programs)
In Programs Model i have a field:
class Programs(models.Model):
name = models.CharField(max_length=40)
(...)
Django creates additional table for many-to-many fields. In my application I create (with form) a Program and Subject corresponding to Program. Then i create some Students and choose some subjects.
How can i access program name field (Student.objects.all()) and display what program name Student is using ? Is it possible, or i need to create additional fields in Student Model connected with Many-to-Many relationships with Program Model ?
Am I right in thinking that you want to return a list of the program names for the programs belonging to each subject in student.subject?
If so you could use this as a method of the Student model:
def get_program_names(self)
programs = []
for subject in self.subjects:
programs += [program.name for program in subject.program]
return programs
It sounds from your question, however, that you expect only one program name to be returned. if this is the case then maybe you should replace your manyToMany fields with ForeignKey fields, which give a one to one relationship between two models, meaning that this method should work:
def get_program_name(self):
return self.subject.program.name
(either way, there is no reason you should have to create a direct link between your student model and the program model, unless you wish to reduce the number of database calls, in which case you could add a field to Student which is updated with the latest program name or similar.)
I hope that I haven't misunderstood your question.

Creation of dynamic model fields in django

This is a problem concerning django.
I have a model say "Automobiles". This will have some basic fields like "Color","Vehicle Owner Name", "Vehicle Cost".
I want to provide a form where the user can add extra fields depending on the automobile that he is adding. For example, if the user is adding a "Car", he will extra fields in the form, dynamically at run time, like "Car Milage", "Cal Manufacturer".
Suppose if the user wants to add a "Truck", he will add "Load that can be carried", "Permit" etc.
How do I achieve this in django?
There are two questions here:
How to provide a form where the user can add new fields at run time?
How to add the fields to the database so that it can be retrieved/queried later?
There are a few approaches:
key/value model (easy, well supported)
JSON data in a TextField (easy, flexible, can't search/index easily)
Dynamic model definition (not so easy, many hidden problems)
It sounds like you want the last one, but I'm not sure it's the best for you. Django is very easy to change/update, if system admins want extra fields, just add them for them and use south to migrate. I don't like generic key/value database schemas, the whole point of a powerful framework like Django is that you can easily write and rewrite custom schemas without resorting to generic approaches.
If you must allow site users/administrators to directly define their data, I'm sure others will show you how to do the first two approaches above. The third approach is what you were asking for, and a bit more crazy, I'll show you how to do. I don't recommend using it in almost all cases, but sometimes it's appropriate.
Dynamic models
Once you know what to do, this is relatively straightforward. You'll need:
1 or 2 models to store the names and types of the fields
(optional) An abstract model to define common functionality for your (subclassed) dynamic models
A function to build (or rebuild) the dynamic model when needed
Code to build or update the database tables when fields are added/removed/renamed
1. Storing the model definition
This is up to you. I imagine you'll have a model CustomCarModel and CustomField to let the user/admin define and store the names and types of the fields you want. You don't have to mirror Django fields directly, you can make your own types that the user may understand better.
Use a forms.ModelForm with inline formsets to let the user build their custom class.
2. Abstract model
Again, this is straightforward, just create a base model with the common fields/methods for all your dynamic models. Make this model abstract.
3. Build a dynamic model
Define a function that takes the required information (maybe an instance of your class from #1) and produces a model class. This is a basic example:
from django.db.models.loading import cache
from django.db import models
def get_custom_car_model(car_model_definition):
""" Create a custom (dynamic) model class based on the given definition.
"""
# What's the name of your app?
_app_label = 'myapp'
# you need to come up with a unique table name
_db_table = 'dynamic_car_%d' % car_model_definition.pk
# you need to come up with a unique model name (used in model caching)
_model_name = "DynamicCar%d" % car_model_definition.pk
# Remove any exist model definition from Django's cache
try:
del cache.app_models[_app_label][_model_name.lower()]
except KeyError:
pass
# We'll build the class attributes here
attrs = {}
# Store a link to the definition for convenience
attrs['car_model_definition'] = car_model_definition
# Create the relevant meta information
class Meta:
app_label = _app_label
db_table = _db_table
managed = False
verbose_name = 'Dynamic Car %s' % car_model_definition
verbose_name_plural = 'Dynamic Cars for %s' % car_model_definition
ordering = ('my_field',)
attrs['__module__'] = 'path.to.your.apps.module'
attrs['Meta'] = Meta
# All of that was just getting the class ready, here is the magic
# Build your model by adding django database Field subclasses to the attrs dict
# What this looks like depends on how you store the users's definitions
# For now, I'll just make them all CharFields
for field in car_model_definition.fields.all():
attrs[field.name] = models.CharField(max_length=50, db_index=True)
# Create the new model class
model_class = type(_model_name, (CustomCarModelBase,), attrs)
return model_class
4. Code to update the database tables
The code above will generate a dynamic model for you, but won't create the database tables. I recommend using South for table manipulation. Here are a couple of functions, which you can connect to pre/post-save signals:
import logging
from south.db import db
from django.db import connection
def create_db_table(model_class):
""" Takes a Django model class and create a database table, if necessary.
"""
table_name = model_class._meta.db_table
if (connection.introspection.table_name_converter(table_name)
not in connection.introspection.table_names()):
fields = [(f.name, f) for f in model_class._meta.fields]
db.create_table(table_name, fields)
logging.debug("Creating table '%s'" % table_name)
def add_necessary_db_columns(model_class):
""" Creates new table or relevant columns as necessary based on the model_class.
No columns or data are renamed or removed.
XXX: May need tweaking if db_column != field.name
"""
# Create table if missing
create_db_table(model_class)
# Add field columns if missing
table_name = model_class._meta.db_table
fields = [(f.column, f) for f in model_class._meta.fields]
db_column_names = [row[0] for row in connection.introspection.get_table_description(connection.cursor(), table_name)]
for column_name, field in fields:
if column_name not in db_column_names:
logging.debug("Adding field '%s' to table '%s'" % (column_name, table_name))
db.add_column(table_name, column_name, field)
And there you have it! You can call get_custom_car_model() to deliver a django model, which you can use to do normal django queries:
CarModel = get_custom_car_model(my_definition)
CarModel.objects.all()
Problems
Your models are hidden from Django until the code creating them is run. You can however run get_custom_car_model for every instance of your definitions in the class_prepared signal for your definition model.
ForeignKeys/ManyToManyFields may not work (I haven't tried)
You will want to use Django's model cache so you don't have to run queries and create the model every time you want to use this. I've left this out above for simplicity
You can get your dynamic models into the admin, but you'll need to dynamically create the admin class as well, and register/reregister/unregister appropriately using signals.
Overview
If you're fine with the added complication and problems, enjoy! One it's running, it works exactly as expected thanks to Django and Python's flexibility. You can feed your model into Django's ModelForm to let the user edit their instances, and perform queries using the database's fields directly. If there is anything you don't understand in the above, you're probably best off not taking this approach (I've intentionally not explained what some of the concepts are for beginners). Keep it Simple!
I really don't think many people need this, but I have used it myself, where we had lots of data in the tables and really, really needed to let the users customise the columns, which changed rarely.
Database
Consider your database design once more.
You should think in terms of how those objects that you want to represent relate to each other in the real world and then try to generalize those relations as much as you can, (so instead of saying each truck has a permit, you say each vehicle has an attribute which can be either a permit, load amount or whatever).
So lets try it:
If you say you have a vehicle and each vehicle can have many user specified attributes consider the following models:
class Attribute(models.Model):
type = models.CharField()
value = models.CharField()
class Vehicle(models.Model):
attribute = models.ManyToMany(Attribute)
As noted before, this is a general idea which enables you to add as much attributes to each vehicle as you want.
If you want specific set of attributes to be available to the user you can use choices in the Attribute.type field.
ATTRIBUTE_CHOICES = (
(1, 'Permit'),
(2, 'Manufacturer'),
)
class Attribute(models.Model):
type = models.CharField(max_length=1, choices=ATTRIBUTE_CHOICES)
value = models.CharField()
Now, perhaps you would want each vehicle sort to have it's own set of available attributes. This can be done by adding yet another model and set foreign key relations from both Vehicle and Attribute models to it.
class VehicleType(models.Model):
name = models.CharField()
class Attribute(models.Model):
vehicle_type = models.ForeigngKey(VehicleType)
type = models.CharField()
value = models.CharField()
class Vehicle(models.Model):
vehicle_type = models.ForeigngKey(VehicleType)
attribute = models.ManyToMany(Attribute)
This way you have a clear picture of how each attribute relates to some vehicle.
Forms
Basically, with this database design, you would require two forms for adding objects into the database. Specifically a model form for a vehicle and a model formset for attributes. You could use jQuery to dynamically add more items on the Attribute formset.
Note
You could also separate Attribute class to AttributeType and AttributeValue so you don't have redundant attribute types stored in your database or if you want to limit the attribute choices for the user but keep the ability to add more types with Django admin site.
To be totally cool, you could use autocomplete on your form to suggest existing attribute types to the user.
Hint: learn more about database normalization.
Other solutions
As suggested in the previous answer by Stuart Marsh
On the other hand you could hard code your models for each vehicle type so that each vehicle type is represented by the subclass of the base vehicle and each subclass can have its own specific attributes but that solutions is not very flexible (if you require flexibility).
You could also keep JSON representation of additional object attributes in one database field but I am not sure this would be helpfull when querying attributes.
Here is my simple test in django shell- I just typed in and it seems work fine-
In [25]: attributes = {
"__module__": "lekhoni.models",
"name": models.CharField(max_length=100),
"address": models.CharField(max_length=100),
}
In [26]: Person = type('Person', (models.Model,), attributes)
In [27]: Person
Out[27]: class 'lekhoni.models.Person'
In [28]: p1= Person()
In [29]: p1.name= 'manir'
In [30]: p1.save()
In [31]: Person.objects.a
Person.objects.aggregate Person.objects.all Person.objects.annotate
In [32]: Person.objects.all()
Out[33]: [Person: Person object]
It seems very simple- not sure why it should not be a considered an option- Reflection is very common is other languages like C# or Java- Anyway I am very new to django things-
Are you talking about in a front end interface, or in the Django admin?
You can't create real fields on the fly like that without a lot of work under the hood. Each model and field in Django has an associated table and column in the database. To add new fields usually requires either raw sql, or migrations using South.
From a front end interface, you could create pseudo fields, and store them in a json format in a single model field.
For example, create an other_data text field in the model. Then allow users to create fields, and store them like {'userfield':'userdata','mileage':54}
But I think if you're using a finite class like vehicles, you would create a base model with the basic vehicle characteristics, and then create models that inherits from the base model for each of the vehicle types.
class base_vehicle(models.Model):
color = models.CharField()
owner_name = models.CharField()
cost = models.DecimalField()
class car(base_vehicle):
mileage = models.IntegerField(default=0)
etc