how to override an attribute in the object? - python

please help solve the problem.
have an object:
class Product:
title = models.CharField(max_length=255)
active = models.BooleanField(default=False)
I create a new object:
class Book(Product):
slogan = models.CharField(max_length=255)
active = models.BooleanField(default=True) #???????
I need to override the attribute active. that is, to attribute always been active=True
at the same time I can not change the Product since I do not have access to it

You have two options. You can use save() method in your model or you can use pre_save() signal.

Unfortunately, that is not possible, see https://docs.djangoproject.com/en/dev/topics/db/models/#field-name-hiding-is-not-permitted

Related

Set ManyToManyField with particular users from another model's ManyToMany Field

I am building a simple class group app in which I am trying to add particular users from another model's ManyToFieldField to a new model's ManyToFieldField.
class ClassGroup(models.Model):
admins = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='admins')
members = models.ManyToManyField(settings.AITH_USER_MODEL)
title = models.CharField(max_length=9999, default='')
class ClassGroupInvite(models.Model):
class_group = models.ForeignKey(ClassGroup, on_delete=models.CASCADE)
invite_receiver = models.ManyToManyField(class_group.admins.all())
invite_sender = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
As you can see that I am filtering (send request only to class group admins) in ClassGroupInvite with setting ManyToManyField with ClassGroup.admins
But when I try this then it is showing
ManyToManyField(<django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x000001CE78793280>) is invalid. First parameter to ManyToManyField must be either a model, a model name, or the string 'self'
I also read the documentation about it, But I didn't find anything about defining it.
then I tried using ClassGroup.admins.all then it showed
AttributeError: 'ManyToManyDescriptor' object has no attribute 'all'
I have tried many times but it is still not working, Any help would be much Appreciated. Thank You in Advance.

django model inheritance: How does model creation work with custom manager?

Recently I've faced an issue with Django, model inheritance and how the creation of model instances works.
Suppose I have the following (basic) setup:
class InviteBaseManager(models.Manager):
def create(self):
new_code = # create some kind of unique code, not really relevant here.
return super().create(code=new_code)
class InviteBase(models.Model):
code = models.CharField(max_length=10, blank=False, null=False, unique=True)
creationDate = models.DateTimeField(default=timezone.now())
objects = InviteBaseManager()
class PartyInviteManager(models.Manager):
def create(self, name):
# method 1
newInvite = InviteBase.objects.create()
print(newInvite.code) # is definitly set, lets assume "ABCD"
# as expexted, the "InviteBase" table has one row with code "ABCD" and
# default creationDate
newPartyInvite = super().create(partyName=name, invite=newInvite)
print(newPartyInvite.invite.code) # is EMPTY, prints nothing
# In fact, when looking at the db, there is still only *one* row in the table "InviteBase",
# with an *empty* code field and a default creationDate field.
return newPartyInvite
#method 2
newPartyInvite = super().create(partyName=name)
# creates the InviteBase instance implicitly, again, newPartyInvite.invite.code is empty.
# fill newPartyInvite.invity.code manually.
return newPartyInvite
class PartyInvite(InviteBase):
#Isn't blank=False and null=False unnecessary? A child should probably not exist with no parent?
invite = models.OneToOneField(InviteBase, parent_link=True, on_delete=models.CASCADE, null=False, blank=False)
partyName = models.CharField(...)
objects = PartyInviteManager()
So the question is: How can I pass an already existing instance of the base class inside the create method of my PartyInviteManager? Even when using method 1, the existing instance that I pass along seems to be overwritten. A new one is created with the default value. Interestingly enough, this violates the constraints that code cannot be blank or NULL.
This behaviour seems a bit odd to me? Can someone point out what I am missing here?
To clarify: I know that I should usually use **kwargs in the create methods and that inheritance might not be the ideal use case here, but I'm just very curious about this behaviour.
I know that this kind of model inheritance wont even create a pk for the child model (because holding a OneToOneField to the parent class effectively acts as a pk anyway), but why would it be impossible to pass a manually created instance as parent? Am I not allowed to use inheritance for my use-case?
I think I've found the correct way of doing this:
class InviteBaseManager(models.Manager):
def create(self, **kwargs):
kwargs['code'] = #createCode
return super().create(**kwargs)
class InviteBase(models.Model):
code = models.CharField(max_length=10, blank=False, null=False, unique=True)
creationDate = models.DateTimeField(default=timezone.now())
objects = InviteBaseManager()
class PartyInviteManager(InviteBaseManager):
def create(self, name):
return = super().create(partyName=name)
class PartyInvite(InviteBase):
invite = models.OneToOneField(InviteBase, parent_link=True, on_delete=models.CASCADE, null=False, blank=False)
partyName = models.CharField(...)
objects = PartyInviteManager()
The PartyInviteManager now inherits from the InviteManager as well. When calling super.create() from the child manager, the base manager gets called, appends the code field and everything works as expected.
I also found out, that if the PartyInviteManager does not inherit from the InviteBaseManager, the create method of InviteBaseManager does not get called when creating a new PartyInvite. This seems very odd to me.
Of course, the easier way would have been to create the code as default value via a function, like that:
def createCode():
return "ABCD" # add fancy code creation magic here.
class InviteBase:
code = models.CharField(max_length=128, blank=False, null=False, default=createCode)
But if, depending on the child class, the code needs additional information (such as invited members or whatever), this approach would not work anymore.
On a side note, interestingly enough the following code snippet:
invite = PartyInviteManager.objects.create(partyName='Birthday')
print(invite.invite.code)
print(invite.code)
produces the following output:
ABCD
ABCD
In the create method of the PartyInviteManager, one can directly use code=XXXX to pass along a string for the InviteBase model, invite_code on the other hand does not work.

