I'm trying to make a registration form for a extension of django's user model. It has a two relationships, one to User and Address. The form needs to have all the fields from User, UserDetails and Address. But i'm struggling to get the correct view and form. Just having a ModelForm for UserDetails combined with FormView doesn't add the fields for User and Address.
class User(AbstractBaseUser, PermissionMixin):
email = models.EmailField(unique=True)
class UserDetails(model.Model):
date_of_birth = models.DateField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
address = models.OneToOneField(Address, on_delete=models.CASCADE)
class Address(model.Model):
field = models.CharField(max_length=100)
field2 = models.CharField(max_length=100)
The form and view look like this:
class UserRegistrationForm(ModelForm):
class Meta:
model = Orchestra
fields = '__all__'
class UserRegistrationView(FormView):
form_class = UserRegistrationForm
template_name = 'users/register.html'
<form action="" method="post">
{% csrf_token %}
{{ form.as_table }}
<input type="submit" value="submit">
</form>
You missed the unicode or str method declaration in model classes. You should always declare it.
Remember that str is for python 3.x, and unicode for python 2.x.
Here is an example for class Address and python 2:
def __unicode__(self):
return '%s %s' % (self.field1, self.field2)
I had to create different forms for each model. Then combine all the instances created from the forms. See this answer for more details
Related
I need two of the three form fields to be filled in automatically before submitting to the database. Slug is supposed to be filled based on test_name, and user have to be filled based on data about the current user.
Now I can submit the form, but the database entry will not be created.
models.py
class Test(models.Model):
test_name = models.CharField(max_length=100, db_index=True, verbose_name='Test name')
slug = models.SlugField(max_length=100, unique=True, verbose_name='URL')
author = models.ForeignKey(User, db_column="user", on_delete=models.PROTECT)
forms.py
class AddTestForm(forms.ModelForm):
class Meta:
model = Test
fields = ['test_name', 'slug', 'author']
views.py
def ask_test_name(request):
form = AddTestForm(request.POST)
if form.is_valid():
test = form.save(False)
test.slug = slugify(test.test_name)
test.author = request.user
test.save()
return render(request, 'app/ask_test_name.html', {'form': form})
ask_test_name.html
<form action="{% url 'ask_test_name' %}" method="post">
{% csrf_token %}
<p><input type="text" name="test_name" required></p>
<p><input type="hidden" name="slug"></p>
<p><input type="hidden" name="author"></p>
<p><button type="submit">Create</button></p>
</form>
Updated
It seems to me the problem is that the html does not see what model I want to use, but I don't know how to solve it here, I need two fields to be hidden
Remove slug and author from the fields in forms.py and don't include them in your HTML form. That should do the trick. You're only hitting the DB after already assigning values to slug and author, so that shouldn't throw an error.
I have two object models, NewsObject and StockObject. The stock object is a foreign key in the news object.
class stockObject(models.Model):
stock_name = CharField(max_length=100, blank=True, null=True)
stock_tag = CharField(max_length=100, blank=True, null=True)
def __str__(self):
return self.stock_name
class newsObject(models.Model):
title = CharField(max_length=100, blank=True, null=True)
body = TextField(blank=True, null=True)
stock = ForeignKey(stockObject, on_delete=models.SET_NULL, blank=True, null=True)
I have used autocomplete_fields property in the ModelAdmin class as I want a searchable dropdown for stocks in news. I have also added search_fields in the stocks ModelAdmin as mentioned in the documentation.
This is what my admin.py looks like:
class stockAdmin(admin.ModelAdmin):
list_display = ['stock_name', 'stock_tag']
search_fields = ['stock_name']
class newsAdmin(admin.ModelAdmin):
list_display = ['title', 'body', 'stock']
search_fields = ['title', 'body', 'stock']
autocomplete_fields = ['stock']
Now, the issue is that I get a searchable dropdown on the Django Admin site for this field, but it is only a dropdown (not searchable) on the actual template screen. I have a basic view which calls the template, like so:
Views.py
def createNews(request):
form = NewsForm()
if request.method == 'POST':
form = NewsForm(request.POST)
if form.is_valid():
form.save()
return redirect('/backoffice/')
context = {'form' : form}
return render(request, 'NewsForm.html', context)
And NewsForm.html is:
{% extends "base.html" %}
{% load static %}
{% block content %}
<form action="" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" name="Submit">
</form>
{% endblock %}
I've been wondering what might be the cause of this behavior. Tried multiple things but none of them work. What might I be missing here?
Django Admin site image
Django Template Image
I think you have written all your models in camelCase so first changed them to PascalCase.
Second, you have missed models in all your models:
Write them like this add models before every datatype like:
from django.db import models
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
Not only datatype of fields.
I am new to django but really want to learn how to use this framework.
What want to do :
I have a form, that allows the user to create a new client for example.
So in this form I have 3 fields :
Name
Description
Skills
The 'Skills' field is currently a text area, where the user would copy and paste a list already existing in another document(excel). Therefore, each element is separated by a splitline.
What I would like to do is :
create in the database the client entered by the user
In the database, link the description entered by the user to the client
In the database, link each skill entered by the user to the name so that I can work on them independantly of each other in further functions/apps. I don't want all of the skills to be linked to the client as one big bloc.
So I read the documentation and thought about using a ForeignKey. The thing is I was unable to get an input text area when using a ForeignKey. Everytime I used it I got an empty 'select list' like this ...
Empty list field
And even though I would be able to get that, I still don't know how to treat each element separatly of the others..
This is the code I have now :
model.py
class Post(models.Model):
name = models.CharField(max_length=100, null=True)
description = models.TextField(null=True)
skills = models.TextField(null=True)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
views.py
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['name', 'description', 'skills']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
post_form.html
{% extends "taskflow/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Client</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Save</button>
</div>
</form>
</div>
{% endblock content %}
As an example of what I tried to implement using a Foreign Key :
models.py
class Skills(models.Model):
element = models.TextField(null=True)
class Post(models.Model):
name = models.CharField(max_length=100, null=True)
description = models.TextField(null=True)
skills = models.ForeignKey(Skills, on_delete=models.CASCADE)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
views.py
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['name', 'description', 'skills']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
If in views.py, instead of calling 'skills' I call 'element', I get an error saying 'element' is undefined.
I thought that using a ForeignKey would include the 'element' field contained in Skills in the 'skills' field contained in Post. So from what I understand it is not the case.
What am I doing wrong?
Any information and tips would be welcome.
Thanks a lot.
Displaying foreign key field
If you want to display skills.element in your view then you don't have to call skills.element in fields just define __str__() method in your Skills model.
class Skills(models.Model):
element = models.TextField(null=True)
def __str__(self):
return self.element
p.s. Regarding the relation between Post and Skill, I think it might be Many to Many because one Post can have many Skills and one Skill can belong to many Posts but your current model doesn't allow that (Any Post can have only one Skill while one Skill belong to many Post).
You can find out more about how to implement many to many relationship in Django at https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/
** I CHANGED SKILLS TO ADDRESS **
I thought about this :
Get a TextField instead of ForeignKey
the user enters his list like this for example :
TextField
Then in Views.py I try to parse it, by creating a new field and use splitlines() like this:
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['name', 'description', 'address']
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.address_list = self.object.address.splitlines()
form.instance.author = self.request.user
self.object.save()
return super().form_valid(form)
Here I think i need to do something like
for element in self.object.address_list:
#create object here
But I don't really know how to do it and most of the time I get
Post object has no attribute object
And also, in my template if I use for example :
<p class="article-content">{{ post.address_list }}</p>
I get ['123456', '123457', '123458']
And if I use :
{{ post.address_list.1 }}
I'll get the first str character which is '
So the general idea would be to get from this form this output in the db :
db
as I want to create an instance of each address in the db, linked to the client.
Thanks for your very appreciated help !
I am new to django and building an user (named "Developer") settings update page. I used model form and passed the settings instance via views.py hoping them to show up in the rendered template for users (named "Developer") to edit. But the instance value is not populated into the template in form.as_p.
I have tested the {{project_form.instance.pk}} is passing the correct project instance, so I am expecting the project name to show up as default value in the form for user input project name, but it is showing blank.
models.py (simplified)
class Project(models.Model):
project_name = models.TextField(unique=True)
class Developer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE, default=Project.get_default_project)
institution = models.ForeignKey(Institution, on_delete=models.CASCADE, null=True, blank=True)
forms.py
class ProjectForm(ModelForm):
class Meta:
model = Project
fields = ['project_name']
views.py
def developerSettingsUpdate(request):
from .forms import ProjectForm
developer = request.user.developer
project = developer.project
if request.method == 'POST':
project_form = ProjectForm(request.POST, instance=project)
if project_form.is_valid():
project_form.save()
else:
project_form = ProjectForm(instance=project)
return render(request,
'decg/developer_settings.html',
{
'project_instance': project,
'project_form': project_form,
})
developer_settings.html
<div>
<h5>Expecting this field to show instance: {{ project_form.instance.project_name }}</h5>
</div>
<form method="post">
{% csrf_token %}
{{ project_form.as_p }}
<button class="button" type="submit">Update</button>
</form>
But it is showing blank: see Screenshot of rendered developer_settings.html:
see Screenshot of rendered developer_settings.html
The problem lies in this code:
developer = request.user.developer
project = developer.project
Those variables must point to an actual model instance in order to populate the form like you did in project_form = ProjectForm(instance=project) . It should be something like this:
developer = Developer.objects.filter(user=request.user.developer)
project = Project.objects.filter(project_name=request.user.developer)
I have the following model in my Django project:
from django.contrib.auth.models import User
class Project(models.Model):
project_title = models.CharField(max_length=200)
project_description = models.CharField(max_length=200, default="")
created_date = models.DateTimeField('date created')
owner = models.ForeignKey(User)
def __str__(self):
return self.project_title
This view uses the Project model as follows:
class ProjectView(generic.edit.UpdateView):
model = Project
fields = ['project_title','project_description']
template_name = 'steps/project.html'
success_url = reverse_lazy('steps:index')
My question is how can I bring the User's fields into my ProjectView so I can then use them in templates? In particular, I would like to display the logged-in user's name and email.
user information placed on request, not on views. So you can write in template {{user.username}}, or {{user.email}}. and you'll get it. Of course if user.is_authenticated
in your template write:
{% if request.user.is_authenticated %}
{{ request.user.username }}
{{ request.user.email }}
{% endif %}