如何将 url 参数传递给视图以供其他类函数和模板使用

Posted

技术标签:

【中文标题】如何将 url 参数传递给视图以供其他类函数和模板使用【英文标题】:How to pass a url parameter into the views to be used by other class functions and the template 【发布时间】:2021-01-12 20:25:18 【问题描述】:

请我有一个严重的问题,这几天给我留下了各种各样的错误。我想实现一些功能,但不知道如何实现。任何帮助将不胜感激。

我想创建一个注册表单,用于注册用户并在他们注册后将他们发送到他们的个人资料页面。我尝试通过尝试将用户填写表单的用户名传递给我的个人资料视图的 urls 参数来做到这一点。但是,我不确切知道如何执行此操作,并且我在网上找到的每个代码只会导致我出错。我是 Django 新手。

除此之外,我想创建我的个人资料视图,这样如果用户搜索他们自己的模板,那么他们可以编辑它,我为此使用了 UpdateView,如果它不是他们的个人资料,那么他们只能将其查看为只读的,我为此使用了 detailView。

另外,请有人也可以帮助我了解如何将 url 参数传递到基于类的视图中,视图中的所有功能如何访问此参数。如何在同一个基于类的视图中的另一个函数中使用基于类的视图中的函数的变量。也是使用 url 参数和重定向在不同视图之间传输变量的唯一方法。

请注意,我使用了自定义用户模型

这是我当前的错误

错误回溯

Traceback (most recent call last):
  File "C:\Users\Elisha\AppData\Local\Programs\Python\Python38\lib\site- 
packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "C:\Users\Elisha\AppData\Local\Programs\Python\Python38\lib\site- 
packages\django\core\handlers\base.py", line 179, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Elisha\AppData\Local\Programs\Python\Python38\lib\site- 
packages\django\views\generic\base.py", line 73, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\Elisha\AppData\Local\Programs\Python\Python38\lib\site- 
packages\django\views\generic\base.py", line 101, in dispatch
    return handler(request, *args, **kwargs)
  File "C:\Users\Elisha\AppData\Local\Programs\Python\Python38\lib\site- 
packages\django\views\generic\edit.py", line 172, in post
    return super().post(request, *args, **kwargs)
  File "C:\Users\Elisha\AppData\Local\Programs\Python\Python38\lib\site- 
packages\django\views\generic\edit.py", line 142, in post
    return self.form_valid(form)
  File "c:\MouauEasyGo\user\views.py", line 38, in form_valid
    return HttpResponseRedirect(self.get_success_url())
  File "c:\MouauEasyGo\user\views.py", line 55, in get_success_url
    return reverse('profile', args=(self.kwargs['name_of_user']))
  File "C:\Users\Elisha\AppData\Local\Programs\Python\Python38\lib\site- 
packages\django\urls\base.py", line 87, in reverse
    return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
  File "C:\Users\Elisha\AppData\Local\Programs\Python\Python38\lib\site- 
packages\django\urls\resolvers.py", line 685, in _reverse_with_prefix
    raise NoReverseMatch(msg)

Exception Type: NoReverseMatch at /user/register/
Exception Value: Reverse for 'profile' with arguments '('a', 'g', 'e')' not found. 1 pattern(s) tried: ['user/profile/(?P<username>[^/]+)/$']

下面是我的代码

urls.py

from django.urls import path
from user import views as user_views


urlpatterns = [
    path('profile/<str:username>/', user_views.profile_update_view.as_view(), name="profile"),
    path('register/', user_views.user_register_view.as_view(), name="register"),
]

views.py

class user_register_view(CreateView):
    template_name = "user/register.html"
    form_class = UserRegistrationForm
    model = NewUser


    # I had to override the form_valid method and added form to the self parameter since get_success_url can't access form directly

    def form_valid(self, form):
        self.form = form
        if form.is_bound:
            self.kwargs['name_of_user'] = form.cleaned_data['user_name']
        return HttpResponseRedirect(self.get_success_url())

    def get_context_data(self, **kwargs):
        data = super().get_context_data(**kwargs)
        try:
            data['name_of_user'] = self.kwargs['name_of_user']
        except KeyError:
            return data
        return data

    def get_queryset(self):
        qs = super().get_queryset()
        return qs.filter(name__startswith=self.kwargs[self.request.user.user_name])

    # if the user's username is in slug, then use it in the profile's url else then pick the username from the form and use instead
    def get_success_url(self):
        if self.kwargs['name_of_user']:
            return reverse('profile', args=(self.kwargs['name_of_user']))


# this is the profile page as viewed by the owner of the profile
# the viewer passes the test only if they are the logged in user
# if they are not, then they are redirected to the the
# profile_detail_view.
class profile_update_view(UserPassesTestMixin, UpdateView):
    model = Profile
    fields = ['date_of_birth', 'country', 'about', 'image', ]
    template_name = 'user/profile_update_form.html'

    def get_object(self):
        user = self.request.user
        return get_object_or_404(Profile, pk=user.id)

    # try to get the user_name from the current user.
    # if the user is an Anoynmous user then just redirect to detail page
    def test_func(self):
        try:
            x = self.request.user.user_name
            y = self.kwargs.get('name_of_user')
            if x == y:
                return True
            else:
                return redirect('profile_detail_view.as_view()')
        except AttributeError:
            return redirect('profile_detail_view.as_view()')


