Edit another model after creating an instance - python

I am finding it difficult to achieve the following scenario:
In my app, a user creates a project, now to that project he can link a previous team that he created or create a new team.
A team can be part of many projects but a project is linked to only ONE team.
models.py:
class Team(models.Model):
team_name = models.CharField(max_length=100, default = '')
team_hr_admin = models.ForeignKey(MyUser, blank=True, null=True)
def __str__(self):
return self.team_name
class TeamMember(models.Model):
user = models.ForeignKey(MyUser)
team = models.ForeignKey(Team)
def __str__(self):
return self.user.first_name
class Project(models.Model):
name = models.CharField(max_length=250)
team_id = models.ForeignKey(Team, blank=True, null=True)
project_hr_admin = models.ForeignKey(MyUser, blank=True, null=True)
def get_absolute_url(self):
return reverse('website:ProjectDetails', kwargs = {'pk' : self.pk})
def __str__(self):
return self.name
views.py:
class ProjectCreate(CreateView):
model = Project
fields = ['name']
template_name = 'project_form.html'
def form_valid(self, form):
form.instance.project_hr_admin = self.request.user
return super(ProjectCreate, self).form_valid(form)
class ProjectDetailView(generic.DetailView):
model = Project
template_name = 'project_details.html'
class TeamCreate(CreateView):
model = Team
fields = ['team_name']
template_name = 'team_form.html'
def form_valid(self, form):
obj = form.save(commit=False)
obj2 = Project.team_id
obj2 = obj.team_id
obj2.save()
print("sucess")
I would like that when a user creates a team, and if the team is created it successfully. Add automatically to the Project models with the corresponding team_id.
Any help would be appreciated. Thanks in advance!

Well, you can get the project with your user id which has a team_id null.
In the form_valid method of your TeamCreate() view:
def form_valid(self, form):
valid = super(TeamCreate, self).form_valid(form)
obj = form.save()
obj2 = Project.objects.get(project_hr_admin=self.request.user, team_id=None)
obj2.team_id = obj
obj2.save()
return valid
Here you just get the Project which has your user as admin and a null team_id.
Warning though, if an admin create two projects with no team, the request Project.objects.get(...) will raise an error as it will return more than one object.
So you must be sure it will always be one project and then one team created.
Hope it helps.

Related

How display categories in forms only for user who created this?

I am creating app for control transaction (expense, income, budget). I want each user to be able to create their own spending categories and their own expenses. All expenses and categories created by a user are to be visible only to that user.
If user A creates the category "Food123" then user B cannot see it. He can create his own such category.
I've created two models - Category and Expense.
class Category(models.Model):
name = models.CharField(max_length=100)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="category")
class Expense(models.Model):
name = models.CharField(max_length=100)
amount = models.DecimalField(max_digits=8, decimal_places=2)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="expense")
I use a generic view when creating expenses and categories.
class ExpenseListView(LoginRequiredMixin, ListView):
model = Expense
context_object_name = 'expense'
template_name = 'expense/expense_list.html'
def get_queryset(self):
return self.request.user.expense.all()
class ExpenseCreateView(CreateView):
model = Expense
success_url = '/record/expense'
form_class = ExpenseForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return HttpResponseRedirect(self.get_success_url())
class CategoryCreateView(CreateView):
model = Category
success_url = '/record/expense'
form_class = CategoryForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return HttpResponseRedirect(self.get_success_url())
What is more, I've used forms.py.
class ExpenseForm(forms.ModelForm):
class Meta:
model = Expense
fields = ('name', 'amount', 'category')
class CategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = ('name',)
Unfortunetly, when user A create category "IT" it automatically goes to user B. When user B creates his expense he also sees this "IT" category that A created, not B.
How can I limit the display of categories in the form to only those created by a particular user?
The problem is because you're not filtering the model fields by your user in the ExpenseForm (like you are doing in the ExpenseListView.get_queryset).
To do it, you will need to change a bit your logic. you can try something like this:
# forms.py
class ExpenseForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
# limit the category field queryset
self.fields['category'] = forms.ModelChoiceField(
queryset=user.category.all())
)
class Meta:
model = Expense
fields = ('name', 'amount', 'category')
# views.py
class ExpenseCreateView(CreateView):
...
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
# inject the user in the form instantiation
kwargs['user'] = self.request.user
return kwargs

ValueError at /post/new/ Cannot assign "<SimpleLazyObject:<User: chetan>>": "Post.author" must be a "User" instance

