3

I've struggled with this problem for the last two days and could use some help. The home page for my Django 1.6 application will include two forms, one that a user can use to sign in to the site and one they can use to sign up (create a login) for the site:

# templates/home/home_page.html
<div class="sign-in-form">
    <form action="{% url 'apps.home.views.sign_in' %}" method="post">
        {% csrf_token %}

        {{ sign_in_form.as_p }}

        {% if next %}
            <input type="hidden" name="next" value="{{ next }}">
        {% else %}
            <input type="hidden" name="next" value="{% url 'view-members' %}">
        {% endif %}
        <input type="submit" value="Sign in">
    </form>
</div>

<div class="sign-up-form">
<fieldset>
    <legend>Sign up</legend>
    <form action="{% url 'apps.home.views.sign_up' %}" method="post">
        {% csrf_token %}

        {{ sign_up_form.as_p}}

        <p><input type="submit" value="Sign up" /></p>
    </form>
</fieldset>
</div>

If the user submits, the sign_in form, they'll be taken to a page where they can view other site members. If they submit the sign_up form, they'll be taken to a second signup page where they'll create a user profile, etc.

Originally, I was going to use the technique shown in this question and use one view to handle the homepage. However, I decided to try to use two views because I'm using the Django's actual login view (django.contrib.auth.views.login) so that I can add code to it to detect the user's device (phone, tablet, or computer), and merging that view with my sign_up view would create a very long and complicated view to maintain. I'd prefer to keep the views for both forms separate.

Here's the home page and sign_in views:

# apps/home/views:
def home_page(request, template):
    sign_in_form = SignInAuthenticationForm()
    sign_up_form = CreateAccountForm()
    return render(request, template, {"sign_in_form": sign_in_form,
                                      "sign_up_form": sign_up_form})

@sensitive_post_parameters()
@csrf_protect
@never_cache
def sign_in(request, 
            template='home_page.html',
            redirect_field_name=REDIRECT_FIELD_NAME,
            # authentication_form=AuthenticationForm,
            authentication_form=SignInAuthenticationForm,
            current_app=None, extra_context=None):

    # Do device detection here...
    # django.contrib.auth.views code goes here...

    return response

The signup view will just be your typical, function-based view for processing a form as described in the Django documentation.

What I'm struggling with is my URLconf files. Here's my main and "home" URLconf files:

# conf/urls.py
urlpatterns = patterns('',
    url(r'^$',         include('apps.home.urls')),
    # Other url patterns...
)

# apps/home/urls.py
urlpatterns = patterns('apps.home.views',
    url(r'^$',
        'home_page',
        {'template': 'home/home_page.html'},
        name='home-page'),
    url(r'^sign_in/$',
        'sign_in',
        {'template': 'home/home_page.html'},
        name='sign-in'),
    url(r'^sign_up/$',
        'sign_up',
        {'template': 'home/home_page.html'},
        name='sign-up'),
)

The problem is that I get this error during template rendering:

NoReverseMatch at /

Reverse for 'apps.home.views.sign_in' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['$sign_in/$']

Request Method: GET
Request URL:    http://localhost:8000/
Django Version: 1.6.2
Exception Type: NoReverseMatch
Exception Value:    
Reverse for 'apps.home.views.sign_in' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['$sign_in/$']
Exception Location: /Users/smith/venv/swing/lib/python2.7/site-packages/django/core/urlresolvers.py in _reverse_with_prefix, line 429
Python Executable:  /Users/smith/venv/swing/bin/python
Python Version: 2.7.5
Python Path:    
['/Users/smith/Dropbox/www/swing',
 '/Users/smith/venv/swing/lib/python2.7/site-packages/wurfl_cloud-1.0.1-py2.7.egg',
 '/Users/smith/venv/swing/lib/python27.zip',
 '/Users/smith/venv/swing/lib/python2.7',
 '/Users/smith/venv/swing/lib/python2.7/plat-darwin',
 '/Users/smith/venv/swing/lib/python2.7/plat-mac',
 '/Users/smith/venv/swing/lib/python2.7/plat-mac/lib-scriptpackages',
 '/Users/smith/venv/swing/Extras/lib/python',
 '/Users/smith/venv/swing/lib/python2.7/lib-tk',
 '/Users/smith/venv/swing/lib/python2.7/lib-old',
 '/Users/smith/venv/swing/lib/python2.7/lib-dynload',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
 '/Users/smith/venv/swing/lib/python2.7/site-packages']

