I'm new to django, working on a website requiring multiple types of registrations, needing two seperate forms, and basing myself off of cookiecutter-django's template, which utilizes allauth.
I'd still like to retain allauth's email confirmation and password verification.
I've searched around for a solution, coming down to this:
Multiple signup, registration forms using django-allauth
It doesn't resolve my problem. The sign up form stays the same in my case. Perhaps only because I'm trying to use the model in the form?
Here's my attempt at a customized log on form:
in cookiecutter's app users/
In models.py:
class Proveedor(models.Model):
TIENE_EMPRESA = (
('S','Si'),
('M','No'),
)
SEXO = (
('F','Femenina'),
('M','Masculino'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
oficios = []
ubicacion = models.CharField(_('Ubicacion'),max_length=255)
ubicaciones_servicios = []
tiene_empresa = models.CharField(_('Tienes Empresa?'),max_length=1, choices=TIENE_EMPRESA)
foto = models.ImageField(_('Foto'),upload_to=None, blank=False)
email = models.EmailField(_('Email'),max_length=254)
fecha_nacimiento = models.DateField(_('Fecha de nacimiento'), default=datetime.datetime.now(), blank=True)
sexo = models.CharField(_('Sexo'),max_length=1, choices=SEXO)
telefono = models.CharField(_('Numero de Telefono'),max_length=10)
fotos_trabajos_realizados = []
descripcion_forma_trabajar = models.TextField(_('Descripcion de Forma de Trabajar'),null=True, blank=True)
class Meta:
db_table = 'proveedor'
permissions = (
("menu_proveedor", "Puede ver menu de proveedor"),
)
In formularios.py (forms):
class FormularioProveedor(SignupForm):
class Meta:
model = Proveedor
fields = '__all__'
def save(self, request, user):
user = super(FormularioProveedor, self).save(request)
user.sexo = self.cleaned_data['sexo']
user.tiene_empresa = self.cleaned_data['tiene_empresa']
user.save()
In views.py:
class ProveedorRegistroView(SignupView):
template_name = 'account/form_proveedor.html'
form_class = FormularioProveedor
redirect_field_name = 'proximo'
view_name = 'registroproveedor'
success_url = None
def get_context_data(self, **kwargs):
ret = super(ProveedorRegistroView, self).get_context_data(**kwargs)
ret.update(self.kwargs)
return ret
registroproveedor = ProveedorRegistroView.as_view()
urls.py in the package directory for testing:
url(r'registroproveedor', registroproveedor, name='registroproveedor')
Finally the template itself:
{% extends "account/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{% trans "Registro de Proveedor" %}{% endblock title %}
{% block content %}
<form id="signup_form" method="post" action="{% url 'registroproveedor' %}">
{% csrf_token %}
{{ form|crispy }}
</form>
{% endblock %}
I've only had new fields show up by pointing to my form in the settings, assigning ACCOUNT_SIGNUP_FORM_CLASS ... but that's not really what I need or want. I just want multiple registration forms, still able to utilize features provided by allauth and the template provided by cookiecutter-django. Right now, basing myself off of this template, I see too many things that might be wrong and any help would be appreciated. Thanks.
When I was learning more about Django's default user registration forms I came across the site below:
https://learndjango.com/tutorials/django-custom-user-model
One key aspect of this tutorial was using the default Django class models to create new class models that are more flexible if one wanted to add new meta fields. In the cookiecutter-django template they do this as following in the .../users/forms.py file:
from django.contrib.auth import forms as admin_forms
class UserCreationForm(admin_forms.UserCreationForm):
...
As can be seen above the import the default Django class model and use it to create a class model that inherits all the methods and properties of the default class. If I understand your question correctly you want to use cookiecutter-django default templates and reuse them multiple times to create different sorts of registration forms.
I might be wrong, but the following might work:
from (DIRECTORY, example: ...user/forms.py) import (COOKIECUTTER-DJANGO REGISTRATION CLASS, example UserCreationForm
class NewUserRegistrationForm(UserCreationForm):
Class Meta(UserCreationForm.Meta):
model = User # cookiecutter-django template already includes this
fields = ('username', 'email', 'street', 'house_number', 'postal_code', 'province', 'state', 'country',)
# add additional fields in here
Please note, the cookiecutter-django UserCreationForm is already a copy of the default Django UserCreationForm and thus the code I showed in the example is a copy of the cookiecutter-django UserCreationForm. Thus the example is no different from the default Django UserCreationForm with the exception of the included Meta fields variable and the utilization of allauth.
I'm still a novice myself so I could be wrong, but this might solve your problem.
Related
First section of code works fine; it is for reference.
#Basic Model
class MyTestModel(models.Model):
record = models.CharField(max_length=100)
def __str__(self):
return self.record
#Specify verbose_name
class Meta:
verbose_name = 'UniqueNameExample'
verbose_name_plural = verbose_name
#Generic ListView.
class MyTemplateView(ListView):
model = MyTestModel
template_name = 'base.html'
context_object_name = 'model_list'
ordering = ['record']
#Python block in HTML template. So far, so good.
{% for item in model_list %}
{{ item.record }}<br>
#{{ item }} also works
{% endfor %}
I am trying to access the Model's verbose_name ('UniqueNameExample') AND the model_list in the view. I've tried registering a filter, a tag, and simple_tag.
Something like: templatetags/verbose.py
from django import template
register = template.Library()
#register.filter (or #register.tag or #register.simple_tag)
def verbose_name(obj):
#Could be verbose_name(model) or whatever input
return obj._meta.verbose_name
And then after
{% load verbose %}
in my HTML (which also works fine), I'll try something like this:
{{ object|verbose_name }}
And I'll get the error 'str' object has no attribute '_meta'. Error is the same if using a tag:
{% verbose_name object %}
Note: tags apparently worked for earlier versions, but maybe I'm using them incorrectly? Not asking to access the Model field verbose_name for "record," btw -- that's answered adequately on SO.
The one thing I've tried that gets the answer half right is if I set the following under MyTemplateView:
queryset = model._meta.verbose_name
The problem with this is it overrides the model_list, and the only result I'm left with is 'UniqueNameExample' without being able to access the record(s) I've used in the model.
I know private=True for _meta (not sure if that's relevant or worth exploring/possibly breaking), but Django admin displays the verbose_name (if set) in the list of created models, so I don't see why I can't do the same (also had a rough time tracing back exactly how it does it in the source code). Maybe it's not a generic ListView but a MixIn? Function-based?
Large(ish) db with thousands of models, each with unique verbose_name[s]; would very much like to keep it simple.
EDIT: Found a fantastic solution from Dominique Barton # https://blog.confirm.ch/accessing-models-verbose-names-django-templates/
First, create a templatags folder at the app level and populate with an init file. Next, create a template tag file. Something like verbose.py.
from django import template
register = template.Library()
#register.simple_tag
def verbose_name(value):
#Django template filter which returns the verbose name of a model.
#Note: I set my verbose_name the same as the plural, so I only need one tag.
if hasattr(value, 'model'):
value = value.model
return value._meta.verbose_name
Next, the ListView should be modified.
from django.views.generic.list import ListView as DjangoListView
from .models import MyTestModel
class ListView(DjangoListView):
#Enhanced ListView which includes the `model` in the context data,
#so that the template has access to its model class.
#Set normally
model = MyTestModel
template_name = 'base.html'
context_object_name = 'model_list'
ordering = ['record']
def get_context_data(self):
#Adds the model to the context data.
context = super(ListView, self).get_context_data()
context['model'] = self.model
return context
Don't forget to add the path to urls.py:
path('your_extension/', views.ListView.as_view(), name='base')
Lastly, load the tag and iterate through the "records" normally:
{% load verbose %}
<h1> {% verbose_name model%} </h1>
<ul style='list-style:none'>
{% for item in model_list %}
<li>{{ item }}}</a></li>
{% endfor %}
</ul>
Pagination also works as advertised.
I am trying to create a Django web app that accepts text in a form/textbox, processes it and redirects to a webpage showing the processed text . I have written a half-functioning app and find de-bugging quite challenging because I don't understand most of what I've done. I'm hoping you will help me understand a few concepts, Linking to resources, also appreciated.
Consider this simple model:
class ThanksModel(models.Model):
thanks_text = models.CharField(max_length=200)
Is the only way to set the text of thanks_text through the manage.py shell? This feels like a pain if I just have one piece of text that I want to display. If I want to display a webpage that just says 'hi', do I still need to create a model?
Consider the view and template below:
views.py
class TestView(generic.FormView):
template_name = 'vader/test.html'
form_class = TestForm
success_url = '/thanks/'
test.html
<form action = "{% url 'vader:thanks'%}" method="post">
{% csrf_token %}
{{ form }}
<input type = "submit" value = "Submit">
</form>
I need to create another model, view and html template and update urls.py for '/thanks/' in order for the success_url to redirect correctly? (That's what I've done.) Do I need to use reverse() or reverse_lazy() the success_url in this situation?
Models are used when you are dealing with Objects and Data and DataBases that can contain a lot of information.
For Example A Person would be a model. their attributes would be age, name, nationality etc.
models.py
class Person(models.Model):
Name = models.CharField(max_length=50)
age = models.IntegerField()
nationality = models.CharField(max_length=50)
Thi deals with multiple bits of information for one object. (the object being the person)
A Thank you message would not need this? so scrap the model for the thank you message. just have views where you create the view using a templates and setting the view to a url.
views.py
class TestView(generic.FormView):
template_name = 'vader/test.html' # self explantory
form_class = TestForm # grabs the test form object
success_url = reverse_lazy('vader:thanks') # this makes sure you can use the name of the url instead of the path
def ThanksView(request): # its simple so you don't even need a class base view. a function view will do just fine.
return render(request,"thanks.html")
test.html
<form action = "{% url 'vader:thanks'%}" method="post">
{% csrf_token %}
{{ form }}
<input type = "submit" value = "Submit">
</form>
thanks.html
<h1>Thank you for Submitting</h1>
<h2> Come Again </h2>
url.py
from django.urls import path
from djangoapp5 import views
urlpatterns = [
path('', TestView.as_view(), name='test_form'),
path('thanks/', views.ThanksView, name='vader:thanks'),
]
I haven't tested this but hopefully it helps and guide you in the right direction
I am getting this error while I was trying to make two forms (with two models) and process that in the view. My SongForm is not saving its data in database while AlbumForm is perfectly saving its data.
views.py-
def formm(request):
if request.method=='POST':
songform = SongForm(request.POST)
albumform=AlbumForm(request.POST)
if songform.is_valid() and albumform.is_valid():
songform.save()
albumform=albumform.save(commit=False)
albumform.date=timezone.now()
albumform.save()
return redirect("result")
forms.py-
from django import forms
from . models import Album,Song
class SongForm(forms.ModelForm):
class Meta:
model=Song
fields=('song_title','genre')
class AlbumForm(forms.ModelForm):
class Meta:
model=Album
fields=('album_title',)
models.py-
from __future__ import unicode_literals
from django.db import models
class Album(models.Model):
album_title=models.CharField(max_length=50)
date=models.DateTimeField(blank=True,null=True)
def __str__(self):
return self.album_title
class Song(models.Model):
song_title=models.CharField(max_length=50)
genre=models.CharField(max_length=50)
album=models.ForeignKey(Album,on_delete=models.CASCADE)
def __str__(self):
return self.song_title
formmpage.html-
{% extends "musicapp/basepage.html" %}
{% block content %}
<form method="POST" class="post-form">
{% csrf_token %}
{{ songform.as_p }}
{{ albumform.as_p }}
<button type="submit" class="btn btn-info">POST</button>
</form>
{% endblock %}
Do correct me, where actually I am doing wrong. I guess it is in my views.py.
It looks as if you should be setting the song's album before you save it.
if songform.is_valid() and albumform.is_valid():
album = albumform.save(commit=False)
album.date = timezone.now()
album.save()
song = songform.save(commit=False)
song.album = album
song.save()
return redirect("result")
Note that I changed the code to album=albumform.save(commit=False), since the save() method returns a model instance, not a form instance.
Ok,I was certain this was the issue but i've used the code you've given me and I get an integrity error due to the fact that your Song model has a Foreign Key to the Album model without null=True it won't allow you to create a new Song without an Album model.
There has to be some kind of business logic to know whether a song belongs to an album. In my opinon you should have these 2 in separate endpoints.
When creating a Song you should be able to select from a list albums that it may or may not belong to based on a genre.
Anyways, you can get past this with just adding null=True on the the album Foreign key attribute in your Song model.
I read the following thread: Django Multiple Choice Field / Checkbox Select Multiple
But I somehow miss something important as I can't succeed in displaying the checkboxes in my template. However, the name of the field does appear in the template but that's all, after the field name, it's all white and blank.
Curiously, in the thread I read, the author didn't wrote a list of tuple. That's why I think the problem could lie in the models.py
Here is my models.py
from django.db import models
from user.models import User
class RegionChoices(models.Model):
REGION_CHOICES = (
('London', 'Londres'),
('Paris', 'Paris'),
('Berlin', 'Berlin'),
)
region = models.CharField(max_length=30, choices=REGION_CHOICES)
def __str__(self):
return self.region
class Offer(models.Model):
publisher = models.ForeignKey(User)
content = models.TextField()
region_choices = models.ManyToManyField(RegionChoices)
def __str__(self):
return self.publisher.username
forms.py
from django import forms
from django.contrib import admin
from django.conf import settings
from offers.models import Offer, RegionChoices
class SendOfferForm(forms.ModelForm):
region_choices = forms.ModelMultipleChoiceField(queryset=RegionChoices.objects.all(), widget=forms.CheckboxSelectMultiple)
class Meta:
model = Offer
exclude = ['publisher']
offer.html
<form action="{% url "send_offer" %}" method='POST' class='sendofferform'>
{{ form.errors }}
{{ form.non_field_errors }}
{% csrf_token %}
{{ offerform.as_p }}
</form>
views.py
if offerform.is_valid():
sent = True
offer = offerform.save(commit=False)
offer.publisher = User.objects.get(id=logged_user.id)
offer.save()
offerform.save_m2m()
else:
print(offerform.errors)
From your code sounds like you want to limit the choices of region your project can have. I think you should create an admin for RegionChoices first. In there you could create entrances of RegionChoices you like. Follow the django docs if you are not sure how to create an admin interface for a model https://docs.djangoproject.com/en/1.8/ref/contrib/admin/
ps: You might want to do unique=True on region field in RegionChoices. Otherwise you might create duplicate entries of the same region by accident.
Okay, I realize I had to load data in the model RegionChoices.
I loaded the data in the admin part of my website and now, it works perfectly.
I'm in the learning stages of django. I just dived into a project to learn the framework and am having a series of questions throughout the process.
I basically want to have individual pages for users who create a task list and have them post tasks to their own page.
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserProfile(models.Model):
# This line is required. Links UserProfile to a User model instance.
user = models.OneToOneField(User)
# The additional attributes we wish to include.
website = models.URLField(blank = True)
# Override the __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.user.username
class TaskItem(models.Model):
taskn = models.CharField(max_length = 400)
usern = models.ForeignKey(User)
In my template, if the user has their task entered, how do I call it to render onto the page?
My View:
def profile_page(request, username):
user = User.objects.get(username=username)
taskitems = user.taskn_set.all()
return render_to_response('profile.html', {}, context)
Current issue:
'User' object has no attribute 'taskn_set'
{{ request.user.taskitem_set.all }} would give you all the related task items. Now, to display it in your template:
{% for task_item in user.taskitem_set.all %}
{{ task_item.task_n }}
{% endfor %}
would display the list of tasks.
Here is the documentation on reverse-queries on foreign key (related_name) Also, read this
you would do something like this:
{% for task in user.taskitem_set.all %}
{{ task.task_n }}
{% endfor %}
This will fetch all TaskItem instances related to your user. (notice the extra database query)
While i don't know how your view works, i will assume that you are making the right checks to make sure that every user can only see his own tasks.
One performance trick you will find most useful is to use prefetch_related('taskitem_set'), this will prefetch the TaskItem instances as long as your UserProfile instance with one query:
user = User.objects.filter(id=user_id).prefetch_related('taskitem_set')
You can tune the code to match your preferences.
Hope this helps!