Django create instance of model from another models save method - django

I have an Article model which has a OnetoOne relationship with a Catalog Model. Is it possible to create an instance of Catalog from within the save method of the Article. I'd like to attach an Article with a Catalog of the same name, it would be easiest to create these at the same time.
Here is my Catalog class:
class Catalog(models.Model):
name = models.CharField(max_length=100)
price = models.IntegerField
def __unicode__(self):
return self.name
Article Class:
class Article(models.Model):
catalog = models.OneToOneField(Catalog, related_name='article_products', blank=True, null=True)
title = models.CharField(max_length=200)
abstract = models.TextField(max_length=1000, blank=True)
full_text = models.TextField(blank=True)
proquest_link = models.CharField(max_length=200, blank=True, null=True)
ebsco_link = models.CharField(max_length=200, blank=True, null=True)
def __unicode__(self):
return unicode(self.title)
def save(self, *args, **kwargs):
self.full_text = self.title
super(Article, self).save(*args, **kwargs)
I'd like to some logic similar to this within the save method: I'm not sure if it's possible though
cat = Catalog.create(title = self.title)
cat.save()

You could instead use post_save signal for creating catalog objects at the time of creation of article objects. This would ensure creation of the catalog objects, without having to include non-relevant code in the article models' save method.
from django.db.models.signals import post_save
# method for updating
def create_catalog(sender, instance, created, **kwargs):
if instance and created:
#create article object, and associate
post_save.connect(create_catalog, sender=Article)

Related

Populate model instance with another model data during instance creation

I have creating an app as my learning project in Django.
There are 3 model classes:
# MOC class
class Moc(models.Model):
name = models.CharField(max_length=128, blank=True, null=True)
my other fields...
def __str__(self):
return str(self.id)
def save(self, *args, **kwargs):
created = not self.pk
super().save(*args, **kwargs)
if created:
CheckList.objects.create(moc=self)
# Pre Implement class
class CheckList(models.Model):
moc = models.OneToOneField(Moc, related_name='checklist', on_delete=models.CASCADE, default='1')
name = models.CharField(max_length=128, blank=True, null=True)
def __str__(self):
return str(self.id)
def save(self, *args, **kwargs):
created = not self.pk
super().save(*args, **kwargs)
if created:
CheckListItem.objects.create(checklist=self)
# Pre Implement Items class
class CheckListItem(models.Model):
checklist = models.ForeignKey(CheckList, related_name='checklistitems', on_delete=models.CASCADE, default='1')
action_item = models.TextField(max_length=128, blank=True, null=True)
actionee_name = models.ForeignKey(User, related_name='actionee_ready_pre_implements', on_delete=models.CASCADE, default='1')
action_due = models.DateField(blank=True, null=True)
def __str__(self):
return str(self.id)
I am creating Moc instance and on post save signal creating my CheckList class instance and consequently my CheckListItem class instances.
However, imaging that my CheckList once created always should have 10 CheckListItem objects as a pre populated list (like an initial data). I could not figure-out if this is something doable (at least how I am trying to achieve it as per my model relationships).
I do not want to hard code thus items in my HTML, I want to control add/delete of thus CheckListItems for related Moc/CheckList instances as relevant.
Any thoughts please?
I solved this by using InlineFormSets as it is responsible for FK relationships.

Django: Is it Possible to create a model like Profile Model, to create an instance at the time of registration automatically