I keep getting this error "ValueError at /post/new/
Cannot assign ">": "Post.author" must be a "User" instance."
class User(models.Model):
user = models.OneToOneField(User,on_delete = models.CASCADE)
def __str__(self):
return self.user.username
class Post(models.Model):
author = models.ForeignKey('User.User',related_name="posts",on_delete = models.CASCADE)
text = models.TextField()
created_at = models.DateTimeField(default = timezone.now)
updated_at = models.DateTimeField(blank = True,null =True)
def update(self):
updated_at = timezone.now()
self.save()
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
views.py
class CreatePostView(LoginRequiredMixin, CreateView):
# form_class = forms.PostForm
fields = ['text',]
model = Post
def form_valid(self, form):
self.object = form.save(commit=False)
form.instance.author = self.request.user
self.object.save()
return super().form_valid(form)
Please help!
You here made two User objects, the User object from django.contrib.auth and one from the User app. In order to retrieve the related User object from the User app, you can use self.request.user.user (given you of course constructed that related object):
class CreatePostView(LoginRequiredMixin, CreateView):
# form_class = forms.PostForm
fields = ['text',]
model = Post
def form_valid(self, form):
self.object = form.save(commit=False)
form.instance.author = self.request.user.user
self.object.save()
return super().form_valid(form)
It is however very confusing to name two models the same. It might be better to just use Profile for example. In that case it would be form.instance.author = self.request.user.profile which is also more readable.

Django Inline form validation ignored partly filled form

