简体   繁体   English

如何使用用户外键将模型表单保存到Django模型

[英]How to save a Model Form with a foreign key of User to django models

I am trying to save user API keys to a Django Model with a foreign key of User such that each set of unique API keys has a unique User associated with them in the database. 我正在尝试使用用户的外键将用户API密钥保存到Django模型中,以便每组唯一的API密钥在数据库中都具有与之关联的唯一的用户。 I want a api keys input form to appear when a user who clicks "account" if the user has no associated API keys and a message saying " Your keys have already been entered" if the user does have associated API keys. 我希望当用户单击“帐户”(如果该用户没有关联的API密钥)并且单击“您的密钥已经输入”的消息(如果该用户确实具有关联的API密钥)时出现api密钥输入形式。

I am using the built in Django User Model and I have created my own Model Form in forms.py. 我正在使用内置的Django用户模型,并且已经在forms.py中创建了自己的模型表单。

I have tried including user in the Model form and Meta class to no avail. 我试图将用户包括在Model表单和Meta类中而徒劳无功。 I have tried passing the keys and password as parameters to the model and form before saving. 我尝试过在保存之前将密钥和密码作为参数传递给模型和表单。 I have tried using instances of the form with commit set to False before adding the User to form.user. 在将用户添加到form.user之前,我尝试使用commit设置为False的表单实例。 I've tried looking up the latest Django documentation but its fragmented and hard to follow. 我尝试查找最新的Django文档,但其内容分散且难以理解。

I'm purposefully leaving out imports unnecessary to this problem. 我特意省去了不必要的导入操作。

This is my Models.py : 这是我的Models.py

from django.db import models
from django.contrib.auth.models import User
from django.conf import settings

# Create your models here.

class UserApiDetails(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=None)
    key = models.CharField(max_length=32)
    password = models.CharField(max_length=32)

    def __str__(self):
        out = "key: " + str(self.key) + '\n' + "Password: " + str(self.password)
        return out

     # this is the method that checks if the user has existing API keys
    def keys_exist(self): 
        if UserApiDetails.objects.filter(pk=User).exists():
            return True
        else:
            return False

This is my forms.py : 这是我的forms.py

from django import forms
from .models import UserApiDetails

class ApiKeysForm(forms.ModelForm):
    key = forms.CharField(max_length=200, label="Api Key")
    password = forms.CharField(max_length=200, widget=forms.PasswordInput, label="Api password")

    class Meta:
        model = UserApiDetails
        fields = {'password', 'key', }

This is my views.py : 这是我的views.py

from django.shortcuts import render, redirect
from .models import UserApiDetails  # tables in database from models.py
from django.http import JsonResponse, HttpResponse
from django.contrib.auth.models import User
from . import forms
from .forms import ApiKeysForm  # the forms that will get data & pass to views
from django.template.loader import render_to_string

import sys

sys.path.insert(1, '/Development applications/python dev/TradingBot')
# backend imports
from Main import update, trade # methods in bot
from API_comm import ConnAPI  # conn API class used to set keys & session AUTH


# Create your views here.

def account_request(request):
    if request.method == 'POST':

        form = forms.ApiKeysForm(request.POST)
        if form.is_valid():
            key = form.cleaned_data.get('key')
            password = form.cleaned_data.get('password')
            instance = form.save(commit=False)
            instance.user = request.user
            instance.save()
            c = {
                "key": key,
                "password": password
            }

            result = ConnAPI.set_keys(key, password)  # gets the return from the set keys method
            messages.success(request, result)  # a toast to display if the api conn was successful or not
            return redirect("main:homepage")
    else:
        form = forms.ApiKeysForm(request.POST)

    context = {
        "form": form,
    }

    return render(request,
                  "main/account.html",
                  context)

This is my account.html template : 这是我的account.html模板

{% extends "main/header.html" %}
{% block content%}

{% if UserApiDetails.keys_exist %}

<div class="row1">
    <h2>Your Api Keys have already been entered.</h2>
    <div class="col s12 m8 14">
        <p></p>
    </div>

</div>

{% else %}

<div class="row2">
    <form class="col s12 " action="/account/" method="POST">
        {% csrf_token %}
        {{form.as_p}}

        <div class="col s12 m6 14">
            <button class="btn" type="submit">Submit Api Keys</button>
        </div>

    </form>
</div>

{% endif %}

{% endblock %}

edit I have managed to save the API details with Unique Users but i'm struggling to ensure that each user enters only 1 set of keys. 编辑我设法与唯一用户一起保存API详细信息,但是我在努力确保每个用户仅输入1组键。

When a user who does have API keys associated to their account clicks "account" the form still appears instead of the HTML with div ID of "Row1". 当确实具有与其帐户相关联的API密钥的用户单击“帐户”时,仍会显示该表单,而不是显示div ID为“ Row1”的HTML。

There's a few issues with your code, you're mixing instances and classes: 您的代码存在一些问题,您正在混合实例和类:

  • First your keys_exist() function is wrong because you use pk=User in the filter of your query, which doesn't make sense. 首先,您的keys_exist()函数是错误的,因为您在查询的过滤器中使用pk=User ,这没有任何意义。 User is the class user and pk is the primary key of your UserApiDetails instances, so they can never be equal. User是类用户,而pkUserApiDetails实例的主键,因此它们永远不能相等。 You need to test against a User instance : 您需要针对User 实例进行测试:

     @classmethod def keys_exist(cls, user): return cls.objects.filter(user=user).exists() 

    Note: It would be cleaner to write this method on your User model, but it seems you haven't customised User and are using the plain Django user model, so in this case this is fine. 注意:在您的User模型上编写此方法会更干净,但是似乎您尚未自定义User ,并且使用的是纯Django用户模型,因此在这种情况下可以。

  • Second, since you need to pass the user as argument to the function, you can't call it directly in your template. 其次,由于需要将用户作为参数传递给函数,因此不能直接在模板中调用它。 So either add the result to your context (and use that in your template) or create a custom template filter. 因此,要么将结果添加到您的上下文中(并在模板中使用它),要么创建一个自定义模板过滤器。 I'll show the first method. 我将展示第一种方法。 In your view, define your context like this: 在您的视图中,如下定义上下文:

     context = {'form': form, 'has_keys': UserApiDetails.keys_exist(request.user)} 

    then in your template you can just check {% if has_keys %} . 那么您可以在模板中仅检查{% if has_keys %}

I've managed to fix the issue: 我设法解决了这个问题:

I firstly had to change my keys_exist() method in models.py as follows: 我首先必须按照以下方式更改models.py中的keys_exist()方法:

def keys_exist(request):  # had to pass request to use request.user in the filter
    if UserApiDetails.objects.filter(user=request.user).exists():  # where foreign key = current logged user
        print("User has API details")
        return True
    else:
        print("User does not have API details")
        return False

I then had to add the following to my account_request() view: 然后,我必须将以下内容添加到我的account_request()视图中:

    if models.keys_exist(request): # pass request to use in modely.py
        context = {
            "form": form,
            "exists": True,
        }
    else:
        context = {
            "form": form,
            "exists": False,
        }

Making sure to pass request when calling .keys_exist() 确保在调用.keys_exist()传递请求

And then finally I changed the if statement in my account.html template: 最后,我更改了account.html模板中的if语句

{% if exists  %}  <!-- Do not use the double braces or == true within the code blocks -->
.
.
.
{% else %}     <!-- ensure this is not elif -->
.
.
.
{% endif %}


声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM