Adding a model object to a parent table - django

I am creating a form where a someone enters a network, location, and administrators of the network. This is my model --
class Administrator(models.Model):
email = models.EmailField()
name = models.CharField(max_length=100, blank=True)
class Network(models.Model):
name = models.CharField(max_length=50)
location = models.CharField(max_length=50)
administrators = models.ManyToManyField(Administrator, blank=True)
How could I create a form such that when the site admin adds an administrator to a network, it will immediately create that entry in the Administrator class and then link up to that in the administrators column?

For custom processing of your form objects use form.save(commit=False):
This save() method accepts an optional
commit keyword argument, which accepts
either True or False. If you call
save() with commit=False, then it will
return an object that hasn't yet been
saved to the database. In this case,
it's up to you to call save() on the
resulting model instance. This is
useful if you want to do custom
processing on the object before saving
it, or if you want to use one of the
specialized model saving options.
from: https://docs.djangoproject.com/en/1.0/topics/forms/modelforms/#the-save-method
So if you have a NetworkForm you could use commit=False and then check if your administrator already exists or if he needs to be created. get_or_create is really handy for this.
Then you could set administrator on your form to the newly created or fetched administrator-instance and save the form (using form.save() and form.save_m2m()).

Related

How can I make an attribute associate automatically with User? django

