How can I create a many to one relationship with an existing model in django? Looking at the documentation, You can see that you can create a foreign key and create and object with a reference to the other model.
For example,
r = Reporter(first_name='John', last_name='Smith', email='john#example.com')
r.save()
a = Article(id=None, headline="This is a test", pub_date=date(2005, 7, 27), reporter=r)
a.save()
You can then access the id of r with a.reporter.id.
One problem with this, however is that if you wanted to check the id of r through a, you have to create a in order to do it.
How would you do this with an already existing model?
As an example, if I have a user and I want the user to be able to create multiple characters for a game, how can I assign the character a foreign key to the user if the user already exists?
Looking at this answer, you see that you need to give the model that you want to reference to the foreign key, but it doesn't actually explain how to do it.
How would you do this with an already existing model?
It's unclear which model you're referring to. If you mean an existing reporter, you'd get it and do it exactly the same way:
r = Reporter.objects.get(email='john#example.com')
a = Article(headline="This is a test", pub_date=date(2005, 7, 27), reporter=r)
a.save()
If you mean an existing article, you can change the foreign key just like any model instance field:
a = Article.objects.get(headline="This is a test")
a.r = Reporter.objects.create(...) # or .get() depending on what you want.
a.save()
How can I assign the character a foreign key to the user if the user already exists?
Using the same logic, you'd get the user and create a new character with this existing user object:
# Get user, or if this was the logged in user maybe just request.user
user = User.objects.get(username='wanderer')
# Create the character, using the existing user as a foreign key
# (the .create is just shorthand for creating the object then saving it)
Character.objects.create(character_name='Trogdor', user=user)
# Or alternatively, you can simply use the implicit reverse relationship
user.character_set.create(character_name='Homestar Runner')
Related
I am new to DJango and Python. Right now I am building a model that looks something like this:
Property -> Room -> Images.
I mean to say that a user can have a property.
Every property can have multiple rooms.
Every room can have multiple images.
Now I set property ID as foreign key in Room model.
And Room ID as foreign key in Image model.
But when I am making a post call to insert a new image for a specific room and a specific property.
It creates a image object even though the property id does not exist. It only checks for room id.
Though the put call is executing perfectly.
I want to validate both room id and property id before inserting a new image.
Code:
class PropertyRoom(models.Model):
pass
class PropertyRoom(models.Model):
property = models.ForeignKey(Property,related_name='rooms')
class PropertyRoomImage(AbstractImage):
room = models.ForeignKey(PropertyRoom, related_name='images')
localhost:8000/api/properties/221/rooms/1/images I am making a post call on this url for example. Room id 1 exist but property id 221 does not.
You shouldn't need to pass the room across at all, or if you do need to then you can just ignore it, you can just create an image using the id of the room, and if you need the property, then you can access the correct room via room.property
localhost:8000/api/properties/221/rooms/1/images I am making a post
call on this url for example. Room id 1 exist but property id 221 does
not.
You need to implement this check yourself. The models don't know about all the hierarchy of your data; or your business rules.
You need to check:
Property exists
Room being referenced, belongs to that property or not.
Image is of correct type/dimensions; etc.
Try a pattern like this:
from django.http import Http404
from django.shortcuts import get_object_or_404
def api(request, room=None, property=None):
property = get_object_or_404(Property, pk=property)
if not property.property_room_set.filter(pk=room).exists():
raise Http404
# other checks
# your normal logic
While theoretically your database should ensure that you have correct data, there are cases when this may not be the case, (IIRC foreign keys might not be present in the database on MySQL with mixed table engines (InnoDB and MyISAM))
Assuming you use forms, you could add a form validation to your upload form.
def clean(self):
cleaned_data = super(MyForm, self).clean()
image = cleaned_data['image']
property = cleaned_data['property']
if image.room.property != property:
raise ValidationError("room property and supplied property don't match")
return cleaned_data
You can write the same logic for models too, but beware they are not called by save by default, so you would have to create them explicitly. Official model validations documentation
image = PropertyRoomImage()
image.room = ...
image.full_clean() # call it explicitly as save doesn't
image.save()
I just started playing with Django, I love it! I am still working my way around with the Django ORM though...
At the moment I have a model Shift with a m2m relationship with users:
class Shift(models.Model):
users = models.ManyToManyField(User)
I want to define a view that checks if a M2M relationship exists, if it does, it removes this relationship. This is where I am stuck: I am able to lookup if a relationship exists, but I am not able to remove it. What is wrong with my code?
def remove_if_exists(request, shift_id, username):
shift = get_object_or_404(Shift, pk=shift_id)
if shift.users.filter(username=username).exists()
shift.users.remove(username)
The trouble with your code is that the relationship is not with a username, but with a User object. So your call to remove should have a User object as its argument. You need to actually get the relevant user from the db first, then call remove with that object.
However, there is a shortcut: remove does not raise an error if the object is not in the related set, so you can skip the exists call. That gives just:
user = User.objects.get(username=username)
shift = get_object_or_404(Shift, pk=shift_id)
shift.users.remove(user)
Some stupid syntax mistake of my own, should be:
shift.users.remove(User.objects.get(username=username))
I am writing a script and want to fake a User with an id (PK) of 2
var = Table(FKToUser=2)
var.save()
the problem is I'm getting :
"Table.FKToUser" must be a "User" instance
I've verified that the auth_user has a record with id=2
How can I fake this 2 value for testing purposes?
Thank you!
Assuming that Table is your model and FKToUser is a foreign key, there are two ways. The first is to set the FKToUser_id attribute to 2 and save the model. The other is to fetch the user and set the FKToUser attribute to the right user model instance.
This is also basically how a foreign key works. The actual column in the database is the FKToUser_id column, and it's a simple Integer foreign key to an id in another column. Django magic makes it possible to automatically retrieve the right instance by accessing FKToUser, and to set the right value by assigning a model instance to FKToUser.
u = UserDetails.objects.create(first_name='jake',last_name='sullivan')
u.save()
UserDetails.objects.create() and u.save() both perform the same save() function. What is the difference? Is there any extra check or benefit in using create() vs save()?
Similar questions:
What's the best way to create a model object in Django?
Django: Difference between save() and create() from transaction perspective
Django Model() vs Model.objects.create()
The Django documentation says it is the same. It is just more convenient to make it on one line. You could make a save() on one line too, but it would be more verbose and less readable -- it is clear you are creating a new object with the create() method.
create(**kwargs)
A convenience method for creating an object and saving it all in one
step. Thus:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
and:
p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)
are equivalent.
The force_insert parameter is documented elsewhere, but all it means
is that a new object will always be created. Normally you won’t need
to worry about this. However, if your model contains a manual primary
key value that you set and if that value already exists in the
database, a call to create() will fail with an IntegrityError since
primary keys must be unique. Be prepared to handle the exception if
you are using manual primary keys.
Similar question:
Django Model() vs Model.objects.create()
The difference between Model() vs Model.objects.create() are summarized as below.
.save() perform internally as either INSERT or UPDATE object to db, while .objects.create() perform only INSERT object to db.
Model.save() perform ....
UPDATE → If the object’s primary key attribute is set to a value that evaluates to True
INSERT →
If the object’s primary key attribute is not set or if the UPDATE didn’t update anything (e.g. if primary key is set to a value that doesn’t exist in the database).
If primary key attribute is set to a value then Model.save() perform UPDATE but Model.objects.create raise IntegrityError.
eg.
models.py
class Subject(models.Model):
subject_id = models.PositiveIntegerField(primary_key=True, db_column='subject_id')
name = models.CharField(max_length=255)
max_marks = models.PositiveIntegerField()
1) Insert/Update to db with Model.save()
physics = Subject(subject_id=1, name='Physics', max_marks=100)
physics.save()
math = Subject(subject_id=1, name='Math', max_marks=50) # Case of update
math.save()
Output:
Subject.objects.all().values()
<QuerySet [{'subject_id': 1, 'name': 'Math', 'max_marks': 50}]>
2) Insert to db with Model.objects.create()
Subject.objects.create(subject_id=1, name='Chemistry', max_marks=100)
IntegrityError: UNIQUE constraint failed: m****t.subject_id
Explanation: Above math.save() is case of update since subject_id is primary key and subject_id=1 exists django internally perform UPDATE, name Physics to Math and max_marks from 100 to 50 for this, but objects.create() raise IntegrityError
Model.objects.create() not equivalent to Model.save() however same can be achieved with force_insert=True parameter on save method i.e Model.save(force_insert=True).
Model.save() return None where Model.objects.create() return model instance i.e. package_name.models.Model
Conclusion: Model.objects.create() internally do model initialization and perform save with force_insert=True.
source-code block of Model.objects.create()
def create(self, **kwargs):
"""
Create a new object with the given kwargs, saving it to the database
and returning the created object.
"""
obj = self.model(**kwargs)
self._for_write = True
obj.save(force_insert=True, using=self.db)
return obj
The following links can be followed for more details:
https://docs.djangoproject.com/en/stable/ref/models/querysets/#create
https://github.com/django/django/blob/2d8dcba03aae200aaa103ec1e69f0a0038ec2f85/django/db/models/query.py#L440
Note: Above answer is from question.
I'm dynamically storing information in the database depending on the request:
// table, id and column are provided by the request
table_obj = getattr(models, table)
record = table_obj.objects.get(pk=id)
setattr(record, column, request.POST['value'])
The problem is that request.POST['value'] sometimes contains a foreign record's primary key (i.e. an integer) whereas Django expects the column's value to be an object of type ForeignModel:
Cannot assign "u'122'": "ModelA.b" must be a "ModelB" instance.
Now, is there an elegant way to dynamically check whether b is a column containing foreign keys and what model these keys are linked to? (So that I can load the foreign record by it's primary key and assign it to ModelA?) Or doesn't Django provide information like this to the programmer so I really have to get my hands dirty and use isinstance() on the foreign-key column?
You can use get_field_by_name on the models _meta object:
from django.db.models import ForeignKey
def get_fk_model(model, fieldname):
"""Returns None if not foreignkey, otherswise the relevant model"""
field_object, model, direct, m2m = model._meta.get_field_by_name(fieldname)
if not m2m and direct and isinstance(field_object, ForeignKey):
return field_object.rel.to
return None
Assuming you had a model class MyModel you would use this thus:
fk_model = get_fk_model(MyModel, 'fieldname')
Simple one liner to find all the relations to other models that exist in a model:
In [8]: relations = [f for f in Model._meta.get_fields() if (f.many_to_one or f.one_to_one) and f.auto_created]
Above will give a list of all the models with their relations.
Example:
In [9]: relations
Out[9]:
[<ManyToOneRel: app1.model1>,
<ManyToOneRel: app2.model1>,
<OneToOneRel: app1.model2>,
<OneToOneRel: app3.model5>,
<OneToOneRel: app5.model1>]
I encountered the same use case, and the accepted answer did not work for me directly. I am using Django 1.2 if it's relevant. Instead, I used the get_field_by_name method as follows.
def get_foreign_keys(self):
foreign_keys = []
for field in self._meta.fields:
if isinstance(self._meta.get_field_by_name(field.name)[0], models.ForeignKey):
foreign_keys.append(field.name)
if not foreign_keys:
return None
return foreign_keys
This is a method define inside a class. For my case, what I needed are the names of the ForeignKey fields. Cheers!
Explore the "ModelChoiceField" fields. Can they solve your problem putting foreign keys into forms for you; rather than doing that yourself.
http://docs.djangoproject.com/en/1.1/ref/forms/fields/#fields-which-handle-relationships
record = forms.ModelChoiceField(queryset=table_obj.objects.all())