Naming a Django Model after the User's name it is extending

In my models I have:
class Collaborator(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
photo = models.ImageField(verbose_name= 'fotografia', upload_to='collaborators')
According to Django Docs this is the correct way to extend a user object, but I couldn't find a reference on how to name this "collaborator" after the user.
I'm referring to the Django Admin Interface where creating a Collaborator will result in a object named "Collaborator object". Is there any way for the Collaborator to appear with the user's name?
You need to define a __str__ method, like explained in Models Docs:
class Collaborator(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
photo = models.ImageField(verbose_name= 'fotografia', upload_to='collaborators')
def __str__(self):
return self.user.first_name #or whatever else you want.

how to access may-to-many relationship in django?

I have two model
class ClassProfile(models.Model):
classname = models.CharField(max_length=100, blank=True)
class UserProfile(models.Model):
user = models.OneToOneField(User)
class = models.ManyToManyField('ClassProfile')
I try to get all the famulymember like this
class = Class.objects.get(pk=1)
members = class.userprofile_set.all()
this will rasie an error
'ClassProfile' object has no attribute 'userprofile_set'
what's wrong with my code?
What makes you think django uses CamelCase anywhere? By default, the reverse accessor is lowercaseclsname_set
So class.userprofile_set.all() should do it.
Aside from the fact that it is not a good idea to name a variable class, I think you have a typo in this line:
class = Class.objects.get(pk=1)
You probably meant:
class = ClassProfile.objects.get(pk=1)

Django Many-to-Many (m2m) Relation to same model

I'd like to create a many-to-many relationship from and to a user class object.
I have something like this:
class MyUser(models.Model):
...
blocked_users = models.ManyToManyField(MyUser, blank=True, null=True)
The question is if I can use the class reference inside itself. Or do I have to use "self" insead of "MyUser" in the ManyToManyField? Or is there another (and better) way to do it?
Technically, I'm pretty sure "MyUser" or "self" will work, as long as it's a string in either case. You just can't pass MyUser, the actual class.
However, the docs always use "self". Using "self" is not only more explicit about what's actually happening, but it's impervious to class name changes. For example, if you later changed MyUser to SomethingElse, you would then need to update any reference to "MyUser" as well. The problem is that since it's a string, your IDE will not alert you to the error, so there's a greater chance of your missing it. Using "self" will work no matter what the class' name is now or in the future.
class MyUser(models.Model):
...
blocked_users = models.ManyToManyField("self", blank=True)
Don't forget use symmetrical=False, if you use .clear() or .add() method for related objects and don't wanna object on other side of relation update own data in relation field.
some_field = models.ManyToManyField('self', symmetrical=False)
I think it should be class name instead of self. because with using self like this
parent = models.ManyToManyField('self', null=True, blank=True)
when i add parent:
user1.parent.add(user2)
i have 2 record in database like this:
and with using class name liken this:
parent = models.ManyToManyField('User', null=True, blank=True)
i have one record in database like this:
note that i use uuid for pk and i use django 3.1
EDIT:
as #shinra-tensei explained as comment in this answer we have to set symmetrical to False if we use self. documented in Django Documents: ManyToManyField.symmetrical
If you use self or MyUser you will get a NameError in both cases. You should write "self" as string. See the example below:
class MyUser(models.Model):
...
blocked_users = models.ManyToManyField("self", blank=True, null=True)
And do not forget to set the symmetrical attribute to False if the relationship is not symmetrical.
For further details check: https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.ManyToManyField
don't use 'self' in ManyToManyField, it will cause you object link each other, when use django form to submit it
class Tag(models.Model):
...
subTag = models.ManyToManyField("self", blank=True)
...
aTagForm.save()
and result:
a.subTag == b
b.subTag == a

Categories