I'm making a simple website using django.
I've added a 'Comment' model to make a comment section on a blog post. I'd like to print out each of the 'date_added', 'text', and 'owner' attributes in html.
class User_Comment(models.Model):
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.text
I have problems with the 'owner' attribute.
owner = models.ForeignKey(User, on_delete=models.CASCADE)
if I try to make migrations with it, Django asks me to provide a default value.
It is impossible to change a nullable field 'owner' on user_comment to non-nullable
without providing a default. This is because the database needs something to populate
existing rows.
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for
this column)
2) Ignore for now. Existing rows that contain NULL values will have to be handled
manually, for example with a RunPython or RunSQL operation.
3) Quit and manually define a default value in models.py.
If I add 'blank=True', 'null=True' parameters to the onwer attribute,
the attribute works but it doesn't automatically associate with the owner when adding a comment. So I have to go to the admin to designate the comment manually to its owner.
owner = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
What'd be the best solution for this ? I'd like to print the 'owner' attribute in html automatically without having to handle it manually.. Thank you so much for your time.
It may be helpful to explain exactly what has happened here.
You have added an additional field, owner, to an existing Comment model. Because there were already some existing comments, the migration process (that updates Django's understanding of the model in the database) needs to know what to do with the existing comment records that currently have no owner.
This is a one-time process purely to handle the existing records.
However, when you create a new comment, you'll also need to handle who the owner is so the model field gets filled automatically. Let's say you have a model form that takes in user comments and your view tests if a comment is being posted:
form = CommentForm(request.POST or None)
if request.method == "POST" and form.is_valid:
#create an uncommitted version of the form to add fields to
form_uncommitted = form.save(commit=False)
#here we explicitly assign the owner field to the user that made the request
form_uncommitted.owner = request.user
#then save the form data plus our added data
form_uncommitted.save()

Django Admin - One to Many - How to make sure only one children has a boolean field selected

In django, I have the following models:
class System(models.Model):
name = models.CharField(max_length=200)
""" ... many other fields, not useful for here ..."""
# Would it make more sense to have the primary instance here ?
class Instance(models.Model):
name = models.CharField(max_length=200)
url = models.UrlField(max_length=200)
system = models.ForeignKey(System, on_delete=models.PROTECT)
is_production = models.BooleanField()
This data is managed using the admin. What I want is that when an instance of the system is marked as is_production, all other instances, for that system have their is_production field updated to False.
Also, I am interested in how to best setup the admin for this case. I, will be using inlines for the edition/creation of instances.
However, I am not sure about how to make sure each system can only have one instance in production.
Should I use a dropdown on the System to select the production instance and filter using formfield_for_foreignkey?
Use an admin action, something like: Mark as production ?
Use signals after a save ?
is there any other way I have not thought about ?
You asked multiple questions but I'll focus on what I interpreted as the main one:
What I want is that when an instance of the system is marked as is_production, all other instances, for that system have their is_production field updated to False.
How about overriding the Instance model's save method?
class Instance(models.Model):
name = models.CharField(max_length=200)
url = models.URLField(max_length=200)
system = models.ForeignKey(System, on_delete=models.PROTECT)
is_production = models.BooleanField()
def save(self, *args, **kwargs):
if self.is_production:
self.system.instance_set.exclude(id=self.id).update(is_production=False)
super().save(*args, **kwargs)
This ensures that whenever an Instance instance with is_production=True is saved, all other Instance instances that are linked to the related System object will have their is_production values updated to False.
Depending on how you go about changing the Instance instances' is_production values, this might or might not be suitable for what you want to do. See e. g. this thread discussing how using the .update() method doesn't lead to the save() method being called: Django .update doesn't call override save? (also described in the Django docs, referred to in the linked thread)

Django how to implement a one-to-many self-dependent foreign key

I am implementing a User referral system, which existing users can refer other people to register an account with the link they provided. After the new user registers, the new user will be stored to the field 'referred_who' of the existing user.
I have tried using the following method:
class CustomUser(AbstractBaseUser):
...
referred_who = models.ManyToManyField('self', blank=True, symmetrical=False)
class ReferralAward(View):
def get(self, request, *args, **kwargs):
referral_id = self.request.GET['referral_id']
current_referred = self.request.GET['referred']
// referrer
user = get_user_model().objects.filter(referral_id=referral_id)
// user being referred
referred_user = get_user_model().objects.filter(username=current_referred)
for item in user:
previous_referred = item.referred_who
previous_referred.add(referred_user[0])
user.update(referred_who=previous_referred)
And I got the following error:
Cannot update model field <django.db.models.fields.related.ManyToManyField: referred_who> (only non-relations and foreign keys permitted).
I am not sure if this method even works. I have check the Django Admin backend and I realized the 'Referred who' field actually contains all the users. It seems that it only highlightes the user being referred instead of only showing the referred users.
Also, I tried to access the 'referred_who' field in the back-end and it returns 'None'.
Is there a way to stored the users in the 'referred_who' field so that I can see all of the user being referred and access them in the back-end? For instance:
referral_id = self.request.GET['referral_id']
user = get_user_model().objects.filter(referral_id=referral_id)
print(user[0].referred_who)
Can someone show me a better way to do it? Thanks a lot!
You ask how to create a 1-Many field, but in your models you're trying to create m2m. Just change field to FK.
referred_who = models.ForeignKey('self', blank=True).
In case you need to have multiple fks to the same model, you need to specify related_name as well. You can use name of the field for it. More in docs.

Django check if object in ManyToMany field

I have quite a simple problem to solve. I have Partner model which has >= 0 Users associated with it:
class Partner(models.Model):
name = models.CharField(db_index=True, max_length=255)
slug = models.SlugField(db_index=True)
user = models.ManyToManyField(User)
Now, if I have a User object and I have a Partner object, what is the most Pythonic way of checking if the User is associated with a Partner? I basically want a statement which returns True if the User is associated to the Partner.
I have tried:
users = Partner.objects.values_list('user', flat=True).filter(slug=requested_slug)
if request.user.pk in users:
# do some private stuff
This works but I have a feeling there is a better way. Additionally, would this be easy to roll into a decorator, baring in mind I need both a named parameter (slug) and a request object (user).
if user.partner_set.filter(slug=requested_slug).exists():
# do some private stuff
If we just need to know whether a user object is associated to a partner object, we could just do the following (as in this answer):
if user in partner.user.all():
#do something

Replace Django model object with another

I'm working on an application where we have to review model changes before accepting them.
For this, when a user edits one of the company model objects in the app frontend, the form's initial data is filled with data from the original object and then stored into a new object that is flagged using the origin_company field (which is a foreign key to the previous version of the object).
So basically when someone edits a company, a new, inactive company is created.
To apply the changes, I want to copy all data from the changed company to the original company. (I'm doing this with custom django-admin actions.) The easiest way would probably be to start a transaction, delete the original company and change the primary key of the changed company to match the original company. But by doing that, the changed company is not UPDATEd, it is copied. And related database entries (FKs) are not updated either.
Is there an easy way to copy or move all data (including FK relations) from one model instance to another one? Or is my entire way of solving this problem messed up?
Here's the model definition:
class Company(models.Model):
company_name = models.CharField(max_length=150)
...
origin_company = models.ForeignKey('self', related_name=u'CompanyEdits',
null=True, blank=True, default=None)
Try the following:
# get the company instance's data as a dict
data = company_instance.__dict__.copy()
# remove the `id` and `origin_company` keys. don't need these
del data['id']
del data['origin_company_id']
# update the origin company instance
Company.objects.filter(id=company_instance.origin_company.id).update(**data)