Create a Django model with referencing Models in Manager class - python

Using Django 1.5 and Python 2.7 and these example models:
class Company(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
class Showroom(models.Model):
name = models.CharField(max_length=100)
company = models.ForeignKey(Company)
How would I go about creating a "Company" with a default "Showroom". I know I could do this in the view, eg.
company = models.Company(name=name, email=email)
company.save()
showroom = models.Showroom(name=name, company=company)
showroom.save()
and I tried using a Manager like:
class CompanyManager(models.Manager):
def create_company(self, name, email):
company = self.create(name=name, email=email)
company.save() # <-- DONT LIKE THIS LINE
user = User.objects.create_user(name, email, 'generated')
showroom = Showroom(name=name, company=company)
showroom.save()
return company
Can I use the unsaved company to create my showroom? If not, I need to save it, but this is breaking the convention that the manager returns an unsaved instance (or am I wrong?).
Can anybody recommend a strategy?
Thanks!

How would I go about creating a "Company" with a default "Showroom?
Override the save method of model Company or register a post save signal on model Company.
Can I use the unsaved company to create my showroom?
No.
Updated:
class Company(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
def save(*args, **kwargs):
super(Company, self).save(*args, **kwargs)
self.showroom__set.create(name=self.name)
Updated by Berdus:
class Company(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
def save(self, *args, **kwargs):
is_first_save = self.pk is None
super(Company, self).save(*args, **kwargs)
if is_first_save:
self.showroom_set.create(name=self.name)
Note the self argument in save and the single underscore on showroom_set.

This is the way I think of it.
setting.py
DEFAULT_SHOWROOM_NAME = 'blah'
models.py
class Company(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
def save(*args, **kwargs):
super(Company, self).save(*args, **kwargs)
if not self.showroom__set.all():
self.showroom__set.create(name=DEFAULT_SHOWROOM_NAME)

Related

Django - ModelForm - Filter by user

I need to filter in EmployeeForm just to show me options of Companies related to user is logged in. I'm using ModelForm and CreateViews
This is my code:
models.py:
class Company(models.Model):
reg_user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
cuit = models.CharField(max_length=20)
class Employee(models.Model):
company = models.ForeignKey(Empresa, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
cuil = models.CharField(max_length=20)
forms.py:
class EmployeeForm(ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
...
self.fields['name'].widget.attrs['autofocus'] = True
What is the code I need to write in the ellipses? It's currently showing me all companies even ones not owned by the user.
I use forms.Form for this instead of ModelForm, but what i do is:
class EmployeeForm(forms.Form):
companies = forms.ModelChoiceField(queryset=None)
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['companies'].queryset = Company.objects.filter(reg_user=user)
I finally could solve this by using this in views.py
def get_form(self):
form = super(EmployeeCreateView, self).get_form()
form.fields['company'].queryset = Company.objects.filter(reg_user=self.request.user)
return form
Thanks for everyone!

Django: How to save predefined values in modelForm

Good evening,
is it possible to change the ModelForm inside my forms.py, so that already known values are saved inside the database? For example:
models.py:
class Customer(models.Model):
name = models.CharField(max_length=255)
class Project(models.Model):
customer = models.ForeignKey(Customer, null=False, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
class Entry(models.Model):
user = ...request.user.id?...
customer = models.ForeignKey(Customer, null=False, on_delete=models.CASCADE)
project= models.ForeignKey(Project, null=False, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
forms.py:
class EntryForm(ModelForm):
class Meta:
model = Entry
fields = '__all__'
def __init__(self, *args, pk, **kwargs):
super().__init__(*args, **kwargs)
self.fields['project'].queryset = Project.objects.filter(customer_id=pk)
When entering the knew site, I already know about the only possible Customer (pk)! I don't want to place a choicefield inside my knew site, but the customer should be saved inside my database nonetheless! Same goes for the active user (request.user), respectively the id (request.user.id). Can this data be passed into the modelForm as well?
Did someone else also had this problem and might know the solution? What do I have to change inside my modelForm to make it work?
Thanks for all your efforts and a happy weekend to all of you!
You don't have to. You can simply exclude the customer field from the fields:
class EntryForm(ModelForm):
class Meta:
model = Entry
exclude = ['customer']
def __init__(self, *args, pk, **kwargs):
super().__init__(*args, **kwargs)
self.fields['project'].queryset = Project.objects.filter(customer_id=pk)
Then in the view where you use the EntryForm, you can thus implement this as:
def my_view(request, customer_id):
if request.method == 'POST':
form = EntryForm(request.POST, request.FILES, pk=customer_id)
if form.is_valid():
form.instance.customer_id = customer_id
form.save()
return redirect('name-of-some-view')
else:
form = EntryForm(pk=customer_id)
return render(request, 'name_of_template.html', {'form': form})
You thus can "inject" data, by setting it at form.instance.

Django: Get all the parent data based on a field in both parent and foreign key model

I have these two models:
class Post(models.Model):
user = models.TextField()
name = models.TextField(max_length=1024)
created = models.DateTimeField(False)
class Meta:
ordering = ['-created']
def save(self, *args, **kwargs):
if not self.id:
self.created = timezone.now()
return super(Post, self).save(*args, **kwargs)
and
class PostShared(models.Model):
post = models.ForeignKey(Post, related_name='postshared', on_delete=models.CASCADE)
is_accepted = models.BooleanField(default=False)
shared_to = models.TextField(max_length=50)
shared_by = models.TextField(max_length=50)
A post can be shared by a user to any number of users. Now given a user's name, I would like to get the Post details of all the Posts that a given user might have created or Posts that were shared to him/her.
I tried
Post.objects.filter(postshared__isnull=False,postshared__shared_to='user1',user='user1')
But I am only getting the Posts that have been shared to the user and not the Posts created by the user.

How to create a UserProfile field which is alias for a User field?

I want access User model's first_name, last_name and email fields from UserProfile as if they were UserProfile's own fields.
class Person(models.Model):
user = models.OneToOneField(User)
name = #ModelField which refers to user.first_name
surname = #ModelField which refers to user.last_name
email = #ModelField which refers to user.email
birth_date = models.DateField(null=True, blank=True)
#and other fields
I could use independent name, surname, email, fields but it would have caused data duplication with User fields.
upd
I want name, surname and email to be of some Field type (as birth_date) and modification of these fields to equal modification of corresponding User fields (property behavior shown below). I need this because I want these three fields to be edible in admin interface or to be prcocessed equally with "native" fields in ModelForm for example.
upd solution. Not very fancy, but here how it worked for me:
class Person(models.Model):
user = models.OneToOneField(User)
#and also some char, text fields
#property
def name(self):
return self.user.first_name
#name.setter
def name(self, value):
self.user.first_name = value
#and by analogy surname and email properties
class PersonForm(ModelForm):
class Meta:
model = Person
exclude = ('user',)
name = forms.CharField(max_length=100, required=False)
surname = forms.CharField(max_length=100, required=False)
email = forms.EmailField(required=False)
#no make fields filled with User data on form load
def __init__(self, *args, **kwargs):
if 'instance' in kwargs:
instance = kwargs['instance']
initial = kwargs.get('initial', {})
initial['name'] = instance.name
initial['surname'] = instance.surname
initial['email'] = instance.email
kwargs['initial'] = initial
super(PersonForm, self).__init__(*args, **kwargs)
# to save form data to User model when commit
def save(self, commit=True):
instance = super(PersonForm, self).save(commit)
user = instance.user
user.first_name = self.cleaned_data['name']
user.last_name = self.cleaned_data['surname']
user.email = self.cleaned_data['email']
user.save()
return instance
class PersonAdmin(admin.ModelAdmin):
fields = ['name', 'surname', 'email', 'and_others']
form = PersonForm
admin.site.register(Person, PersonAdmin)
If want you want is to access user.first_name, user.last_name, etc... directly as attributes of Person, you can add a name, surname, etc... properties to Person model, instead of fields:
class Person(models.Model):
user = models.OneToOneField(User)
birth_date = models.DateField(null=True, blank=True)
#and other fields
#property
def name(self):
return self.user.first_name
#property
def surname(self):
return self.user.last_name
....
class Person(models.Model):
user = models.OneToOneField(User)
#property
def name(self):
return self.user.first_name
#property
def surname(self):
return self.user.last_name

Django call a funtion in model save method and call another function to fill value

I have a model in Django
class File(models.Model):
NORMAL = 'normal'
AD = 'ad'
FILE_TYPE_CHOICES = (
(NORMAL, 'Normal'),
(AD, 'Ad'),
)
file_name = models.CharField(max_length=50)
file_type = models.CharField(max_length=10, default=NORMAL,
choices=FILE_TYPE_CHOICES)
file_path = models.FileField('file', upload_to='documents/%Y/')
duration = models.IntegerField()
#prompt_id = models.CharField(max_length=50)
def __unicode__(self):
return self.file_name
def save(self, *args, **kwargs):
self.prompt_id = IvrUploadAudioFile(self.file_path)
super(File, self).save(*args, **kwargs)
i have a column prompt_id in file table, but I don't want to show prompt_id field in add/edit.
i Want to insert prompt_id value, which a function IvrUploadAudioFile will return behind the scene. so i am overriding save method here.
so where to write IvrUploadAudioFile function.
how to write this situation
Django models are just normal Python classes, and you can add as many helper methods as you want to the class:
class File(models.Model):
# -- normal stuff
prompt_id = models.CharField(max_length=50, editable=False)
def ivr_upload_audio_file(self):
# do something with self.file_path
return something
def save(self, *args, **kwargs):
self.prompt_id = self.ivr_upload_audio_file()
super(File, self).save(*args, **kwargs)
As for your other question, about not showing the field - you can add editable=False to hide the field in the admin and any ModelForms - however, if you just want to hide it in the admin, but show it in other forms - you can customize your admin to not show that field:
#admin.register(File)
class FileAdmin(admin.ModelAdmin):
fields = ('file_name', 'file_path', 'file_type', 'duration',)
You can write it anywhere as long as it can be imported into your project.
from <insert_path_here> import IvrUploadAudioFile # Function written somewhere else. You need to insert the correct path here
from django.db import models
class File(models.Model):
NORMAL = 'normal'
AD = 'ad'
FILE_TYPE_CHOICES = (
(NORMAL, 'Normal'),
(AD, 'Ad'),
)
file_name = models.CharField(max_length=50)
file_type = models.CharField(max_length=10, default=NORMAL,
choices=FILE_TYPE_CHOICES)
file_path = models.FileField('file', upload_to='documents/%Y/')
duration = models.IntegerField()
#prompt_id = models.CharField(max_length=50, editable = False)
def __unicode__(self):
return self.file_name
def save(self, *args, **kwargs):
self.prompt_id = IvrUploadAudioFile(self.file_path)
super(File, self).save(*args, **kwargs)
To make sure that the prompt_id field is not editable in the admin view, set the editable = False attribute when defining the prompt_id field in the model.
If you're talking about wanting to hide the field in Django admin, you need to set it as editable=False: https://docs.djangoproject.com/en/1.7/ref/models/fields/#editable
class File(models.Model):
. . .
prompt_id = models.CharField(max_length=50, editable=False)
I'm not sure what you intend to do by passing self.file path to your IvrUploadAudioFile class, but the code, as written, will not return the primary key of that object.

Categories

Resources