I'm trying to create a simple to-do app in Django. I have some trouble to understand the idea of foreign keys. Each project suppose to get multiple apartments, and each apartment should get multiple tasks.
models:
# Project model
class Project(models.Model):
name = models.CharField(_("Name"), max_length=30)
city = models.CharField(_("City"), max_length=30)
street = models.CharField(_("Street"), max_length=30)
number = models.IntegerField(_("Number"), max_length=4)
ZIP = models.ImageField(_("ZIP"), max_length=10)
manager = models.CharField(_("Manager"), choices=managers, default='ariel')
# Apartments
apartment = models.ForeignKey(_("Apartment"), Apartment, on_delete=models.CASCADE)
def __repr__(self):
return "{}".format(self.name)
# Apartment model
class Apartment(models.Model):
building = models.CharField(_("Building"), max_length=4)
floor = models.CharField(_("Floor"), max_length=4)
number = models.CharField(_("Number"), max_length=4)
type = models.CharField(_("Type"), max_length=4)
upgraded = models.BooleanField(_("Upgraded"), default=False)
drawing = models.FileField(_("Drawing"), upload_to=None)
notes = models.TextField(_("Notes"), max_length=500)
status = models.BooleanField(_("Completed"), default=False)
# Tasks
airTunnels = models.ForeignKey(_("Air Tunnels"), Task, on_delete=models.CASCADE)
gasPipelines = models.ForeignKey(_("Gas Pipelines"), Task, on_delete=models.CASCADE)
def __repr__(self):
return "{} - {}".format(self.number, self.status)
# Task model
class Task(models.Model):
title = models.CharField(_("Task"), max_length=30)
doneBy = models.CharField(_("Done By"), choices=workers, default='daniel')
date = models.DateTimeField(_("Date"), default=timezone.now())
def __repr__(self):
return "{}".format(self.title)
If you use apartment = models.ForeignKey(_("Apartment"), Apartment, on_delete=models.CASCADE), it means that each project has onyl one apartment. So you must define different project for each apartment. If your each apartment can has only one project, you must define foreignkey inside your apartment model like that:
class Apartment(models.Model):
#...your other fields
project = models.ForeignKey(Project, on_delete=models.CASCADE)
For apartment tasks, If I understood correctly, your apartment model can has multiple tasks.So, you can use ManyToMany field for this.With this definition, your each apartment can has multiple tasks. But your each task can belong to multiple apartment objects. If you don't want to each task can belongs to different apartment objects, you must set OneToMany relation.You can do that with adding foreignkeyfield to task model like that:
class Task(models.Model):
#...your other fields
apartment = models.ForeignKey(Apartment, on_delete=models.CASCADE)
Related
I have these two models:
How do I correctly set the relationship so I can do backward queries?
class Client(models.Model):
city = models.CharField(max_length=16)
worker = models.ForeignKey(
"Worker",
null=True,
default="1",
on_delete=models.SET_DEFAULT,
related_name="assigned_workers",
)
class Meta:
abstract = True
And:
class Worker(models.Model):
first_name = models.CharField(max_length=16)
last_name = models.CharField(max_length=16)
gender = models.CharField(max_length=1)
What I want to do is set up the models in a way I can do the following queries:
Query the clients assigned to a worker using the worker object. Something like this:
Worker.objects.assigned_workers.all()
I have a Django model for a player of a game
class Player(models.Model):
name = models.CharField(max_length=50)
team = models.ForeignKey('Team', on_delete=models.CASCADE, blank=True, null=True)
game = models.ForeignKey('Game', on_delete=models.CASCADE)
objects = GameManager()
class Meta:
unique_together = ('name', 'game',)
I have only one unique constraint, that the name and the game are unique together.
Now, I would like to extend our page by adding registered users. So, I would add this to the model.
user = models.ForeignKey('auth.User', on_delete=models.CASCADE, blank=True, null=True)
So, an registered user can subscribe to a game by adding a name, team, game, and his/her user. However, the user should only be able to add his account once to an game, which would be a second unique constrain
unique_together = ('user', 'game',)
Is it possible to give in Django two unique constraints to the model? Or do I have to search in the table manually prior to saving the new entries? Or is there a better way?
Yes, in fact by default unique_together is a collection of collections of fields that are unique together, so something like:
class Player(models.Model):
name = models.CharField(max_length=50)
team = models.ForeignKey('Team', on_delete=models.CASCADE, blank=True, null=True)
game = models.ForeignKey('Game', on_delete=models.CASCADE)
objects = GameManager()
class Meta:
unique_together = (('name', 'game',), ('user', 'game',))
Here we thus specify that every name, game pair is unique, and every user, game pair is unique. So it is impossible to create two Player objects for the same user and game, or for the same game and name.
It is only because a single unique_together constraint is quite common, that one can also pass a single collection of field names that should be unique together, as is written in the documentation on Options.unique_together [Django-doc]:
Sets of field names that, taken together, must be unique:
unique_together = (("driver", "restaurant"),)
This is a tuple of tuples that must be unique when considered
together. It's used in the Django admin and is enforced at the
database level (i.e., the appropriate UNIQUE statements are included
in the CREATE TABLE statement).
For convenience, unique_together can be a single tuple when dealing with a single set of fields:
unique_together = ("driver", "restaurant")
You should use models.UniqueConstraint (reference).
As noted in the reference:
UniqueConstraint provides more functionality than unique_together. unique_together may be deprecated in the future.
Do this:
class Meta:
constraints = [
models.UniqueConstraint(fields=['name', 'game'], name="unique_name_game"),
models.UniqueConstraint(fields=['user', 'game'], name="unique_user_game"),
]
For example please refer to this :-
class Stores(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=50)
lat = models.FloatField()
lng = models.FloatField()
merchant = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="stores")
def __str__(self):
return "{}: {}".format(self.name, self.address)
class Meta:
verbose_name_plural = 'Stores'
class Items(models.Model):
name = models.CharField(max_length=50, unique=False)
price = models.IntegerField()
description = models.TextField()
stores = models.ForeignKey(Stores, on_delete=models.CASCADE, related_name="items")
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "Items"
unique_together = ('name', 'stores',)
I have an app which allows to associate to each client multiple boards, boards where I can upload files relevant for the client to make decisions about how the website page in question will look.
So the relationships I need to model are:
one client, multiple boards;
one board, one client;
one board, multiple files;
Let's concentrate on the first two
models.py
class Board(models.Model):
title = models.CharField(max_length=120, verbose_name="Titolo")
description = models.TextField()
files = models.FileField( null=True, blank=True, upload_to = 'clients_download_area', verbose_name = 'Client Reserved File')
date = models.DateTimeField(auto_now_add=True, verbose_name = 'Data di pubblicazione')
def __str__(self):
return str(self.title)
class Client(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=120)
boards = models.ManyToManyField(Board, blank=True)
def __str__(self):
return str(self.name)
Ok, relationship #1 is done. But what if I need to know which client is associated to a board (relationship #2)?
If I set a new field to Board Class
class Board(models.Model):
[...]
client = models.ForeignKey(Client, blank = True)
of course, when I makemigrations Django complains because it does not know what Client is, since I define it in the next model.
How can I design this DB?
Thank you in advance for any help you could provide
The problem here is that you reference to an identifer (here Client), before it is constructed (since Board is defined before the Client class).
Django has some support for this: you can pass strings that contain the name of the model. In the same app, you can just use ClassName, for another app, you can use other_app.ClassName, like the documentation says:
If you need to create a relationship on a model that has not yet been defined, you can use the name of the model, rather than the model
object itself:
from django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
'Manufacturer',
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
So here you can write it like:
class Board(models.Model):
title = models.CharField(max_length=120, verbose_name="Titolo")
description = models.TextField()
files = models.FileField( null=True, blank=True, upload_to = 'clients_download_area', verbose_name = 'Client Reserved File')
date = models.DateTimeField(auto_now_add=True, verbose_name = 'Data di pubblicazione')
client = models.ForeignKey(
'Client',
related_name='my_boards'
on_delete=models.CASCADE
)
def __str__(self):
return str(self.title)
class Client(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=120)
boards = models.ManyToManyField(Board, blank=True)
def __str__(self):
return str(self.name)
Note however that you already defined a ManyToManyField relation from Client to Board. Although it is possible it is not very common that two such relations exists simultaneously.
If you define a ForeignKey relationship from Board to Client, then Django automatically creates a reverse relationship (with the related_name), such that some_client.my_boards, is a manager of all the related Boards.
I think you can pass model class name instead of the class itself:
class Board(models.Model):
[...]
client_id = models.ForeignKey('Client', blank=True)
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.
I want to allow my users to define custom properties.
They are managing apartments so each customer manages the apartments in different way.
I want to allow them to define some custom properties for they apartments.
class Unit(CommonInfo):
version = IntegerVersionField( )
number = models.CharField(max_length=30,null=True, blank=True)
max_occupants = models.PositiveSmallIntegerField()
floor = models.PositiveSmallIntegerField()
rooms = models.PositiveSmallIntegerField()
is_disabled_access = models.BooleanField(default=False)
balcony_quantity = models.PositiveSmallIntegerField()
building = models.ForeignKey(Building)
recomended_price = models.DecimalField(max_digits=7, decimal_places=2)
I want them to be able additional fields to this model.
For example - is_breaker is_fuse Number_of
Since I cant predict what data they will require.
how can I do it?
I would reccomend the following solution:
1.Create a "property" Model:
class Property(models.Model):
property = models.CharField(max_length=140)
value = models.CharField(max_length=140)
def __str__(self):
return self.property
2.To your Unit model, add a ManytoMany field with property model:
class Unit(models.Model):
(...)
properties = models.ManyToManyField(Property)
3.Add an inline in your admin to view the different Properties:
class Unit(admin.ModelAdmin):
fields = ('__all__')
inlines = ('properties')