At first I started to think that maybe it's telling me that it can's find the correct URL pattern in my home/urls.py file because the URL signature in my form is incorrect. Maybe I needed to do this to match the arguments in the sign_in view:

<form action="{% url 'apps.home.views.sign_in' 'home/home_page.html' %}" method="post">

But I'm already showing the template name in the home URLconf. And I don't think I need to pass the other view arguments in the form action (e.g. redirect_field_name) because their optional. In any case, adding this argument to the form action didn't fix it.

One of the things that confuses me is how to set the first url argument. I've set them to r'^sign_in/$' and r'^sign_up/$' because if I set them both to r'^$', the page will render properly but when I submit either form, it justs posts back to the home page. You can see this will happen by doing a "view source" on the page. It shows each form's action will be "/". On the other hand, the way I have it now seems incorrect to me because the site won't actually have a "/sign_in/" and "/sign_up/" URL since both forms are on the home page. Also, is there going to be a problem in which if the user submits one for or the other improperly, errors for both forms will be rendered on the page?

The Django documentation, to the best of my knowledge, doesn't really describe a standard approach for doing what I'm trying to do. It describes how to render multiple versions of the same form. Can anyone tell me what I'm doing wrong?

Thanks.

Community
  • 1
  • 1
Jim
  • 11,270
  • 21
  • 86
  • 134
  • why y don't try to use formsets to collect the 2 forms and test in the view if form1 valid do something(sign) or if form2 valid do something else https://docs.djangoproject.com/en/1.6/topics/forms/formsets/ – slim_chebbi Jul 31 '14 at 17:41
  • 1
    Because, as I understand it,FormSets are geared towards iterating through multiple copies of the same form. In my situation, I have two different forms. But perhaps I'm not understanding them. They still don't seem like the right solution. – Jim Jul 31 '14 at 17:51
  • yes that right but you can also use multi formset in the same view in your case 2 formsets evry formset has one form – slim_chebbi Jul 31 '14 at 19:25

2 Answers2

1

Your form names are 'sign_in_form' and 'sign_up_form', but in your html you wrote them 'form.as_p' instead of 'sign_in_form.as_p' and 'sign_up_form.as_p' this is the first bug a saw in your code.

The real problem is in your urls configuration. In your main urls.py you have

 url(r'^$', include('apps.home.urls')),
 Other ...

Though you will not be able to get to localhost:8000/sign_in/ because initially it does not satisfy to ^$ .

Try to change it by

url(r'', include('apps.home.urls')),

and put it to the end of urls.py.

DAKZH
  • 233
  • 2
  • 12
  • While I haven't fully tested it, this looks like may fix the problem. Can you explain why this works? I didn't see the "url(r'',...)," syntax described anywhere in the Django documentation. Thanks. – Jim Jul 31 '14 at 19:13
  • Note that **include('apps.home.urls')** are only for '/' not 'sign_in' or 'sign_out'. **url(r'',...)** basically means **every** pattern, but I don't think that is good way to write urls. It is acceptable only during development. – DAKZH Jul 31 '14 at 21:09
  • user2309693, thanks very much for your help with this problem. I've done all my testing and it looks like it works. You said in your most recent comment that this way of handling urls is only appropriate during development. What should I do in a production environment? Your fix does make things work so I'm reluctant to change it. Thanks again!! – Jim Jul 31 '14 at 23:52
1

i test this see if this what you want: view.py

def loginUser(request,**Kargs):
LoginFormSet = formset_factory(LoginForm)
SignFormSet = formset_factory(SignForm)
if request.method == 'POST':
    login_formset = LoginFormSet(request.POST, prefix='login')
    sign_formset = SignFormSet(request.POST ,prefix='sign')
    if login_formset.is_valid():
        #do somthing

    elif sign_formset.is_valid():
        #do somthing

    return render(request, 'reservetion/login.html',{'login_formset': login_formset,'sign_formset':sign_formset})

else:
    login_formset = LoginFormSet(prefix='login')
    sign_formset = SignFormSet(prefix='sign')
    return render(request, 'reservetion/login.html',{'login_formset': login_formset,'sign_formset':sign_formset})

page.html:

            <form action="{% url 'loginUser'  %}" method="post">
                    {% csrf_token %}
{{ login_formset.management_form }}
{% for form in login_formset %}
    {{ form }}
{% endfor %}

{{ sign_formset.management_form }}
{% for form in sign_formset %}


 {{ form }}


 {% endfor %}
slim_chebbi
  • 754
  • 4
  • 8