I have a custom user model and has created a profile model from it as well. so when user sign up a profile instance is created in the profile model as well. Now I have another similar model which is the address model. I tried configuring it in the same way but the address instance isn't getting created. Is it possible to do that? This is just for an understanding, whether similar model like profile can be created.
this is my model.
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
summary = models.TextField(max_length=250, blank=True, null=True)
birth_date = models.DateField(null=True,blank=True, auto_now_add=False, auto_now=False)
country = CountryField(blank_label='(select country)')
profile_pic = models.ImageField(upload_to='pimage/', default='pimage/default.png')
def __str__(self):
return f'{self.user.username} Profile'
class Address(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True)
address = models.CharField(max_length=200, null=True)
city = models.CharField(max_length=200, null=True)
state = models.CharField(max_length=200, null=True)
zipcode = models.CharField(max_length=200, null=True)
mobile = models.CharField(max_length=12, null=True)
def __str__(self):
return f'{self.user.username} Address'
views
#login_required
def address_add(request):
if request.POST:
a_form = AddressForm(request.POST, instance=request.user.address)
if a_form.is_valid():
a_form.save()
messages.success(request, f'Address Saved')
return redirect('user_address')
else:
a_form = AddressForm(instance=request.user.address)
context = {'a_form':a_form,}
return render(request, 'áccounts/user_address.html', context)
You can override save() method of User model to create an Address instance automatically:
from django.db import models
class User(models.Model):
# Your user model fields
def save(self, *args, **kwargs):
if self._state.adding:
# Create your Address instance here
pass
super(User, self).save(*args, **kwargs)
If you want to know how you can extend the Django user model here is a link that can help you.
Even though you can define some signal to create your Address instance after an User instance has been created.
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Address(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
#receiver(post_save, sender=User)
def create_user_address(sender, instance, created, **kwargs):
if created:
Address.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_address(sender, instance, **kwargs):
instance.address.save()

Django inline formset with manytomany fields

Ive spent a fair bit of time searching on this subject without finding some real up to date answers. I'm trying to create a form that creates a db entry. The basic idea is this:
Many events can have many people
So, the struggle here is that the user needs to create an event where the user can select all the people that attend. Each person that attends though, has certain things that also needs to be tracked per event. See the model below:
models.py
from django.db import models
from django.contrib.auth.models import User[]
class PersonRole(models.Model):
role = models.CharField(max_length=20, choices=ROLE_CHOICES, unique=True)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return self.role
class PersonClass(models.Model):
name = models.CharField(max_length=100, choices=CLASS_CHOICES, unique=True)
color = models.CharField(max_length=6, choices=COLOR_CHOICES, unique=True)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(max_length=100, unique=True)
personclass = models.ForeignKey(PersonClass, on_delete=models.CASCADE, blank=True, null=True)
personrole = models.ForeignKey(PersonRole, on_delete=models.CASCADE, blank=True, null=True)
value = models.IntegerField(default=0)
reliability = models.IntegerField(default=0)
last_item = models.DateField(auto_now=False, blank=True, null=True)
last_event_attended = models.DateField(auto_now=False, blank=True, null=True)
last_manager_attended = models.DateField(auto_now=False, blank=True, null=True)
item_received = models.BooleanField(default=False)
note = models.TextField(null=True, blank=True)
core_attendee = models.BooleanField(default=False)
enabled = models.BooleanField(default=True)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return self.name
class Location(models.Model):
name = models.CharField(max_length=100, unique=True)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return self.name
class Boss(models.Model):
name = models.CharField(max_length=100, unique=True)
location = models.ForeignKey(Location, on_delete=models.CASCADE)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return self.name
class Raid(models.Model):
date = models.DateTimeField(auto_now_add=True)
boss = models.ForeignKey(Boss, on_delete=models.CASCADE, null=True, blank=True)
success = models.BooleanField()
attendees = models.ManyToManyField(Person)
created_by = models.ForeignKey(User,
related_name="raids", blank=True, null=True,
on_delete=models.SET_NULL)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return str(self.date)
I've started down the path of just trying to use the generic in-built create\update\delete views and ran into this:
ValueError: 'roster.Person' has no ForeignKey to 'roster.Raid'.
forms.py
class RaidGenericCreateModelForm(forms.ModelForm):
class Meta:
model = Person
exclude = ()
RaidPersonFormSet = inlineformset_factory(Raid, Person, fields=['name', 'personclass', 'personrole', 'item_received'], extra=1, can_delete=False)
views.py
class RaidCreate(CreateView):
model = Raid
template_name = 'roster/raid_create.html'
form_class = RaidGenericCreateModelForm
success_url = None
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
person_form = RaidPersonFormSet
return self.render_to_response(
self.get_context_data(form=form,
person_form=person_form
)
)
There are 9-year old posts that say you cannot use inlineformset_factory with many to many fields. So my question here is, what are my options? What is the best way to go about simply creating an Event (referred to as Raid in the model) and at the same time selecting the people from the roster (referred to as Person in the model) and changing the options those people have associated to them for that event?
As an example of what I am trying to accomplish here:
Event 1
-Person A (selected, item_received=True)
-Person B (selected, item_received=False)
-Person C (selected, item_received=False)
-Person D (not selected, item_received=False)
Event 2
-Person A (selected, item_received=False)
-Person B (not selected, item_received=False)
-Person C (selected, item_received=True)
-Person D (selected, item_received=False)
Where the list of persons is showing all persons and some of the persons fields from the Person model.
The alternate thing you can do is use DjangoRestFramework for this purpose.
Using rest you can first send persons data to frontend then in frontend you can create Event and add person details for each event,and in last post all that data using javascript.Try it,it will surely work.

Set ManyToMany field in model save method

I have a problem, I try to save the model and only adds to 'members' the users that belong to the company set in the field 'company'.
This is my code:
class GroupFolderAccess(BaseModel):
name = models.CharField(max_length=128)
members = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='belongs')
company = models.ForeignKey('Company', on_delete=models.CASCADE, related_name='folders')
folder = models.ForeignKey('recourse.Folder', null=True, blank=True, on_delete=models.CASCADE, related_name='get_group')
def save(self, *args, **kwargs):
for member in self.members.all():
if self.company != member.company:
print(member)
self.members.remove(member)
return super(GroupFolderAccess, self).save(*args, **kwargs)
When I save, it displays users correctly, but does not remove them from the relationship.

