I have these models in my app models.py:
class A(models.Model):
#some details
pass
class B(models.Model):
a = models.ForeignKey(A, null=True, blank=True)
c = models.ForeignKey(C, null=True, blank=True)
class C(models.Model):
pass
def method(self):
b_list = B.objects.filter(c=self)
a_list = []
for b in b_list:
a_list.append(b.a)
return a_list
this gives me an error when i launch the webserver because in B it declares that C is not defined.
then if i put these models in order A C B django tells me that B is not defined in C's method().
How can i resolve this "not defined" issue in this situation? it seems circular!
You can always use a string in such cases:
class A(models.Model):
#some details
pass
class B(models.Model):
a = models.ForeignKey("A", null=True, blank=True) # note the quotes
c = models.ForeignKey("C", null=True, blank=True) # note the quotes
class C(models.Model):
pass
If this was a more "extreme" case and you couldn't use this trick, declaring C first, then A and B, and after that C.method (def C_method [...] C.method = C_method) would have been the way to follow.
Related
Okay so here is my models.py first:
class UserFollowing(models.Model):
user = models.ForeignKey(CustomUser, related_name="following", on_delete=models.CASCADE)
following_user = models.ForeignKey(CustomUser, related_name="followers", on_delete=models.CASCADE)
created = models.DateTimeField(default=timezone.now, db_index=True)
def __str__(self):
return f"{self.user} follows {self.following_user}"
So in this case, when I try like this:
>>> user = CustomUser.objects.get(id=1) # just a user
>>> user.following.all() # A follows B
>>> user.followers.all() # B follows A
However, I want to do it like this:
>>> user.following.all() # B (Since A is following B)
>>> user.followers.all() # B (Since B is a follower of A)
But how can I differ the __str__ outputs according to the related_name? I couldn't find any information on this so is there a way?
The __str__ method takes into account the object (self), not the origin of that object. So how you constructed that object, through a .following or .followers is irrelevant. While it might be possible by inspecting the call stack, etc. it is simply not a good idea to do this.
You however do not need this. You are only interested in the CustomUsers that are "followers" or "followees" of a CustomUser, not the UserFollowing model that presents this. Therefore it might be better to span a ManyToManyField between CustomUser and CustomUser with Follow as through=… model:
class CustomUser(models.Model):
# …
followers = models.ManyToManyField(
'self',
symmetrical=False,
through='Follow',
related_name='followees',
through_fields=('followee', 'follower')
)
class Follow(models.Model):
follower = models.ForeignKey(
CustomUser,
related_name='followings',
on_delete=models.CASCADE
)
followee = models.ForeignKey(
CustomUser,
related_name='followedby',
on_delete=models.CASCADE
)
created = models.DateTimeField(auto_now_add=True, db_index=True)
def __str__(self):
return f'{self.user} follows {self.following_user}'
Then you thus can access the CustomUsers who are following user with:
b.followers.all() # [c]
b.followees.all() # [a]
here b is thus following a, and c is following b. These are thus CustomUser objects, not Follow objects.
How do you get a field related by OneToOneField and ManyToManyField in Django?
For example,
class A(models.Model):
myfield = models.CharField()
as = models.ManyToManyField('self')
class B(models.Model):
a = models.OneToOneField(A)
If I want to get a 'myfield' and all associated 'as' using class B, given a 'myfield' equal to a string like 'example', how is it done?
Models.py
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self): # __unicode__ on Python 2
return "%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key=True,
)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
def __str__(self): # __unicode__ on Python 2
return "%s the restaurant" % self.place.name
Let create a place instance.
p1 = Place.objects.create(name='Demon Dogs', address='944 W. Fullerton')
Then create a restaurant object.
r = Restaurant.objects.create(place=p1, serves_hot_dogs=True, serves_pizza=False)
Now, to access place from Restaurant:
>>> r.place
<Place: Demon Dogs the place>
vice-versa to access Restaurant from place
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
I did not understand the many-to-many field part can you please elaborate?
First you get an instance of B say b and you can easily access myfield and as through the a attribute of b
b.a.myfield
b.a.as.all()
Furthermore, CharField requires a max_length attribute as follows:
class A(models.Model):
myfield = models.CharField(max_length=128)
as = models.ManyToManyField('self')
class B(models.Model):
a = models.OneToOneField(A)
A general point, give more descriptive names to your models and their attributes, or at the very least, add comments explaining what these models represent
Is there any way to call parent model from base model. my model.py looks like:
models.py
Class A(models.Model):
title = models.CharField(max_length=350)
description = models.TextField()
Class B(models.Model):
reftitle = models.CharField(max_length=100)
inventory = models.IntegerField()
Class C(models.Model):
a = models.ForeignKey('A')
b = models.ForeignKey('B')
notes = models.TextField()
for some reasons I can only retrieve data from Class A is there any possible way I can retrieve Class C by reference to Class A.
To get all C from given A:
a = A()
list_of_c = a.c_set.all()
and get A from given C:
c = C()
a = c.a
The reference has an own section about Many-to-one-relationships.
Essentially I have 6 object models, 3 for my regular objects and 3 for the dependencies of those objects. Individually, these objects can be dependent on one or multiple instances of each of the 3 regular objects.
My Question:
Is this best practice? I essentially want to be able to add a new dependency to a regular object when needed. For example:
a = A.objects.get(id=1)
adependency = ADependencies.objects.get(dependentTo=a)
Then, I'd have an object with all of the dependencies for a.
Alternatively, I did think of a way to merge the 3 dependency objects into one; however, I'm unsure whether it's good practice.
class Dependencies(models.Model):
id = models.CharField(max_length=16)
dependentTo = CharField(max_length=16)
a = models.ManyToManyField(A)
b = models.ManyToManyField(B)
c = models.ManyToManyField(C)
In this scenario, I don't use a ForeignKey to map the dependentTo object. Instead, I would use the object id to pull the object - allowing me to be class agnostic; however, this would require unique ids throughout the 3 regular objects.
a = A.objects.get(id=1)
adependency = ADependencies.objects.get(dependentTo=a.id)
One more idea!
Is it possibly to still use ForeignKey's, but pass in a string with the class name instead?
class Dependencies(models.Model):
id = models.CharField(max_length=16)
type = models.CharField(max_length=16)
dependentTo = ForeignKey(type)
a = models.ManyToManyField(A)
b = models.ManyToManyField(B)
c = models.ManyToManyField(C)
Object Models:
class A(models.Model):
id = models.CharField(max_length=16)
title = models.CharField(max_length=32)
summary = models.CharField(max_length=256)
class B(models.Model):
id = models.CharField(max_length=16)
title = models.CharField(max_length=32)
summary = models.CharField(max_length=256)
a = models.ForeignKey(A)
class C(models.Model):
id = models.CharField(max_length=16)
title = models.CharField(max_length=32)
summary = models.CharField(max_length=256)
b = models.ForeignKey(B)
class ADependencies(models.Model):
id = models.CharField(max_length=16)
dependentTo = models.ForeignKey(A)
a = models.ManyToManyField(A)
b = models.ManyToManyField(B)
c = models.ManyToManyField(C)
class BDependencies(models.Model):
id = models.CharField(max_length=16)
dependentTo = models.ForeignKey(B)
a = models.ManyToManyField(A)
b = models.ManyToManyField(B)
c = models.ManyToManyField(C)
class CDependencies(models.Model):
id = models.CharField(max_length=16)
dependentTo = models.ForeignKey(B)
a = models.ManyToManyField(A)
b = models.ManyToManyField(B)
c = models.ManyToManyField(C)
Thanks!
This can be done a lot simpler. Define a Dependency model instead of a Dependencies model. You will need the contenttypes django contribution:
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Dependency(models.Model):
dependent_contenttype = models.ForeignKey(ContentType)
dependent_id = models.PositiveIntegerField()
dependent = GenericForeignKey('dependent_contenttype', 'dependent_id')
prerequisite_contenttype = models.ForeignKey(ContentType)
prerequisite_id = models.PositiveIntegerField()
prerequisite = GenericForeignKey('prerequisite_contenttype',
'prerequisite_id')
Then you can make dependencies a reverse generic relation on models A, B and C if you like:
class A:
# ...
dependencies = GenericRelation(
Dependency,
content_type_field='dependent_contenttype',
object_id_field='dependent_id')
I think inheritance may simplify your data structures a lot.
Let's leave model A as-is:
class A(models.Model):
id = models.CharField(max_length=16)
title = models.CharField(max_length=32)
summary = models.CharField(max_length=256)
Your classes B and C has those fields of A plus one additional, so we may rewrite that as
class B(A):
a = models.ForeignKey(A)
class C(A):
b = models.ForeignKey(B)
Now as we have one base class, we only need one dependency class:
class ADependencies(models.Model):
id = models.CharField(max_length=16)
dependentTo = models.ForeignKey(A)
dependents = models.ManyToManyField(A)
Now you can set any of A, B and C objects to dependentTo and dependents. If you only need the main object from dependency, the object of type A will have either attribute b, attribute c or none of them. You may also query on those attributes:
ADependencies.objects.filter(dependentTo__b__isnull=False)
This structure is more scalable and more easily maintainable because if you need to add one more model, you only need to write the unique code for it and don't have to deal with dependency classes.
One more way to simplify your models is to just have one model:
class A(models.Model):
id = models.CharField(max_length=16)
title = models.CharField(max_length=32)
summary = models.CharField(max_length=256)
a = models.ForeignKey(A, null=True)
This way you only have model A and you may leave field a empty (indication that it is just a simple A instance) or set the value of a (it will mean the object of type B or C). Then your dependency class is the same as in previous example, but you don't need to deal with those backwards relations to test for true object type.
If you really need to disinguish between B and C objects you may write your A class like this:
class A(models.Model):
A = 0
B = 1
C = 2
TYPE_CHOICES = (
(A, "A"),
(B, "B"),
(C, "C")
)
id = models.CharField(max_length=16)
title = models.CharField(max_length=32)
summary = models.CharField(max_length=256)
a = models.ForeignKey(A, null=True)
obj_type = models.IntegerField(choices=TYPE_CHOICES)
This way you have just one model class and one dependency class and can tell what type the object is by checking obj_type. Also you should implement some check to prevent cases where a is not null and obj_type is A and similar.
Let me know if this solution is what you need.
edit: I completely rewrote the question as the original one didn't clearly explain my question
I want to run a function which is specific to each particular model instance.
Ideally I want something like this:
class MyModel(models.Model):
data = models.CharField(max_length=100)
perform_unique_action = models.FunctionField() #stores a function specific to this instance
x = MyModel(data='originalx', perform_unique_action=func_for_x)
x.perform_unique_action() #will do whatever is specified for instance x
y = MyModel(data='originaly', perform_unique_action=func_for_y)
y.perform_unique_action() #will do whatever is specified for instance y
However there is no datatype FunctionField. Normally this would be solvable with inheritance, and creating subclasses of MyModel, maybe like this:
class MyModel(models.Model):
data = models.CharField(max_length=100)
perform_unique_action = default_function
class MyModelX(MyModel):
perform_unique_action = function_X
class MyModelY(MyModel):
perform_unique_action = function_Y
x = MyModelX(data='originalx')
x.perform_unique_action() #will do whatever is specified for instance x
y = MyModelY(data='originaly')
y.perform_unique_action() #will do whatever is specified for instance y
Unfortunately, I don't think I can use inheritance because I am trying to access the function this way:
class MyModel(models.Model):
data = models.CharField(max_length=100)
perform_unique_action = default_function
class SecondModel(models.Model):
other_data = models.IntegerField()
mymodel = models.ForeignKey(MyModel)
secondmodel = SecondModel.objects.get(other_data=3)
secondmodel.mymodel.perform_unique_action()
The problem seems to be that I don't know what type the foreign key is going to be in SecondModel if I override the perform_unique_action in subclasses.
Can I access MyModel from SecondModel as a foreign key and still have a unique function for each instance of MyModel?
This works for me. I haven't tested it, but you should be able to create another class and override their methods and it'll work. Check the class Meta line, it'll treat it as an abstract class. Here's an example of my actual classes that I'm working on right now.
EDIT: Added VoteComment class and tested it. It works as expected!
class Vote(models.Model):
VOTE_ENUM = (
(VoteEnum.DOWN_VOTE, VoteEnum.toString(VoteEnum.DOWN_VOTE)),
(VoteEnum.NONE, VoteEnum.toString(VoteEnum.NONE)),
(VoteEnum.UP_VOTE, VoteEnum.toString(VoteEnum.UP_VOTE)),
)
question = models.ForeignKey(Question, null=False, editable=False, blank=False)
voter = models.ForeignKey(User, blank=False, null=False, editable=False)
vote_type = models.SmallIntegerField(default=0, null=False, blank=False, choices=VOTE_ENUM)
class Meta:
abstract = True
def is_upvote(self):
return self.vote_type > 0
def is_downvote(self):
return self.vote_type < 0
class VoteAnswer(Vote):
answer = models.ForeignKey(Answer, null=False, editable=False, blank=False)
class Meta:
unique_together = (("voter", "answer"),) # to prevent user from voting on the same question/answer/comment again
def __unicode__(self):
vote_type = "UP" if vote_type > 0 else ("DOWN" if vote_type < 0 else "NONE")
return u"{0}: [{1}] {2}".format(user.username, vote_type, answer.text[:32])
def is_upvote(self):
return "FOO! "+str(super(VoteAnswer, self).is_upvote())
class VoteComment(Vote):
comment = models.ForeignKey(Comment, null=False, editable=False, blank=False)
class Meta:
unique_together = (("voter", "comment"),) # to prevent user from voting on the same question/answer/comment again
def __unicode__(self):
vote_type = "UP" if vote_type > 0 else ("DOWN" if vote_type < 0 else "NONE")
return u"{0}: [{1}] {2}".format(user.username, vote_type, comment.text[:32])
def is_upvote(self):
return "BAR!"
I came up with two ways of having a specific function defined for each object. One was using marshal to create bytecode which can be stored in the database (not a good way), and the other was by storing a reference to the function to be run, as suggested by Randall. Here is my solution using a stored reference:
class MyModel(models.Model):
data = models.CharField(max_length=100)
action_module = models.CharField(max_length=100)
action_function = models.CharField(max_length=100)
class SecondModel(models.Model):
other_data = models.IntegerField()
mymodel = models.ForeignKey(MyModel)
secondmodel_obj = SecondModel.objects.get(other_data=3)
#The goal is to run a function specific to the instance
#of MyModel referred to in secondmodel_obj
module_name = secondmodel_obj.mymodel.action_module
func_name = secondmodel_obj.mymodel.action_function
module = __import__(module_name)
func = vars(module)[func_name]
func()
Thanks to everyone who replied, I couldn't have got to this answer if it weren't for your help.
You could achive some similar behavior overriding the save method. And providing special callbacks to your instances.
Something like:
def default_function(instance):
#do something with the model instance
class ParentModel(model.Model):
data = models.CharField()
callback_function = default_function
def save(self, *args, **kwargs):
if hasattr(self, 'callback_function'):
self.callback_function(self)
super(ParentModel, self).save(*args, **kwargs)
class ChildModel():
different_data = models.CharField()
callback_function = other_fun_specific_to_this_model
instance = ChildModel()
#Specific function to this particular instance
instance.callback_function = lambda inst: print inst.different_data
instance.save()
You can write endpoints on your server and limit their access to just your self. Then store in each model instance corresponding url. For example:
views.py
def funx_x(request):
pass
def func_y(request):
pass
models.py:
class MyModel(models.Model):
data = models.CharField(max_length=100)
perform_unique_action = models.URLField()
and then:
x = MyModel(data='originalx', perform_unique_action='http://localhost/funx_x')
requests.post(x.perform_unique_action)
i dont know whether i understand u correct or not. but you can check out this example here.
Example:
A string representing an attribute on the model. This behaves almost the same as the callable, but self in this context is the model instance. Here's a full model example:
class Person(models.Model):
name = models.CharField(max_length=50)
birthday = models.DateField()
def decade_born_in(self):
return self.birthday.strftime('%Y')[:3] + "0's"
decade_born_in.short_description = 'Birth decade'
class PersonAdmin(admin.ModelAdmin):
list_display = ('name', 'decade_born_in')