Django - ModelForm - Filter by user - python

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!

Related

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.

Django-filters how to pass current user from view inside FilterSet?

I have a filter where I need to access the request.user. However, Django-filter does not pass it. I was able to figure out possible FilterSet configuration.
But how to pass current user from view inside FilterSet?
filters.py
class TransationsListFilter(django_filters.FilterSet):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(TransationsListFilter, self).__init__(*args, **kwargs)
transaction_date = DateFromToRangeFilter(widget=RangeWidget(attrs {'placeholder': 'DD/MM/YYYY'}))
class Meta:
model = Transations
fields = ['transaction_date']
#property
def qs(self):
return super(TransationsListFilter, self).filter(user=user)
views.py
class TransactionsList(PagedFilteredTableView):
model = Transations
table_class = TransactionsTable
filter_class = TransationsListFilter
formhelper_class = TransationsFormHelper
models.py
class Transations(models.Model):
transaction_date = models.DateField(default=datetime.now, blank=True)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
default = 0
)
I solved my problem with django-crum plugin.
Here is my final code(other files are the same):
filters.py
import django_filters
from django_filters import DateFromToRangeFilter
from django_filters.widgets import RangeWidget
from .models import Transations,Account
from crum import get_current_user
class TransationsListFilter(django_filters.FilterSet):
transaction_date = DateFromToRangeFilter(widget=RangeWidget(attrs={'placeholder': 'DD/MM/YYYY'}))
class Meta:
model = Transations
fields = ['transaction_date']
#property
def qs(self):
parent = super(TransationsListFilter, self).qs
return parent.filter(user=get_current_user())

Create a Django model with referencing Models in Manager class

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)

Django: Slugify Post Data

I'm trying to save some form data inputted by the user. I would like to slugify the "name" which was entered by the user, but dont want the slug field to show on the template that the user sees. I tried to do it manually with the sell function that you see below, but cant quite get it to work. I want to eventually save the slugified name into the Item model I have listed below. I'm sure there's a much smarter/simpler way than the sell function I'm currently using :P. Thanks in advance!
class Item(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=75)
slug = models.SlugField(max_length=50, unique=True)
is_active = models.BooleanField(default=True)
image = models.CharField(max_length=50)
price = models.DecimalField(max_digits=9, decimal_places=2)
quantity = models.IntegerField(default=1)
description = models.TextField()
created = models.DateTimeField(auto_now_add=True)
shipping_price = models.DecimalField(decimal_places=2, max_digits=6)
categories = models.ManyToManyField(Category)
class AddItem(forms.ModelForm):
class Meta:
model = Item
exclude = ('user','slug','is_active',)
def sell(request):
if request.method == "POST":
form = AddItem(request.POST)
item = form.save(commit=False)
item.user = request.user
item.is_active = True
item.slug = slugify(form.name) **#not sure what this line should be?**
item.save()
if form.is_valid():
form.save()
return HttpResponseRedirect('thanks.html')
else:
url = urlresolvers.reverse('register')
return HttpResponseRedirect(url)
You can exclude slug from user form.
And slugify in pre_save signal.
from django.dispatch import receiver
from django.db.models.signals import pre_save
#receiver(pre_save, sender=Item)
def iter_pre_save_handler(sender, instance, **kwargs):
if not instance.pk:
instance.slug = slugify(instance.name)
According to the docs, you can exclude a field from being rendered in a model form like this:
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
fields = ('name', 'title')
or
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
exclude = ('birth_date',)
or by setting editable=False on the Field instance in your model.
Once you have done this, you can override the save method of the model, as the comments in the OP have suggested:
# shamelessly copied from http://stackoverflow.com/questions/837828/how-do-i-create-a-slug-in-django/837835#837835
from django.template.defaultfilters import slugify
class test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField()
def save(self, *args, **kwargs):
self.s = slugify(self.q)
super(test, self).save(*args, **kwargs)

Categories

Resources