I have got the code from https://github.com/adandan01/mybook, the code is working fine, even when I have updated it to Django 2. It's very simple project for adding a person in a form, and his/her relatives in the inline form. Everything works but when I add a relative name and forget to add his relationship, and submitted the form, unfortunately, that record will not pass the validation but will give no error messages as well. Django will ignore the entire record. For example, the record for Hawra in the image, will not be saved and Django will remove it. For this simple App there are only two fields to be filled (name and relationship), but I'm working on app with 8 fields, and it will be difficult to lose the data. is there any way to make django do the validation in the formset/subform as long as any fields have data and will ask the user to fill all required fields?
models.py:
class Profile(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
created_date = models.DateTimeField(default=timezone.now)
def get_absolute_url(self):
return reverse('profile-update', kwargs={'pk': self.pk})
def __unicode__(self):
return "%s %s" % (self.first_name, self.last_name)
class FamilyMember(models.Model):
profile = models.ForeignKey(Profile, on_delete=models.PROTECT)
name = models.CharField(max_length=100)
relationship = models.CharField(max_length=100)
form.py
class ProfileForm(ModelForm):
class Meta:
model = Profile
exclude = ()
class FamilyMemberForm(ModelForm):
class Meta:
model = FamilyMember
exclude = ()
FamilyMemberFormSet = inlineformset_factory(Profile, FamilyMember,
form=FamilyMemberForm, extra=1)
views.py
class ProfileCreate(CreateView):
model = Profile
fields = ['first_name', 'last_name']
class ProfileFamilyMemberCreate(CreateView):
model = Profile
fields = ['first_name', 'last_name']
success_url = reverse_lazy('profile-list')
def get_context_data(self, **kwargs):
data = super(ProfileFamilyMemberCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['familymembers'] = FamilyMemberFormSet(self.request.POST)
else:
data['familymembers'] = FamilyMemberFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
familymembers = context['familymembers']
with transaction.atomic():
self.object = form.save()
if familymembers.is_valid():
familymembers.instance = self.object
familymembers.save()
return super(ProfileFamilyMemberCreate, self).form_valid(form)
I found the solution here django inline_formset - form.empty_permitted = False doesn't work
I had to add the following code before if (familymembers.is_valid():...) in the create and update class, so, now Django will show the error if I entered data in the Name field only and will tell me the Relationship field is required.
if familymembers.is_valid() == False:
return self.render_to_response(self.get_context_data(form=form,familymembers=familymembers ))

Django: How do you associate an Object_PK in the URL to the Foreign_Key relation field when creating a new object?

I am building an FAQ system. The models extend from Topic -> Section -> Article. When creating a new Article the User will select a Topic then a Section then the create Article button.
The url will look something like //mysite.org/Topic_PK/Section_PK/Article_Create
In Django it should look like this:
url(r'^ironfaq/(?P<pk>\d+)/(?P<pk>\d+)/article$', ArticleCreateView.as_view(), name=’article-create’)
What I am looking to do is to associate the Section_PK to the Article when the user submits the Article. I have the Section_PK in the URL I need help to figure out how to use it to do this.
Alternatively with this set up I can have a form rendered with a choice selection from the Section_FK in the Articles Model. If when creating the Article upon rendering the template if I could limit the Section choices by the Topic in the form.py this will also work for my needs
The url will look something like //mysite.org/Topic_PK/article/create
In Django the url should look like this:
url(r'^ironfaq/(?P<pk>\d+)/article/create$', ArticleCreateView.as_view(), name=’article-create’)
Both these methods require the Passing of the Topic or Section PK to the view or form thru the URL. If there is a better way to do this I am open to other suggestions.
In Django I have the following Models
class Topic(Audit):
name = models.CharField(max_length=255)
sort = models.SmallIntegerField()
slug = models.SlugField()
class Meta:
verbose_name_plural = "topics"
def __str__(self):
return self.name
def get_absolute_url(self):
return ('faq-topic-detail',(), {'slug': self.slug})
class Section(Audit):
name = models.CharField(max_length=255)
sort = models.SmallIntegerField()
slug = models.SlugField()
topic = models.ForeignKey(Topic,on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "sections"
def __str__(self):
return self.name
def get_absolute_url(self):
return ('faq-section-detail',(), {'topic__slug': self.topic.slug,
'slug': self.slug})
class Article(Audit):
title = models.CharField(max_length=255)
sort = models.SmallIntegerField()
slug = models.SlugField()
section = models.ForeignKey(Section,on_delete=models.CASCADE)
answer = models.TextField()
vote_up = models.IntegerField()
vote_down = models.IntegerField()
view_count = models.IntegerField(default=0)
class Meta:
verbose_name_plural = "articles"
def __str__(self):
return self.title
def total_votes(self):
return self.vote_up + self.vote_down
def percent_yes(self):
return (float(self.vote_up) / self.total_votes()) * 100
def get_absolute_url(self):
return ('faq-article-detail',(), {'topic__slug': self.section.topic.slug,
'section__slug': self.section.slug, 'slug': self.slug})
Mysite Forms
class CreateArticleForm(forms.ModelForm):
class Meta:
model = Article
widgets = {
'answer': forms.Textarea(attrs={'data-provide': 'markdown', 'data-iconlibrary': 'fa'}),
}
fields = ('title','section','answer')
Mysite Views
class TopicCreateView(CreateView):
model = Topic
fields = ['name']
template_name = "faq/form_create.html"
success_url = "/ironfaq"
def form_valid(self, form):
topic = form.save(commit=False)
activity_user = self.request.user.username
activity_date = datetime.datetime.now()
topic.save()
return super(TopicCreateView,self).form_valid(form)
class SectionCreateView(CreateView):
model = Section
fields = ['name', 'topic']
template_name = "faq/form_create.html"
def form_valid(self, form):
section = form.save(commit=False)
activity_user = self.request.user.username
activity_date = datetime.datetime.now()
section.save()
self.success_url = "/ironfaq/%s/%s" % (section.topic.slug,section.slug)
return super(SectionCreateView,self).form_valid(form)
class ArticleCreateView(CreateView):
model = Article
form_class = CreateArticleForm
template_name = "faq/form_create.html"
def form_valid(self, form):
article = form.save(commit=False)
activity_user = self.request.user.username
activity_date = datetime.datetime.now()
article.save()
self.success_url = "/ironfaq/%s/%s/%s" % (article.section.topic.slug,article.section.slug,article.slug)
return super(ArticleCreateView,self).form_valid(form)
Let's say that you have this url
url(r'^ironfaq/(?P<topic_pk>\d+)/article/create$', ArticleCreateView.as_view(), name=’article-create’)
Where topic_pk will be pk of topic you want to be associated with your Article.
Then you just need to retrieve it in view. And this is done like this
class ArticleCreateView(CreateView):
model = Article
form_class = CreateArticleForm
template_name = "faq/form_create.html"
def form_valid(self, form):
article = form.save(commit=False)
# what are this variables for?
activity_user = self.request.user.username
activity_date = datetime.datetime.now()
# here we are getting 'topic_pk' from self.kwargs
article.topic_id = self.kwargs['topic_pk']
article.save()
self.success_url = "/ironfaq/%s/%s/%s" % (article.section.topic.slug,article.section.slug,article.slug)
return super(ArticleCreateView,self).form_valid(form)
All url params are stored in self.args and self.kwargs. Our topic_pk is named parameter and thats why we can get it by doing self.kwargs['topic_pk']
But be sure to validate existence of Topic with such pk before assigning it to your Article

django class based view many to many field display selected values

I have a form created with Update View class based view. It displays every value in input type fields from database, except values of many to many field.
What should i insert into view or maybe model so user will see what options they have slected (like in built-in admin module).
This is my view:
class StudentUpdateView(LoginRequiredMixin, UpdateView):
form_class = StudentForm
model = Student
template_name = 'forms/modify.html'
def get_context_data(self, **kwargs):
context = super(StudentUpdateView, self).get_context_data(**kwargs)
context['year'] = Setting.objects.get(id=2)
return context
def form_valid(self, form):
if self.request.is_ajax():
self.object = form.save()
return HttpResponse(json.dumps("success"),
mimetype="application/json")
return super(StudentUpdateView, self).form_valid(form)
def form_invalid(self, form):
if self.request.is_ajax():
return HttpResponseBadRequest(json.dumps(form.errors),
mimetype="application/json")
return super(StudentUpdateView, self).form_invalid(form)
EDIT:
This is my model used, as Model Form
And StudentForm does not exist
class Student (models.Model):
name = models.CharField(u'Imię', max_length=40)
surname = models.CharField(max_length=80)
email = models.EmailField(blank=True)
subjects = models.ManyToManyField(Subjects, blank=True)
programs = models.ManyToManyField(Programs, editable=False)
history = models.CharField(max_length=50, editable=False)
added = models.DateTimeField(auto_now=True)
def __unicode__(self):
return u'%s %s'(self.name, self.surname)
class StudentForm(ModelForm):
class Meta:
model = Student

Categories

Resources