I have this model in Django, where a person has the same information from the user provided by Django plus a little bit more information. When I create a new person it requires to create a new user also, that's fine. But when I delete a person the user still remains on my database. What am I missing here ? I would like to delete the user too.
class Person(models.Model):
user = OneToOneField(User)
gender = CharField(max_length=1, choices=GenderChoices, blank=True, null=True)
birth_date = DateField(blank=True, null=True)
def __unicode__(self):
return self.user.username
Try to override the delete method on the model (code not tested):
class Person(models.Model):
user = OneToOneField(User)
gender = CharField(max_length=1, choices=GenderChoices, blank=True, null=True)
birth_date = DateField(blank=True, null=True)
def __unicode__(self):
return self.user.username
def delete():
theuser = User.objects.get(id=user)
theuser.delete()
I have found some relevant documentation about CASCADE usage in Django here.
Related
I'm working on Property Management django app where my base model is Tenant with all basic info like name, surname, email etc. Willing tenants will be able to create user account so they can log in and book Gym/Cinema, but not all Tenants will need to have user account. My problem is:
How can I create new user accounts based on existing Tenant objects? Obviously user will have Tenant ForeignKey but how can I extract Tenant.name, Tenant.surname etc to more than 1 field in my user model?
ForeignKey only gives me reference to object but can I somehow access certain fields of that object during creation of new user so I make sure that Tenant.email is the same as user.email?
Edit
tenancy = (('Tenant', 'Tenant'),('Owner', 'Owner'), ('Other', 'Other'))
class Tenant(models.Model):
name = models.CharField(max_length=15, null=True, blank=False)
surname = models.CharField(max_length=30, null=True, blank=False)
email = models.EmailField(max_length=50, unique=True)
phone_number = models.CharField(max_length=20, null=True, blank=True, unique=True)
flat = models.ForeignKey(Flat, on_delete=models.PROTECT)
status = models.CharField(max_length=10, choices=tenancy, null=True, blank=False)
stay_length = models.CharField(max_length=20, null=True, blank=False)
pet_licence = models.CharField(max_length=20, null=True, blank=False)
additional_notes= models.TextField(max_length=300, blank=True)
date_added = models.DateField(auto_now_add=True, null=True)
moved_out = models.BooleanField(default=False)
date_moved_out= models.DateField(auto_now_add=False, null=True)
class Meta:
unique_together = ('name', 'surname',)
def __str__(self):
return f'{self.name} {self.surname}'
Now I'd like to create user account model where name, surname, email, phone_number and flat will be ForeignKeys of Tenant model. Is it even possible to have 4 ForeignKeys from 1 object populating new model?
I've tried playing around with ForeignKey.limit_choices_to, ForeignKey.related_name, ForeignKey.to_field (this was close but field related to has to be unique which doesn't work for my case) but everything gives errors. I just want to find out if it's even possible that more than 1 ForeignKey of 1 object can be directed to multiple different fields of new model object.
I would approach it in a way that the foreign key is in Tenant, instead of User, and define it as a nullable one-to-one. This way you keep your User model free of foreign keys:
class Tenant(models.Model):
user = models.OneToOneField(
User,
related_name='tenant',
on_delete=models.CASCADE,
null=True,
blank=True,
default=None,
)
Then to create the related user, you can add a method in your Tenant model like so:
class Tenant(models.Model):
...
def create_user(self):
if not self.user:
user = User.objects.create(
first_name=self.name,
last_name=self.surname,
...
)
self.user = user
self.save()
Have a look at the example from the docs here.
You can use to_field to create fkeys to non-pk fields of another model, however, those fields need to have a unique constraint (i.e. unique=True) - which seems unlikely for name/surname.
It sounds like you want a transparent access from the User model to the Tenant models fields, and that is not possible.
You can create a fkey from User to Tenant:
class User(models.Model):
tenant = models.OneToOneField(Tenant, null=True, blank=True, related_name='user')
...
and then access the fields with
user = User.objects.get(...)
user.tenant.surname
to keep the fields in sync you can override the save() method:
class Tenant(...)
...
def save(self, *args, **kwargs):
if self.user:
self.user.last_name = self.surname
...
self.user.save()
super().save(*args, **kwargs)
aside: null=True indicates that the database should allow null in the field, blank=True says that the field can be empty in the admin interface. You should probably have null=True, blank=True in most cases.
I have 4 models: Products (the list of products: freezers, microwaves, tvs and pcs), ProductType (entertainment and home appliances), Credit (a credit is registered on each purchase) and PurchaseReason (the reason why the customer has bought the product).
The PurchaseReason depend on the productType, so the purchaseReason has a foreignKey field productType.
In addition, each credit has a product as foreignKey and a purchaseReason as foreignKey.
Also, I have the ProductReason field as a choice field in the credit model, and I want the options to be set dynamically based on the product field of the credit model.
I'm creating an API so I think this cant be handle with modelForms, but i'm not sure. The hard work would be with the serializers (DRF) and with the django-admin (specially this one because in my product the django admin plays an important role)
What would be the best approach to manage my models in Django?
Here are my models. In credit I'm not sure how to implemente the purchase reason:
class Credit(models.Model):
client = models.ForeignKey('clients.Client', on_delete=models.SET_NULL)
name = models.CharField(max_length=30, null=False, blank=True)
product = models.ForeignKey('product',on_delete=models.SET_NULL)
reason_purchase = models.ChoiceField(????)
class PurchaseReason(models.Model):
product_type = models.ForeignKey(product_type, on_delete=models.CASCADE)
reason = models.CharField(max_length=30, null=False, blank=True)
class ProductType(models.Model):
name = models.CharField(max_length=30, null=False, blank=False)
class Product(models.Model):
model = models.CharField(max_length=30, default=None, null=True)
product_type = models.ForeignKey(product_type, on_delete=models.CASCADE)
When we use the foreign key, we need to mention the model name of that particular model so that we can integrate that particular model in that model as a reference entity. Have a look at this example.
from django.db import models
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
def __str__(self):
return self.headline
class Meta:
ordering = ['headline']
you've not mentioned the model name properly. it should be Product in place of 'product' in the Credit class, product field.
use this reference https://docs.djangoproject.com/en/3.2/topics/db/examples/many_to_one/
i think you should be able to use the Foreignkey field properly after this. Although, if you can't, you can share the actual objective. i will help you to write the correct model.
Best wishes :)
I have a problem, I am doing project in Django for my University, and I don't know how can I change value of cell in Database using views.py. My application is an application to do exams online and problem is that many users need to use it at the same time, so I need to do relations in database, like every question has an answer and that answer is provided by one user. And there is problem, I don't know how can I change this dynamically in Views.py.
This is my code from Views.py:
if form.is_valid():
if username == Users.objects.latest('name'):
Choice.objects.username = Users.objects.get('name')
And my models.py:
class Answers(models.Model):
question = models.ForeignKey(Questions, on_delete=models.CASCADE)
text = models.TextField()
def __str__(self):
return self.text
class Users(models.Model):
name = models.CharField(max_length=30)
pass = models.CharField(max_length=30)
def __str__(self):
return self.name
class Choice(models.Model):
username = models.ForeignKey(Users, null=True, on_delete=models.CASCADE)
question = models.ForeignKey(Questions, null=True, on_delete=models.CASCADE)
answer = models.CharField(null=True,max_length=50)
class Questions(models.Model):
text = models.CharField(max_length=150)
madeBy = models.ForeignKey(User, null=True, blank=False, default='kacper', on_delete=models.CASCADE)
def __str__(self):
return self.text
Also if you have any other idea how could I improve this would be great, it's first time that I'm doing something in DJango.
If I understand your question correctly you want to update("how can I change value of cell ...") an specific object. To do this you can use following command :
YourModel.objects.filter(pk=yourobject_pk).update(username=Users.objects.get('name'))
Have this in mind, first you have to filter the object you want to update(I suggest doing this by id) and then update the field(cell) you want.
I'm currently working on a site with Django on Python 3. The site allows users to follow projects that they like, and they can follow as many as you want, as long as the thot projects exist. Here are my models of the site.
This is my Team model, which is the model for all the projects you can follow
class Team(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='team')
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
title = models.CharField(max_length=255)
description = models.TextField()
image = models.ImageField(upload_to='images/team_images', blank=True)
roster = models.TextField(blank=True, default='')
current_raise = models.IntegerField(blank=True, default=0)
# current_backers = models.IntegerField(blank=True, default=0)
time_left = models.DateTimeField(blank=True, default=timezone.now)
raising_minimum = models.PositiveIntegerField(blank=False)
raising_maximum = models.PositiveIntegerField(blank=False)
duration = models.DateTimeField(blank=False)
def __str__(self):
return self.title
This is the user profile mode, I have a Many-to-Many field in this model.
class UserProfile(models.Model):
user = models.OneToOneField('accounts.User')
following = models.ManyToManyField(Team, related_name='user_following', blank=True)
def __str__(self):
return self.user.first_name
def save(self, *args, **kwargs):
if self.pk:
for team in self.following:
team.save()
super(UserProfile, self).save(*args, **kwargs)
The problem is, when I check the database, all the teams I've created for testing are in the field following even though the user hasn't requested to follow them, yet.
All the teams I have created showed up under 'following' in admin page.
enter image description here
Options displayed in the m2m multiple choice field of admin site are just options you can choose from. It is expected behavior of Django admin. To choose some options you can just click on the item or if you want to choose multiple click with CTRL pressed.
In Django I'm trying to write a ModelForm for a ContactForm and when I try to load the page containing the form it says that it doesn't exist. Then when I try to render the other form I had previously written it says that
Caught AttributeError while rendering: 'CashtextsForm' object has no attribute 'subject'
'Subject' is a field in the form that I was trying to render in ContactForm. So is there some certain order I have to list them in models.py? Here's that code:
# Create your models here.
from django.db import models
from django.forms import ModelForm
class Cashtexts(models.Model):
cashTexts = models.CharField(max_length=100, blank=True) #change me to a website filter
superPoints = models.CharField(max_length=100, blank=True)#chance to "superPoints _Username"
varolo = models.CharField(max_length=100, blank=True)
swagbucks = models.CharField(max_length=100, blank=True)
neobux = models.CharField(max_length=100, blank=True)
topline = models.CharField(max_length=100, blank=True)
Paidviewpoint = models.CharField(max_length=100, blank=True)
cashcrate = models.CharField(max_length=100, blank=True)
def __unicode__(self):
return self.cashcode
class Contact(models.Model):
sender = models.EmailField()
subject = models.CharField(max_length=25)
message = models.TextField()
class CashtextsForm(ModelForm):
class Meta:
model = Cashtexts
def __unicode__(self):
return self.subject
class ContactForm(ModelForm):
class Meta:
model = Contact
I previously had them arranged as Model-Modelform, Model-Modelform but hereit shows them as the way I now currently have them.
Also Is there any advantages to write just forms? Right now I'm more comfortable writing model forms over forms(I dont imagine they are much differnt) but if I only wrote model forms would I be missing out on features? So is there anything I missed on how t write multiple forms in models.py or did I have them written worng? or can i not create them via the command syncdb?
The __unicode__(self) method should be part of your Contact class
class Contact(models.Model):
sender = models.EmailField()
subject = models.CharField(max_length=25)
message = models.TextField()
def __unicode__(self):
return self.subject
It doens't make sense inside CashtextsForm as that does not "know" a subject attribute.
Yes, your form really does not have subject, just remove __unicode__ definition and everything will be ok.
This is because of declarative style of django code. If you want to inspect your objects use pdb module and dir builtin.
You will use ModelForm subclasses almost every time, but sometimes you will need a form which can not be built from model. In this case django will help you to describe such form and to use form clean and field validation.
the subject field is defined in the model and not in the modelform, since a modelform can be initialized without a model instance it is not safe to do something like this:
def __unicode__(self):
return self.instance.subject
What you can do (but I do not really see the point of doing this):
def __unicode__(self):
if getattr(self, 'instance') is not None:
return self.instance.subject
return super(CashtextsForm, self).__unicode__()