# this is the profile page as viewed by the general public
# this view can only be reached if the current logged  in user
# is not the one access the view
class profile_detail_view(DetailView):
    template_name = "user/profile_detail.html"
    model = Profile

    def get_object(self):
        user = self.request.user
        return get_object_or_404(Profile.objects.get(pk=user.id))

forms.py

class UserRegistrationForm(UserCreationForm):
    date_of_birth = forms.DateField(required=True)
    country = forms.CharField(max_length=50, required=True)
    image = forms.ImageField(required=False)
    about = forms.CharField(widget=forms.Textarea, required=False)

    class Meta:
        model = NewUser
        fields = ['email', 'user_name', 'first_name', 'last_name', ]

    # save profile info as well as the user info in the form
    def save(self, commit=True):
        if not commit:
            raise NotImplementedError(
                "Can't create User and UserProfile without database save")
        user = super(UserRegistrationForm, self).save(commit=True)
        user_name = self.cleaned_data['user_name']
        email = self.cleaned_data['email']
        first_name = self.cleaned_data['first_name']
        last_name = self.cleaned_data['last_name']
        user, created = NewUser.objects.get_or_create(user_name=user_name, email=email, first_name=first_name, last_name=last_name)
        user.save()
        user_profile = Profile(
            user=user,
            about=self.cleaned_data['about'],
            date_of_birth=self.cleaned_data['date_of_birth'],
            country=self.cleaned_data['country']
        )
        user_profile.save()
        return user, user_profile

models.py

class CustomAccountManager(BaseUserManager):

    def create_superuser(self, email, user_name, first_name, last_name, password, **other_fields):

        other_fields.setdefault('is_staff', True)
        other_fields.setdefault('is_superuser', True)
        other_fields.setdefault('is_active', True)

        if other_fields.get('is_staff') is not True:
            raise ValueError('Superuser must be assigned to is_staff=True.')
        if other_fields.get('is_superuser') is not True:
            raise ValueError(
                'Superuser must be assigned to is_superuser=True.')

        return self.create_user(email, user_name, first_name, last_name, password, **other_fields)

    def create_user(self, email, user_name, first_name, last_name, password, **other_fields):

        if not email:
            raise ValueError(_('You must provide an email address'))

        email = self.normalize_email(email)
        user = self.model(email=email, user_name=user_name, first_name=first_name, last_name=last_name, **other_fields)
        user.set_password(password)
        user.save()
        return user


class NewUser(AbstractBaseUser, PermissionsMixin):

    email = models.EmailField(_('email address'), unique=True)
    user_name = models.CharField(max_length=150, unique=True)
    first_name = models.CharField(max_length=150, unique=True)
    last_name = models.CharField(max_length=150)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)

    objects = CustomAccountManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['user_name', 'first_name', 'last_name']

    def __str__(self):
        return self.user_name


class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    image = models.ImageField(default="default.jpg", upload_to="profile image/")
    about = models.TextField(_('about'), max_length=500, blank=True)
    date_of_birth = models.DateField(default=timezone.now)
    country = models.CharField(max_length=20, blank=True, null=True)

    def __str__(self):
        return f"self.user's profile"

我们将不胜感激。如果需要任何其他信息,请告诉我。提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

我举个例子:

模板:


    <form method="GET" action="% url 'register' %">
        <div class="input-group">
            <input name="q" type="text" class="form-control" placeholder="Enter name..." />
            <span class="input-group-append">
                <input class="btn btn-secondary" type="submit" name="btn" value="Submit" />
            </span>
        </div>
    </form>

网址: path('register/', views.register, name='register'),

查看:

def register(request):
    name = request.GET.get('q')
    # redirect the page with this information.

实现this 的参考 - 查看此处执行的search 操作。

【讨论】:

谢谢。不敢相信这很容易。虽然我在保存表单后通过我的 form_valid() 方法自动登录用户解决了这个问题。然后使用不带参数的配置文件 url 将它们重定向到当前登录的用户,即填写表单的用户。如果有人想查看其他用户的个人资料,我还有另一个个人资料网址可以接受参数。这肯定会派上用场。谢谢

以上是关于如何将 url 参数传递给视图以供其他类函数和模板使用的主要内容,如果未能解决你的问题,请参考以下文章

将参数传递给不同视图之间的显示模板

如何将查询url参数传递给twig模板

如何将视图输入参数传递给 @State 变量?

如何使用从views.py发送的变量将几个参数传递给url模板标签

Objective-c 将参数传递给视图

将模板参数传递给调用成员函数的函数