Cannot assign must be a instance Django

I have an order form which returns this statement of submit:
Cannot assign "<Annual: 2012>": "Order.annuals" must be a "Catalog" instance.
I'm fairly new to Django. I understand it needs an instance instead of the string it has been passed. How would I go about resolving that?
Here is my view:
class OrderListCreateView(
views.LoginRequiredMixin,
views.SetHeadlineMixin,
generic.CreateView
):
form_class = forms.OrderListForm
headline = 'Create'
model = Order
template_name = 'ordercreate.html'
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super(OrderListCreateView, self).form_valid(form)
Here is my form:
class OrderListForm(forms.ModelForm):
annuals = forms.ModelChoiceField(queryset=Annual.objects.all())
issues = forms.ModelChoiceField(queryset=Issue.objects.all())
articles = forms.ModelChoiceField(queryset=Article.objects.all())
class Meta:
fields = (
'annuals',
'issues',
'articles',)
model = models.Order
def __init__(self, *args, **kwargs):
super(OrderListForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
'annuals',
'issues',
'articles',
ButtonHolder(
Submit('create', 'Create')
)
)
Here is my model:
class Catalog(models.Model):
products = models.CharField(max_length=200)
def __unicode__(self):
return self.products
class Issue(models.Model):
catalog = models.ForeignKey(Catalog, related_name='issue_products')
Volume = models.DecimalField(max_digits=3, decimal_places=1)
def __unicode__(self):
return unicode(self.Volume)
class Annual(models.Model):
catalog = models.ForeignKey(Catalog, related_name='annual_products')
year_id = models.IntegerField(max_length=4)
start_date = models.CharField(max_length=6)
end_date = models.CharField(max_length=6)
def __unicode__(self):
return unicode(self.year_id)
#def __unicode__(self):
# return unicode(self.id)
class Annual_Issue(models.Model):
annual_id = models.ForeignKey(Annual, related_name='annual_ids')
issue_id = models.ForeignKey(Issue, related_name='issues')
def __unicode__(self):
return self.annual_id
class Article(models.Model):
catalog = models.ForeignKey(Catalog, related_name='article_products')
title = models.CharField(max_length=200)
abstract = models.TextField(max_length=1000, blank=True)
full_text = models.TextField(blank=True)
proquest_link = models.CharField(max_length=200, blank=True, null=True)
ebsco_link = models.CharField(max_length=200, blank=True, null=True)
def __unicode__(self):
return self.title
class Order(models.Model):
user = models.ForeignKey(User, related_name='who_ordered')
annuals = models.ForeignKey(Catalog, related_name='annuals_ordered', blank=True, null=True)
issues = models.ForeignKey(Catalog, related_name='issues_ordered', blank=True, null=True)
articles = models.ForeignKey(Catalog, related_name='items_ordered', blank=True, null=True)
In your Order model, you have defined a ForeignKey relationship for several other models (Annual, Issue, and Article), but each of these relationships points to the Catalog model. When you attempt to save the Order instance created by your form, it has received objects of these types (Annual, Issue, and Article), but it cannot store a foreign-key reference to these objects in the fields defined on the Order model. This is due to the foreign-key fields on the Order demanding that they can only contain a reference to Catalog objects.
If, for each of these foreign-key relationships, you wish to store one of these various kinds of objects, you will need to alter your Order model definition to expect references to objects of those models rather than Catalog objects.
In brief, I would suggest that the Order model be modified to include the following relationships. This will allow an order object to store a single reference to an object of each other kind (Annual, Issue, and Article).
annuals = models.ForeignKey(Annual, related_name='annuals_ordered', blank=True, null=True)
issues = models.ForeignKey(Issue, related_name='issues_ordered', blank=True, null=True)
articles = models.ForeignKey(Article, related_name='items_ordered', blank=True, null=True)
For more information about ForeignKey relationships in Django, see the reference here.