Django One(Many)-To-Many Relation in reusable app - django

I have a model named Exam. each Exam has a set of users called participants. The only way I found to keep such set in Django is to add a field in User model. But I'd prefer to write this model to be as independent as possible so if later I want to use it again I can do it without changing my User model. So How can I handle having such set without manually modifying the User model fields?

Regarding your comment here is what you could do something like this:
class Exam(models.Model):
participants = models.ManyToMany(settings.AUTH_USER_MODEL, through='Participation')
class Participation(models.Model)
user = models.OneToOneField(settings.AUTH_USER_MODEL)
exam = models.ForeignKey('Exam')
active = models.BooleanField(default=False)
Another option would be to use Django's limit_coices_to. It's not transaction-save, but might do the job. You would just limit to choices to all non-related objects.

Related

How can I access a value from one model and pass to another model in Django?

I have one model called Weight (filled by User input/choice) and another called Enterprise.
class Weight(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="weights")
weight_of_history = models.IntegerField(null=True, blank=True)
class Enterprise(models.Model):
...
The weight is saved, one per user, and replaced everytime the user choose new one.
Inside the Enterprise class, I am creating an property that must get the "weight_of_history" (depending on the user, who has chosen the weight) from Weight class, but the models have no Foreign key or related name between them.
class Enterprise(models.Model):
...
#property
def ranking(self):
weight_of_history = <-- HERE I NEED TO TAKE WEIGHT_HISTORY FROM THE FIRST MODEL
THEN I COULD CALCULATE
How could I do that? Thank you!
You can use django's powerful query functionality and fetch the required objects from the db. Here are the docs that might help you with that. Django docs are amazing, so I would recommend that you read up on queries, models, and forms to have easier time with you project.
For your example we can fetch all the weights for the user in one query by filtering the weights by user. In fact, django ORM allows for chaining filters and you can create really sophisticated queries
class Enterprise(models.Model):
...
#property
def ranking(self):
weight_of_history = Weight.objects.filter(user=some_user)
If you do not know the user beforehand, then you can do inside the view and grab the user that makes the request and filter using this user:
#views.py
user_making_request = request.user
weight_of_history = Weight.objects.filter(user=user_making_request)

User model with static set of related models

Say I have a User model in django and I want to add some achievements to users. So I've created an Achieve model:
class Achive:
type = ....
value = ....
status = BooleanField(default=False)
I want all those achieves be a static set of models for every user (20 instances, for example) with ability to delete old and create new achieves. The problem is how to do it. Expected flow is:
1) user granted to use achievement system;
2) user got all those achieves (in admin panel shows like a table);
3) in admin panel per user I can change status of every achieve (affects only on edited user);
4) if new Achieve instance is created — add to all users who have achievements;
5) if existed Achieve instance has been deleted — remove from all users;
Solutions with I came up:
1) use Achieve model with jsonfield. store achieves in json like dictionary, use custom widget for admin panel to show checkboxes to change status). But where to store global set of achievements to create new/delete old ones? how to manage it?
2) use many to many field to Achieve and Achieve model without status. Why: if relation between User ← → Achieve exists, that means that user earn an achieve.
Both solutions I don't really like so hope for your advice.
P.S. sqlite is used as db and not allowed to use another (like mongo, etc.)
Thanks in advance!
What you want is a ManyToMany relationship between Achieve and User, but with the ability to store extra data on the relationship (the status for example).
With a normal ManyToManyField on a Model, Django actually creates an intermediate model to store the relationships in the database. By adding a through argument to your ManyToManyField, you can specify the intermediate model used for the relationship and store extra data with the relationship, as documented here:
class Goal(models.Model):
type = ...
value = ...
achievers = models.ManyToManyField(to=User, through='Achievement', related_name='goals')
class Achievement(models.Model):
status = models.BooleanField()
date_reached = models.DateField(null=True)
goal = models.ForeignKey(to=Goal, on_delete=models.CASCADE)
achiever = models.ForeignKey(to=User, on_delete=models.CASCADE)
then you can create and query the relationships like this, assuming you have a user and a goal:
achievement = Achievement.objects.create(status=True, date_reached=date(2018, 10, 12), achiever=user, goal=goal)
user.goals.filter(achievement__status=True) # gives the achieved goals of a user
goal.achievers.filter(achievement__status=True) # gives the users that achieved a goal

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")

Use multiwidget for many to many field with readonly additional data

I've the following models:
class Exam(models.Model):
participants = models.ManyToMany(settings.AUTH_USER_MODEL, through='Participation')
class Participation(models.Model)
user = models.OneToOneField(settings.AUTH_USER_MODEL)
exam = models.ForeignKey('Exam')
specific_number = models.PositiveIntegerField(editable=False)
As you can see, the data I'm storing in intermediary model is readonly. It's generated automatically by the system when an instance is created. So I'd like to be able to use the multiwidget in admin to select the participants. (Using inline is really hard when you have a large number of users).
Is there anyway to do it?
The only way I found was to use a new view for managing participants in the admin and add a link to it by overriding the default edit template.

Model design question: custom fields at runtime?

I have some newbie questions about Django.
I want to write a generic ticket-management system, where the administrator of the site should be able to add custom fields to a ticket. It seems that the database tables are generated on initialization, so it is not clear to me how to add custom fields at runtime.
One way is to have a long list of fields of different types, all nullable, and let the administrator rename/select the fields she needs. Is there a better design?
Thanks!
I'm currently in charge of maintaining a similar site where a treatment for a medical condition is listed and there can be arbitrary number of "cases" which are user-posted experiences for that treatment/condition combo attached.
The method my company used to set it up was to have an Entry object which would be analogous to the custom field you described, which has a Foreign Key referencing the treatment/condition to which it belongs.
Then when we want to get all the entries for a particular treatment/condition combo, we simply do an
Entry.objects.filter(condition=ID)
So, in your case, I would suggest having a Ticket model, and an "Entry" style model which contains a Foreign Key reference to the Ticket to which it belongs.
I would make something like the code below. Store extra attributes in an attribute model. Store the values in AttributeValue.
class Ticket(models.Model):
name = models.CharField(max_length=200)
class Attribute(models.Model):
name = models.CharField(max_length=200)
class AttributeValues(models.Model):
attribute = models.ForeignKey(Attribute)
ticket = models.ForeignKey(Ticket)
value = models.CharField(max_length=200)